/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with context work for additional information
* regarding copyright ownership. The ASF licenses context file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use context file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.doplgangr.secrecy.fragments;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.doplgangr.secrecy.Config;
import com.doplgangr.secrecy.R;
import com.doplgangr.secrecy.utils.Util;
import com.doplgangr.secrecy.filesystem.Base64Coder;
import com.doplgangr.secrecy.filesystem.Storage;
import com.doplgangr.secrecy.adapters.VaultsListFragment;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
/*
Called whenever user installs/upgrades.
context class is for handling the differences in vault versions.
The changes are hardcoded in the respective "transition actions"
e.g. from version 4 to version 5
The manager shows what it is doing and allows user to proceed when update is finished.
*/
public class UpdateManager extends Fragment {
//Console-like log view
private TextView log;
//Continue button
private Button continueButton;
//Preference that stores last app version
int version;
private VaultsListFragment.OnFragmentFinishListener mFinishListener;
//Current version
private Integer versionnow;
private String versionnow_name;
private Context context;
private static java.io.File getRoot() {
// Function for determining temp folder location in version1, only used in upgrading from v1 to v2
java.io.File sdCard = Environment.getExternalStorageDirectory();
java.io.File tempDir = new java.io.File(sdCard.getAbsolutePath() + "/" + "SECRECYFILES");
tempDir.mkdirs();
return tempDir;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mFinishListener = (VaultsListFragment.OnFragmentFinishListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement Listener");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity();
// Fills variables with appropriate version data
getVersionInfo();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.activity_update_manager, container, false);
log = (TextView) view.findViewById(R.id.log);
continueButton = (Button) view.findViewById(R.id.continueButton);
continueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// When user presses the continue button, alert if app is still in beta.
//Define 100 as initial beta code
if (versionnow < 100) {
Util.alert(context,
getString(R.string.Updater__alpha),
getString(R.string.Updater__alpha_message),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
},
null
);
} //Define 200 as initial official release code
else if (versionnow < 200) {
Util.alert(context,
getString(R.string.Updater__beta),
getString(R.string.Updater__beta_message),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
},
null
);
}
else {
finish();
}
}
});
return view;
}
@Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
version = PreferenceManager.getDefaultSharedPreferences(context).getInt(Config.APP_VERSION_NUMBER, 1);
String versionName = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Config.APP_VERSION_NAME, getString(R.string.Updater__alpha0_1));
// If the version is not upgraded, skip the update manager
if (versionnow == version) {
finish();
return;
}
// Writes the previous/current version into the log view
appendlog(String.format(getString(R.string.Updater__previous_version), version, versionName));
appendlog(String.format(getString(R.string.Updater__next_version), versionnow, versionnow_name));
// Switches between different upgrades, based on last app version.
switch (version) {
case 53:
version53to60();
case 32:
version32to53();
case 31:
version31to32();
break;
case 30:
version30to31();
break;
case 21:
version21to30();
break;
case 20:
version20to21();
break;
case 19:
version19to20();
break;
case 18:
version18to19();
break;
case 17:
version17to18();
break;
case 16:
version16to17();
break;
case 15:
version15to16();
break;
case 14:
version14to15();
break;
case 13:
version13to14();
break;
case 12:
version12to13();
break;
case 11:
version11to12();
break;
case 10:
version10to11();
break;
case 9:
version9to10();
break;
case 8:
version8to9();
break;
case 7:
version7to8();
break;
case 6:
version6to7();
break;
case 5:
version5to6();
break;
case 3:
version3to5();
break;
case 2:
version2to3();
break;
case 1:
version1to2();
break;
default:
onFinishAllUpgrade(); //FailSafe
}
// Notify user that app is upgrading
appendlog(getString(R.string.Updater__updating));
}
void version53to60(){
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.remove(Config.VAULT_SORT);
editor.apply();
appendlog("Replacing preference \"" + Config.VAULT_SORT + "\"");
onFinishAllUpgrade();
}
void version32to53() {
Collection folders = FileUtils.listFilesAndDirs(Storage.getRoot(), FalseFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
for (Object folderObject : folders) { //Search for dirs in root
File folder = (File) folderObject;
if (new File(folder, ".vault").exists() || !new File(folder, ".nomedia").exists()) {
appendlog("\n" + folder.getAbsolutePath() + " is 5.x or not a vault, skip");
continue; //The whole thing should be skipped because vault is in 5.x standard.
}
appendlog("\n" + folder.getAbsolutePath() + " is pre-5.x");
Collection files = FileUtils.listFiles(folder, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
//walks the whole file tree, find out files that do not have encoded file names
//and encode them.
for (Object file : files) {
File realFile = (File) file;
if (".nomedia".equals(realFile.getName()))
continue;
String fileName = FilenameUtils.removeExtension(realFile.getName());
fileName = fileName.replace("_thumb", "");
try {
Base64Coder.decodeString(fileName);
} catch (IllegalArgumentException e) {
String encodedFileName = Base64Coder.encodeString(fileName);
fileName = realFile.getAbsolutePath().replace(fileName, encodedFileName);
realFile.renameTo(new File(fileName));
}
}
}
version53to60();
}
void version31to32() {
//Nahh
version32to53();
}
void version30to31() {
//Nahh
version31to32();
}
void version21to30() {
//Nahh
version30to31();
}
void version20to21() {
//Nahh
version21to30();
}
void version19to20() {
//Nahh
version20to21();
}
void version18to19() {
//Nahh
version19to20();
}
void version17to18() {
// version 18 adds option to enable/disable stealth.
// enable stealth if is set prior to 18.
if (!PreferenceManager.getDefaultSharedPreferences(context)
.getString(Config.STEALTH_MODE_PASSWORD, "").equals("")) {
SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(context).edit();
editor.putBoolean(Config.STEALTH_MODE, true);
editor.apply();
}
version18to19();
}
void version16to17() {
//Still nothing...
version17to18();
}
void version15to16() {
//Still nothing...
version16to17();
}
void version14to15() {
//Still nothing...
version15to16();
}
void version13to14() {
//Still nothing...
version14to15();
}
void version12to13() {
//Nothing to upgrade
version13to14();
}
void version11to12() {
//Nothing to upgrade
version12to13();
}
void version10to11() {
//Nothing to upgrade
version11to12();
}
void version9to10() {
//Nothing to upgrade
version10to11();
}
void version8to9() {
// Changes filebase path to new format.
if (!Util.canWrite(Storage.getRoot())) {
//Append with sdcard link
appendlog("\nOld sdCard format. Changing to new format.");
String newRoot = Environment.getExternalStorageDirectory()
.getAbsoluteFile()
+ "/" + Storage.getRoot().getAbsolutePath();
Storage.setRoot(newRoot);
}
version9to10();
}
void version7to8() {
//Nothing to upgrade
version8to9();
}
void version6to7() {
// Fix a bug in version 6 that corrupts the vault if user tries to move it elsewhere
if (!Storage.getRoot().getName().equals("SECRECYFILES")) {
appendlog("\nUser have used v6 and moved vaults elsewhere");
Util.alert(context,
"Upgrading from alpha 0.6 to 0.7",
"We detect that you have moved your vaults using version 0.6." +
" We discovered some bugs and we will try to fix, if any, problems associated" +
" with it...",
Util.emptyClickListener,
null
);
appendlog("\nTrying to move again...");
try {
org.apache.commons.io.FileUtils.copyDirectory(getRoot(), Storage.getRoot());
appendlog("\nFinish re-moving vaults");
FileUtils.deleteDirectory(getRoot());
} catch (IOException E) {
E.printStackTrace();
Util.alert(context,
"Error moving vaults",
"We encountered an error. Please contact developer for help (mkcyyin(at)gmail.com). Updating aborted.",
Util.emptyClickListener,
null);
return;
}
}
version7to8();
}
void version5to6() {
//Nothing to upgrade
version6to7();
}
void version3to5() {
//Nothing to upgrade
version5to6();
}
void version2to3() {
//Nothing to upgrade
version3to5();
}
void version1to2() {
// remove the temp folder, we do not use it anymore.
java.io.File root = Storage.getRoot();
if (Util.canWrite(root)) {
java.io.File[] files = root.listFiles();
for (java.io.File inFile : files)
if (inFile.isDirectory())
if ("TEMP".equals(inFile.getName()))
Storage.DeleteRecursive(inFile);
appendlog(getString(R.string.Updater__one_to_two));
}
version2to3();
}
void onFinishAllUpgrade() {
// When all updates are finished, notify user and enable the continue button
appendlog(getString(R.string.Updater__update_finish));
continueButton.setEnabled(true);
SharedPreferences.Editor editor =
PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putInt(Config.APP_VERSION_NUMBER, versionnow);
editor.putString(Config.APP_VERSION_NAME, versionnow_name);
editor.apply();
}
void appendlog(String message) {
// Appends log info to log view
log.append(message);
}
void getVersionInfo() {
// get version info from the package manager
PackageInfo pInfo;
try {
pInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
Util.log("Cannot get package info, abort.");
finish();
return;
}
versionnow = pInfo.versionCode;
versionnow_name = pInfo.versionName;
}
void finish() {
mFinishListener.onFinish(this);
mFinishListener.onNew(null, new VaultsListFragment());
}
}