/*
* 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.UpdateManager;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.widget.Button;
import android.widget.TextView;
import com.doplgangr.secrecy.FileSystem.Base64Coder;
import com.doplgangr.secrecy.FileSystem.storage;
import com.doplgangr.secrecy.R;
import com.doplgangr.secrecy.Settings.Prefs_;
import com.doplgangr.secrecy.Util;
import com.doplgangr.secrecy.Views.VaultsListFragment;
import com.doplgangr.secrecy.Views.VaultsListFragment_;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.androidannotations.annotations.sharedpreferences.Pref;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
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.
*/
@EFragment(R.layout.activity_update_manager)
public class UpdateManager extends Fragment {
//Console-like log view
@ViewById(R.id.log)
TextView log;
//Continue button
@ViewById(R.id.continueButton)
Button continueButton;
//Preference that stores last app version
@Pref
AppVersion_ version;
@Pref
Prefs_ Prefs;
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");
}
}
@AfterViews
void onCreate() {
context = getActivity();
// Fills variables with appropriate version data
getVersionInfo();
// If the version is not upgraded, skip the update manager
if (versionnow == version.no().get()) {
finish();
return;
}
// Writes the previous/current version into the log view
appendlog(String.format(getString(R.string.Updater__previous_version), version.no().get(), version.name().get()));
appendlog(String.format(getString(R.string.Updater__next_version), versionnow, versionnow_name));
// Switches between different upgrades, based on last app version.
switch (version.no().get()) {
case 32:
version32to40();
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));
}
@Background
void version32to40() {
//walks the whole file tree, find out files that do not have encoded file names
//and encode them.
Collection files = FileUtils.listFiles(storage.getRoot(), TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
for (Object file : files) {
File realFile = (File) file;
String fileName = FilenameUtils.removeExtension(realFile.getName());
fileName = fileName.replace("_thumb", "");
if (".nomedia".equals(fileName))
continue;
try {
Base64Coder.decodeString(fileName);
} catch (IllegalArgumentException e) {
String encodedFileName = Base64Coder.encodeString(fileName);
fileName = realFile.getAbsolutePath().replace(fileName, encodedFileName);
Boolean ignored = realFile.renameTo(new File(fileName));
}
}
onFinishAllUpgrade();
}
@Background
void version31to32() {
//Nahh
version32to40();
}
@Background
void version30to31() {
//Nahh
version31to32();
}
@Background
void version21to30() {
//Nahh
version30to31();
}
@Background
void version20to21() {
//Nahh
version21to30();
}
@Background
void version19to20() {
//Nahh
version20to21();
}
@Background
void version18to19() {
//Nahh
version19to20();
}
@Background
void version17to18() {
if (Prefs.OpenPIN().exists()) // version 18 adds option to enable/disable stealth.
Prefs.stealth().put(true); // enable stealth if is set prior to 18.
version18to19();
}
@Background
void version16to17() {
//Still nothing...
version17to18();
}
@Background
void version15to16() {
//Still nothing...
version16to17();
}
@Background
void version14to15() {
//Still nothing...
version15to16();
}
@Background
void version13to14() {
//Still nothing...
version14to15();
}
@Background
void version12to13() {
//Nothing to upgrade
version13to14();
}
@Background
void version11to12() {
//Nothing to upgrade
version12to13();
}
@Background
void version10to11() {
//Nothing to upgrade
version11to12();
}
@Background
void version9to10() {
//Nothing to upgrade
version10to11();
}
@Background
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();
}
@Background
void version7to8() {
//Nothing to upgrade
version8to9();
}
@Background
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();
}
@Background
void version5to6() {
//Nothing to upgrade
version6to7();
}
@Background
void version3to5() {
//Nothing to upgrade
version5to6();
}
@Background
void version2to3() {
//Nothing to upgrade
version3to5();
}
@Background
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();
}
@UiThread
void onFinishAllUpgrade() {
// When all updates are finished, notify user and enable the continue button
appendlog(getString(R.string.Updater__update_finish));
continueButton.setEnabled(true);
// Write the new version info into the preferences, for next upgrades.
version.edit()
.no()
.put(versionnow)
.name()
.put(versionnow_name)
.apply();
}
@UiThread
void appendlog(String message) {
// Appends log info to log view
log.append(message);
}
@Click(R.id.continueButton)
public void Continue() {
// 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();
}
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_());
}
}