/*
* Copyright (C) 2012 The LiquidSmoothROMs Project
* author JBirdVegas@gmail.com 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this 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.blackice.control.fragments;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import com.blackice.control.R;
import com.blackice.control.BlackICEPreferenceFragment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ClassCastException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;
public class BackupRestore extends BlackICEPreferenceFragment {
private static final String TAG = "BackupRestore";
private static final boolean DEBUG = true;
private static final boolean CLASS_DEBUG = false;
private static final String BLANK = "";
private static final String BACKUP_PREF = "backup";
private static final String RESTORE_PREF = "restore";
private static final String THEME_CAT_PREF = "theme_cat";
private static String CONFIG_FILENAME = null;
private static final File fSDCARD = Environment.getExternalStorageDirectory();
private static final String SDCARD = fSDCARD.getAbsolutePath();
private static String CONFIG_CHECK_PASS = SDCARD + "/BlackICEControl/%s has been created";
private static final String PATH_TO_CONFIGS = SDCARD + "/BlackICEControl";
private static final String PATH_TO_THEMES = SDCARD + "/BlackICEControl/themes";
private static boolean success = false;
private final String OPEN_FILENAME = "open_filepath";
private final String SAVE_FILENAME = "save_filepath";
private static final String MESSAAGE_TO_HEAD_FILE = "~XXX~ BE CAREFUL EDITING BY HAND ~XXX~ you have been warned!";
private static final String TEXT_IS_EMPTY = "Theme Name Required";
private static String makeThemFeelAtHome = null;
private static int DEFAULT_FLING_SPEED = 65;
private static final String DELIMITER = "+";
private static final String SPILT_DELIMITER = "\\+";
private static String RETURN = "\n";
private static String LINE_SPACE = "\n\n";
private static String TWO_LINE_SPACE = "\n\n\n";
// Dialogs
private static final int THEME_INFO_DIALOG = 100;
private static final int SAVE_CONFIG_DIALOG = 101;
// to hold our lists
String[] array;
ArrayList<String> settingsArray = new ArrayList<String>();
ArrayList<String[]> arrayOfStrings = new ArrayList<String[]>();
PreferenceScreen prefs;
PreferenceScreen mBackup;
PreferenceScreen mRestore;
PreferenceCategory mThemeCat;
Properties mProperties = new Properties();
@Override
public void onCreate(Bundle didOrientationChange) {
super.onCreate(didOrientationChange);
addPreferencesFromResource(R.xml.prefs_backup_restore);
prefs = getPreferenceScreen();
mBackup = (PreferenceScreen) prefs.findPreference(BACKUP_PREF);
mRestore = (PreferenceScreen) prefs.findPreference(RESTORE_PREF);
// gain reference to theme category so we can drop our prefs if not found
mThemeCat = (PreferenceCategory) prefs.findPreference(THEME_CAT_PREF);
setupArrays();
// TODO add themes dir to mkdirs
// make required dirs and disable themes if unavailable
// be sure we have the directories we need or everything fails
File makeDirs = new File(PATH_TO_CONFIGS);
File themersDirs = new File(PATH_TO_THEMES);
if (!makeDirs.exists()) {
if (!makeDirs.mkdirs()) {
Log.d(TAG, "failed to create the required directories");
}
}
if (!themersDirs.exists()) {
if (!themersDirs.mkdirs()) {
Log.d(TAG, "failed to create theme directory");
}
}
// for that personal touch
makeThemFeelAtHome = Settings.System.getString(getActivity().getContentResolver(),
Settings.System.CUSTOM_CARRIER_LABEL);
// setup initial themes view
findThemes();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
private void findThemes() {
// themes live in the theme category while the theme category lives on the PreferenceScreen
// start with a clean slate
mThemeCat.removeAll();
prefs.removePreference(mThemeCat);
File themerDirs = new File(PATH_TO_THEMES);
// verify we have the file structure
if (!themerDirs.exists()) {
// try to make the path; if we fail drop the method instead of the app
if(!themerDirs.mkdirs()) return;
}
String[] allThemesFound = themerDirs.list();
try {
if (DEBUG) Log.d(TAG, themerDirs.list().toString());
} catch (NullPointerException npe) {
return;
}
// so Themes category won't show when we don't have themes
boolean doWeHaveThemes = false;
for (String findThemes : themerDirs.list()) {
File isDirOrTheme = new File(PATH_TO_THEMES, findThemes);
if (isDirOrTheme.isFile()) doWeHaveThemes = true;
}
if (doWeHaveThemes) {
doWeHaveThemes = false;
prefs.addPreference(mThemeCat);
for (final String theme_ : allThemesFound) {
// don't try to load directories as themes
File tf = new File(PATH_TO_THEMES, theme_);
if (!tf.isDirectory()) {
try {
File themeFile = new File(PATH_TO_THEMES, theme_);
PreferenceScreen newTheme = getPreferenceManager().createPreferenceScreen(mContext);
// use namespace for key
newTheme.setKey(theme_);
FileReader fReader = new FileReader(themeFile);
Properties mThemeProps = new Properties();
mThemeProps.load(fReader);
// look for some strings to set title and summary in config file
String returnedTitle = ((String) mThemeProps.get("title"));
String returnedSummary = ((String) mThemeProps.get("summary"));
if (returnedTitle != null) newTheme.setTitle(returnedTitle);
// use the filename is we have nothing else
else newTheme.setTitle(theme_);
if (returnedSummary != null) newTheme.setSummary(returnedSummary);
else newTheme.setSummary(BLANK);
newTheme.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference newTheme) {
wantToDeleteOrApply(theme_, true);
return true;
}
});
// now we have all the info lets add our new preference to the screen
mThemeCat.addPreference(newTheme);
} catch (NullPointerException npe){
// theme file was not found this shouldn't happen but just in case
npe.printStackTrace();
} catch (FileNotFoundException noFile) {
if (DEBUG) noFile.printStackTrace();
} catch (IOException io) {
if (DEBUG) io.printStackTrace();
}
}
}
}
}
private void wantToDeleteOrApply(final String filename, final boolean thisATheme) {
try {
// TODO fix so we don't need this path absolut we should inhearit from filename
final File dialogFile;
if (thisATheme) {
dialogFile = new File(PATH_TO_THEMES, filename);
} else {
dialogFile = new File(filename);
}
FileReader fr = new FileReader(dialogFile);
Properties dialogProps = new Properties();
dialogProps.load(fr);
AlertDialog.Builder shouldDelete = new AlertDialog.Builder(getActivity());
shouldDelete.setTitle(getString(R.string.delete_or_apply));
// complex but looks good TODO would be to simplify this setMessage()
shouldDelete.setMessage(String.format("Theme title: %s", ((String) dialogProps.get("title")))
+ RETURN + ((String) dialogProps.get("summary")));
shouldDelete.setPositiveButton(getString(R.string.apply_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
restore(filename, thisATheme);
}
});
shouldDelete.setNegativeButton(getString(R.string.delete_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialogFile.delete();
findThemes();
}
});
shouldDelete.show();
} catch (FileNotFoundException fnfe) {
// we should have already coverd this
} catch (IOException io) {
// ditto
}
}
private boolean runBackup(final String bkname, final String title_text, final String summary_text) {
// use async handler to avoid performace problems
final Handler mBackupHandler = new Handler();
final Runnable mRunBackupThread = new Runnable() {
public void run() {
if (DEBUG) Log.d(TAG, "runBackup has been called: " + bkname);
String string_setting = null;
int int_setting;
float float_setting;
int foundStrings = 0;
int foundInts = 0;
int foundFloats = 0;
// use army of clones so we don't waste time reading files
ArrayList<String> stringArray = new ArrayList<String>(settingsArray);
ArrayList<String> floatArray = new ArrayList<String>(settingsArray);
// so we can provide more info to the users about the backup
ArrayList<String> handledSettingsArray = new ArrayList<String>();
ArrayList<String> handledValuesArray = new ArrayList<String>();
ArrayList<String> unhandledSettingsArray = new ArrayList<String>(settingsArray);
// get a view to work with
LayoutInflater infoInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View backupDialogLayout = infoInflater.inflate(R.layout.what_happened_dialog, null);
// setup smooth scrolling within our info dialog
ScrollView scroll = (ScrollView) backupDialogLayout.findViewById(R.id.what_happened_scrollview);
scroll.setSmoothScrollingEnabled(true);
scroll.fling(DEFAULT_FLING_SPEED);
// get final reference so we can minuplate text in try blocks
final TextView mShowInfo = (TextView) scroll.findViewById(R.id.what_happened_more_info);
// structure a super simple dialog for our output
AlertDialog.Builder whatHappened = new AlertDialog.Builder(getActivity());
whatHappened.setTitle(getString(R.string.what_happened_title));
whatHappened.setView(backupDialogLayout);
whatHappened.setPositiveButton(getString(R.string.positive_thanks_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// user can't click here till we are done with work
// once user can click just dismiss we are done
}
});
// don't let the user stop this dialog till we are done running the backup
whatHappened.setCancelable(false);
// load builder into an AlertDialog so we can get the positive button
AlertDialog ad = whatHappened.create();
ad.show();
// Issue 6360 prevents us from referencing buttons till after we show dialog
// more info see --> http://code.google.com/p/android/issues/detail?id=6360
final Button mOkButton = (Button) ad.getButton(AlertDialog.BUTTON_POSITIVE);
mOkButton.setEnabled(false);
StringBuilder info = new StringBuilder(settingsArray.size());
final String formater = "Found value: %s=%s";
final String noValue = "Unresolved value: %s";
if (title_text != null) {
mProperties.setProperty("title", title_text);
info.append(String.format("Theme present named: %s", title_text) + RETURN);
mShowInfo.setText(info.toString());
}
if (summary_text != null) {
mProperties.setProperty("summary", summary_text);
info.append(String.format("Summary provided: %s", summary_text) + RETURN);
mShowInfo.setText(info.toString());
}
try {
// handle String[]'s first because they are on a seperate array
for (final String[] stringsInArray : arrayOfStrings) {
int length = stringsInArray.length;
if (DEBUG) Log.d(TAG, "stringsInArray length=" + length);
for (int i = 0; length > i; i++) {
String propValue = Settings.System.getString(getActivity().getContentResolver(), stringsInArray[i]);
if (propValue != null) {
info.append(String.format(formater, stringsInArray[i], propValue) + RETURN);
mProperties.setProperty(stringsInArray[i], propValue);
mShowInfo.setText(info.toString());
// tracking
handledSettingsArray.add(stringsInArray[i]);
handledValuesArray.add(propValue);
} else {
unhandledSettingsArray.add(stringsInArray[i]);
}
}
}
} catch (Exception e) {
if (DEBUG) e.printStackTrace();
}
// handle floats second and remove the handled values other arrays
for (final String liquid_float_setting : floatArray) {
// only alpha is kept as a float so don't bother with the rest
if (liquid_float_setting.contains("alpha")) {
try {
float float_ = Settings.System.getFloat(getActivity().getContentResolver(), liquid_float_setting);
mProperties.setProperty(liquid_float_setting, String.format("%f", float_));
if (DEBUG) Log.d(TAG, "floats: {" + liquid_float_setting + "} returned value {" + float_ + "}");
stringArray.remove(liquid_float_setting);
foundFloats = foundFloats + 1;
// tracking
handledSettingsArray.add(liquid_float_setting);
handledValuesArray.add(String.format("%f", float_));
info.append(String.format(formater, liquid_float_setting, float_) + RETURN);
mShowInfo.setText(info.toString());
} catch (SettingNotFoundException notFound) {
// we didn't find so add to out list of unhandledSettingsArray
unhandledSettingsArray.add(liquid_float_setting);
if (DEBUG) Log.d(TAG, String.format("should add this value? is floats unreliable reference point: %s",
liquid_float_setting));
info.append(String.format(noValue, liquid_float_setting) + RETURN);
mShowInfo.setText(info.toString());
if (CLASS_DEBUG) notFound.printStackTrace();
} catch (ClassCastException cce) {
if (CLASS_DEBUG) cce.printStackTrace();
} catch (NumberFormatException badFloat) {
if (CLASS_DEBUG) badFloat.printStackTrace();
}
}
}
// TODO can strings handle everything?!?! ...for saving only of coarse
for (final String liquid_string_setting : stringArray) {
try {
string_setting = Settings.System.getString(getActivity().getContentResolver(), liquid_string_setting);
try {
// it's an int so set it as so
int testIsANumber = Integer.valueOf(string_setting);
try {
testIsANumber = Settings.System.getInt(getActivity().getContentResolver(), liquid_string_setting);
mProperties.setProperty(liquid_string_setting, String.format("%d", testIsANumber));
foundInts = foundInts + 1;
Log.d(TAG, String.format("Ints: {%s} returned value {%s}",
liquid_string_setting, string_setting));
// tracking
handledSettingsArray.add(liquid_string_setting);
handledValuesArray.add(String.format("%d", testIsANumber));
info.append(String.format(formater, liquid_string_setting, string_setting) + RETURN);
mShowInfo.setText(info.toString());
} catch (SettingNotFoundException noSetting) {
unhandledSettingsArray.add(liquid_string_setting);
// not found
}
} catch (NumberFormatException ne) {
// it's a string not a number
if (string_setting != null) {
mProperties.setProperty(liquid_string_setting, string_setting);
foundStrings = foundStrings + 1;
Log.d(TAG, String.format("Strings: {%s} returned value {%s}",
liquid_string_setting, string_setting));
// tracking
handledSettingsArray.add(liquid_string_setting);
handledValuesArray.add(string_setting);
info.append(String.format(formater, liquid_string_setting, string_setting) + RETURN);
mShowInfo.setText(info.toString());
}
}
} catch (ClassCastException cce) {
if (CLASS_DEBUG) cce.printStackTrace();
} catch (NullPointerException npe) {
npe.printStackTrace();
}
}
if (DEBUG) {
Log.d(TAG, "How many properties were found and handled? Strings: " + foundStrings
+ " Ints: " + foundInts + " Floats: " + foundFloats);
Log.d(TAG, "how long are our lists? Strings: " + stringArray.size() + " Floats: " + floatArray.size());
}
// move down 2 lines before summary
info.append(LINE_SPACE);
info.append(String.format("We handled %d values of %d values",
handledSettingsArray.size(), unhandledSettingsArray.size()) + RETURN);
mShowInfo.setText(info.toString());
ArrayList<String> arrayUnhandled = new ArrayList<String>(settingsArray);
// include String[] in output
ArrayList<String[]> unhandledArrays = new ArrayList<String[]>(arrayOfStrings);
for (String[] string_ary : unhandledArrays) {
for (int ai = 0; ai < string_ary.length; ai++) arrayUnhandled.add(string_ary[ai]);
}
info.append(LINE_SPACE);
info.append("Properties we didn't find values for:" + RETURN);
// remove what we handled from array and display rest
for (String foundIt : handledSettingsArray) {
arrayUnhandled.remove(foundIt);
}
for (String notFoundIt : arrayUnhandled) {
info.append(notFoundIt.toString() + RETURN);
mShowInfo.setText(info.toString());
if (DEBUG) Log.d(TAG, "Unresolved Property: " + notFoundIt);
}
info.append(LINE_SPACE);
if (mProperties != null) {
try {
// TODO fix paths
File storeFile = new File(bkname);
mProperties.store(new FileOutputStream(storeFile.getAbsolutePath()), MESSAAGE_TO_HEAD_FILE);
if (DEBUG) Log.d(TAG, "Does storeFile exist? " + storeFile.exists() + " AbsolutPath: " + storeFile.getAbsolutePath());
success = true;
info.append("Saved file: " + bkname + RETURN);
mShowInfo.setText(info.toString());
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
} else {
if (DEBUG) Log.d(TAG, "mProperties was null");
}
// Notify user if files were created correctly
if (checkConfigFiles(bkname)) {
Toast.makeText(mContext, String.format(CONFIG_CHECK_PASS,
bkname), Toast.LENGTH_SHORT).show();
info.append(LINE_SPACE);
info.append(String.format("Settings saved! %s", bkname) + RETURN);
info.append(RETURN);
mShowInfo.setText(info.toString());
//handleStringArrays();
} else {
// TODO this provides no info to help debug THIS IS IMPORTANT it's all the users see ...maybe we give them counts of vars handled also?
Toast.makeText(mContext, "We encountered a problem, restore not created",
Toast.LENGTH_SHORT).show();
info.append(LINE_SPACE);
info.append(String.format("$#!+ we couldn't save to %s", bkname) + RETURN);
mShowInfo.setText(info.toString());
}
// info is up; let user go away
info.append(LINE_SPACE);
info.append("Thank you come again!" + RETURN);
mShowInfo.setText(info.toString());
mOkButton.setEnabled(true);
// update the screen
findThemes();
}
};
return mBackupHandler.post(mRunBackupThread);
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen prefScreen,
Preference pref) {
if (pref == mBackup) {
if (DEBUG) Log.d(TAG, "calling backup method");
showDialog(SAVE_CONFIG_DIALOG);
return true;
} else if (pref == mRestore) {
if (DEBUG) Log.d(TAG, "calling restore method");
runRestore();
return true;
}
return super.onPreferenceTreeClick(prefScreen, pref);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (DEBUG) Log.d(TAG, "requestCode=" + requestCode + " resultCode=" + resultCode + " Intent data=" + data);
if (requestCode == 1) {
// restore
try {
String supplied = data.getStringExtra(OPEN_FILENAME);
// false because user saved configs are not themes
wantToDeleteOrApply(supplied, false);
} catch (NullPointerException np) {
// user backed out of filepicker just move on
}
} else if (requestCode == 2) {
// save
try {
String supplied = data.getStringExtra(SAVE_FILENAME);
runBackup(supplied, null, null);
} catch (NullPointerException np) {
// user backed out of filepicker nothing to see here
}
} else {
// request code wasn't what we sent
Log.wtf(TAG, "This shouldn't ever happen ...shit is fucked up");
}
}
private boolean checkConfigFiles(String pathToConfig) {
File configNameSpace = new File(pathToConfig);
if (configNameSpace.exists() && configNameSpace.isFile() && configNameSpace.canRead()) {
if (DEBUG) Log.d(TAG, "config files have been saved for: {" + configNameSpace.getAbsolutePath() + "}");
return true;
} else {
if (DEBUG) Log.d(TAG, "config checks failed for: {" + configNameSpace.getAbsolutePath() + "}");
return false;
}
}
private void runRestore() {
// call the file picker then apply in the result
Intent open_file = new Intent(mContext, com.blackice.control.tools.FilePicker.class);
open_file.putExtra(OPEN_FILENAME, BLANK);
// false because we are not saving
open_file.putExtra("action", false);
// provide a path to start the user off on
open_file.putExtra("path", PATH_TO_CONFIGS);
// let users go where ever they want
open_file.putExtra("lock_dir", false);
// result code can be whatever but must match requestCode in onActivityResult
startActivityForResult(open_file, 1);
}
private boolean restore(final String open_data_string, final boolean isTheme) {
Handler mRestoreHandler = new Handler();
final Runnable mRestoreThread = new Runnable() {
public void run() {
try {
Log.d(TAG, String.format("extra open data found: %s", open_data_string));
// always reset the arrays so we don't get confused with the last index each array
setupArrays();
// determine the name to be used for opening saved config files
File nameSpaceFile = new File(open_data_string);
final String userSuppliedFilename = nameSpaceFile.getName();
if (DEBUG) {
Log.d(TAG, String.format("userSuppliedFilename=%s for nameSpaceFile=%s", userSuppliedFilename, nameSpaceFile));
}
// theme path is final but let user restores can come from anywhere
final String filename_strings = open_data_string;
final String theme_filename_strings = String.format("%s/BlackICEControl/themes/%s",
Environment.getExternalStorageDirectory(), userSuppliedFilename);
// TODO handle missing files
// get a view to work with
LayoutInflater i = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View restoreDialogLayout = i.inflate(R.layout.what_happened_dialog, null);
// setup smooth scrolling within our info dialog
ScrollView sv = (ScrollView) restoreDialogLayout.findViewById(R.id.what_happened_scrollview);
sv.setSmoothScrollingEnabled(true);
sv.fling(DEFAULT_FLING_SPEED);
// get final reference so we can minuplate text in try blocks
TextView mRestoreInfo = (TextView) sv.findViewById(R.id.what_happened_more_info);
// Show the user what happend
AlertDialog.Builder restoreDialog = new AlertDialog.Builder(getActivity());
restoreDialog.setTitle(getString(R.string.what_happened_title));
restoreDialog.setView(restoreDialogLayout);
restoreDialog.setPositiveButton(getString(R.string.positive_thanks_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
});
restoreDialog.setCancelable(false);
AlertDialog ad_ = restoreDialog.create();
ad_.show();
final Button mRestoreOk = (Button) ad_.getButton(AlertDialog.BUTTON_POSITIVE);
mRestoreOk.setEnabled(false);
StringBuilder collectInfo = new StringBuilder(settingsArray.size());
// first the strings
try {
File configFile;
if (isTheme) {
configFile = new File(theme_filename_strings);
if (DEBUG) Log.d(TAG, "Theme detected " + theme_filename_strings);
} else {
configFile = new File(filename_strings);
}
if (DEBUG) Log.d(TAG, String.format("Config file {%s} Exists? %s CanRead? %s",
configFile.getPath(), configFile.exists(), configFile.canRead()));
FileReader reader = new FileReader(configFile);
mProperties.load(reader);
// reset our indexes
setupArrays();
// use an army of clones for our dirty work -I think this is how the deathstar was started
ArrayList<String> array_strings = new ArrayList<String>(settingsArray);
ArrayList<String> array_ints = new ArrayList<String>(settingsArray);
ArrayList<String> array_floats = new ArrayList<String>(settingsArray);
ArrayList<String[]> array_string_array = new ArrayList<String[]>(arrayOfStrings);
ArrayList<String> arrays_handled = new ArrayList<String>();
int stringsHandled = 0;
int intsHandled = 0;
int floatsHandled = 0;
for (String[] sarray : array_string_array) {
for (int saint = 0; sarray.length > saint; saint++) {
Settings.System.putString(mContext.getContentResolver(), sarray[saint], ((String) mProperties.get(sarray[saint])));
}
}
for (String intPropCheck : array_ints) {
// don't handle floats here
if (!intPropCheck.contains("alpha")) {
if ((String) mProperties.get(intPropCheck) != null) {
try {
if (DEBUG) Log.d(TAG, String.format("Int property found: %s value: %s",
intPropCheck, (String) mProperties.get(intPropCheck)));
Settings.System.putInt(mContext.getContentResolver(), intPropCheck,
Integer.parseInt((String) mProperties.get(intPropCheck)));
intsHandled = intsHandled + 1;
arrays_handled.add(intPropCheck);
// if we handle the property remove it from the other lists
array_strings.remove(intPropCheck);
array_floats.remove(intPropCheck);
} catch (NumberFormatException nfe) {
if (CLASS_DEBUG) nfe.printStackTrace();
} catch (ClassCastException cce) {
// ok it's not a int
} catch (Exception e) {
if (DEBUG) e.printStackTrace();
}
}
}
}
for (String floatPropCheck : array_floats) {
if (floatPropCheck.contains("alpha")) {
if ((String) mProperties.get(floatPropCheck) != null) {
if (DEBUG) Log.d(TAG, String.format("Float property found: %s value: %s",
floatPropCheck, (String) mProperties.get(floatPropCheck)));
try {
Settings.System.putFloat(mContext.getContentResolver(), floatPropCheck,
Float.parseFloat((String) mProperties.get(floatPropCheck)));
array_strings.remove(floatPropCheck);
arrays_handled.add(floatPropCheck);
} catch (NumberFormatException nfe) {
if (DEBUG) nfe.printStackTrace();
} catch (ClassCastException cce) {
// ok it's not a float
} catch (Exception e) {
if (DEBUG) e.printStackTrace();
}
}
}
}
// we now have an array that contains only strings
for (String stringPropCheck : array_strings) {
if ((String) mProperties.get(stringPropCheck) != null) {
if (DEBUG) Log.d(TAG, String.format("String Property found: %s value: %s",
stringPropCheck, (String) mProperties.get(stringPropCheck)));
try {
Settings.System.putString(mContext.getContentResolver(), stringPropCheck,
(String) mProperties.get(stringPropCheck));
arrays_handled.add(stringPropCheck);
} catch (NumberFormatException nfe) {
if (DEBUG) nfe.printStackTrace();
} catch (ClassCastException cce) {
// this really shouldn't happen at this point
} catch (Exception e) {
if (DEBUG) e.printStackTrace();
}
}
}
// let the users know what happend
ArrayList<String> watcher = new ArrayList<String>(settingsArray);
String title_aquired = (String) mProperties.get("title");
String summary_aquired = (String) mProperties.get("summary");
if (title_aquired != null || summary_aquired != null) {
collectInfo.append("Theme title: " + title_aquired + RETURN);
collectInfo.append("Description: " + summary_aquired + RETURN);
collectInfo.append(LINE_SPACE);
}
collectInfo.append("Properties handled:" + RETURN);
collectInfo.append(RETURN);
for (String sweetShit : arrays_handled) {
collectInfo.append(sweetShit + "=" + (String) mProperties.get(sweetShit) + RETURN);
watcher.remove(sweetShit);
}
collectInfo.append(LINE_SPACE);
collectInfo.append("Properties not handled:" + RETURN);
for (String moreSweetShit : watcher) {
collectInfo.append(moreSweetShit + RETURN);
}
collectInfo.append(TWO_LINE_SPACE);
collectInfo.append(String.format("We restored %d properties of the available %d properties",
settingsArray.size() - watcher.size(), settingsArray.size()) + RETURN);
collectInfo.append(LINE_SPACE);
if (isTheme) {
collectInfo.append("Theme file: " + theme_filename_strings);
} else {
collectInfo.append("Backup file: " + filename_strings + RETURN);
}
collectInfo.append(LINE_SPACE);
collectInfo.append("Thank you come again!");
mRestoreInfo.setText(collectInfo.toString());
mRestoreOk.setEnabled(true);
if (DEBUG) Log.d(TAG, "Message found:" + LINE_SPACE + collectInfo.toString());
} catch (Exception e) {
// TODO covering all my bases not sure what this could throw ...lazy
if (DEBUG) e.printStackTrace();
}
} catch (NullPointerException npe) {
// let the user know and move on
if (DEBUG) npe.printStackTrace();
Toast.makeText(mContext, "no file was returned", Toast.LENGTH_SHORT).show();
}
// update screen
findThemes();
}
};
return mRestoreHandler.post(mRestoreThread);
}
private void setupArrays() {
// be sure we start fresh each time we load
settingsArray.clear();
/* XXX These data sets are a pain to maintain so PLEASE KEEP UP TODATE!!! XXX */
// Strings first
// UserInterface
settingsArray.add(Settings.System.CUSTOM_CARRIER_LABEL);
// StatusBarToggles
settingsArray.add(Settings.System.STATUSBAR_TOGGLES);
// ints next
// UserInterface
settingsArray.add(Settings.System.ACCELEROMETER_ROTATION_ANGLES);
settingsArray.add(Settings.System.RECENT_APP_SWITCHER);
settingsArray.add(Settings.System.CRT_OFF_ANIMATION);
settingsArray.add(Settings.System.SHOW_STATUSBAR_IME_SWITCHER);
settingsArray.add(Settings.Secure.KILL_APP_LONGPRESS_BACK);
settingsArray.add(Settings.System.ACCELEROMETER_ROTATION_SETTLE_TIME);
// Navbar
settingsArray.add(Settings.System.MENU_LOCATION);
settingsArray.add(Settings.System.MENU_VISIBILITY);
settingsArray.add(Settings.System.NAVIGATION_BAR_TINT);
settingsArray.add(Settings.System.NAVIGATION_BAR_BACKGROUND_COLOR);
settingsArray.add(Settings.System.NAVIGATION_BAR_HOME_LONGPRESS);
settingsArray.add(Settings.System.NAVIGATION_BAR_WIDTH);
settingsArray.add(Settings.System.NAVIGATION_BAR_HEIGHT);
settingsArray.add(Settings.System.NAVIGATION_BAR_BUTTONS_SHOW);
settingsArray.add(Settings.System.NAVIGATION_BAR_BUTTONS_QTY);
settingsArray.add(Settings.System.NAVIGATION_BAR_GLOW_TINT);
// Lockscreen
settingsArray.add(Settings.System.LOCKSCREEN_TEXT_COLOR);
settingsArray.add(Settings.System.LOCKSCREEN_LAYOUT);
settingsArray.add(Settings.System.LOCKSCREEN_ENABLE_MENU_KEY);
settingsArray.add(Settings.Secure.LOCK_SCREEN_LOCK_USER_OVERRIDE);
settingsArray.add(Settings.System.SHOW_LOCK_BEFORE_UNLOCK);
settingsArray.add(Settings.System.LOCKSCREEN_BATTERY);
settingsArray.add(Settings.System.VOLUME_WAKE_SCREEN);
settingsArray.add(Settings.System.VOLUME_MUSIC_CONTROLS);
settingsArray.add(Settings.System.LOCKSCREEN_HIDE_NAV);
settingsArray.add(Settings.System.LOCKSCREEN_LANDSCAPE);
settingsArray.add(Settings.System.LOCKSCREEN_QUICK_UNLOCK_CONTROL);
settingsArray.add(Settings.System.ENABLE_FAST_TORCH);
settingsArray.add(Settings.System.LOCKSCREEN_4TAB);
//settingsArray.add(Settings.System.LOCKSCREEN_LOW_BATTERY);
// Powermenu
settingsArray.add(Settings.System.POWER_DIALOG_SHOW_AIRPLANE_TOGGLE);
settingsArray.add(Settings.System.POWER_DIALOG_SHOW_TORCH_TOGGLE);
settingsArray.add(Settings.System.POWER_DIALOG_SHOW_NAVBAR_HIDE);
settingsArray.add(Settings.System.POWER_DIALOG_SHOW_PROFILE_CHOOSER);
settingsArray.add(Settings.System.POWER_DIALOG_SHOW_SCREENSHOT);
// StatusBarGeneral
settingsArray.add(Settings.System.STATUSBAR_SETTINGS_BEHAVIOR);
settingsArray.add(Settings.System.STATUSBAR_QUICKTOGGLES_AUTOHIDE);
settingsArray.add(Settings.System.DATE_OPENS_CALENDAR);
settingsArray.add(Settings.System.STATUS_BAR_BRIGHTNESS_TOGGLE);
settingsArray.add(Settings.Secure.ADB_ICON);
settingsArray.add(Settings.System.STATUSBAR_NOTIFICATION_COLOR);
settingsArray.add(Settings.System.STATUS_BAR_LAYOUT);
settingsArray.add(Settings.System.STATUSBAR_FONT_SIZE);
// StatusBarToggles
settingsArray.add(Settings.System.STATUSBAR_TOGGLES_USE_BUTTONS);
settingsArray.add(Settings.System.STATUSBAR_TOGGLES_BRIGHTNESS_LOC);
settingsArray.add(Settings.System.STATUSBAR_TOGGLES_STYLE);
// StatusBarClock
settingsArray.add(Settings.System.STATUSBAR_CLOCK_STYLE);
settingsArray.add(Settings.System.STATUSBAR_CLOCK_AM_PM_STYLE);
settingsArray.add(Settings.System.STATUSBAR_SHOW_ALARM);
settingsArray.add(Settings.System.STATUSBAR_CLOCK_COLOR);
settingsArray.add(Settings.System.STATUSBAR_CLOCK_WEEKDAY);
// StatusBarBattery
settingsArray.add(Settings.System.STATUSBAR_BATTERY_ICON);
settingsArray.add(Settings.System.STATUSBAR_BATTERY_BAR);
settingsArray.add(Settings.System.STATUSBAR_BATTERY_BAR_STYLE);
settingsArray.add(Settings.System.STATUSBAR_BATTERY_BAR_ANIMATE);
settingsArray.add(Settings.System.STATUSBAR_BATTERY_BAR_THICKNESS);
settingsArray.add(Settings.System.STATUSBAR_BATTERY_BAR_COLOR);
// StatusBarSignal
settingsArray.add(Settings.System.STATUSBAR_SIGNAL_TEXT);
settingsArray.add(Settings.System.STATUSBAR_SIGNAL_TEXT_COLOR);
settingsArray.add(Settings.System.STATUSBAR_HIDE_SIGNAL_BARS);
settingsArray.add(Settings.System.STATUSBAR_WIFI_SIGNAL_TEXT);
settingsArray.add(Settings.System.STATUSBAR_WIFI_SIGNAL_TEXT_COLOR);
// Misc
settingsArray.add(Settings.System.IS_TABLET);
// floats next
// Navbar
settingsArray.add(Settings.System.NAVIGATION_BAR_BUTTON_ALPHA);
// StatusBarGeneral
settingsArray.add(Settings.System.STATUSBAR_NOTIFICATION_ALPHA);
// easy stuff 0.o I wish i knew this was here a LONG TIME AGO!!!
int mProperBackupLength = Settings.System.SETTINGS_TO_BACKUP.length;
for (int i = 0; i < mProperBackupLength; i++) {
settingsArray.add(Settings.System.SETTINGS_TO_BACKUP[i]);
}
// add String[] to ArrayList<String[]>
arrayOfStrings.add(Settings.System.LOCKSCREEN_CUSTOM_APP_ICONS);
arrayOfStrings.add(Settings.System.LOCKSCREEN_CUSTOM_APP_ACTIVITIES);
arrayOfStrings.add(Settings.System.NAVIGATION_BAR_GLOW_DURATION);
arrayOfStrings.add(Settings.System.NAVIGATION_CUSTOM_APP_ICONS);
arrayOfStrings.add(Settings.System.NAVIGATION_CUSTOM_ACTIVITIES);
arrayOfStrings.add(Settings.System.NAVIGATION_LONGPRESS_ACTIVITIES);
// randomize arrays so we don't overly annoy any one area
Collections.shuffle(settingsArray);
}
public Dialog onCreateDialog(final int id) {
switch (id) {
case THEME_INFO_DIALOG:
// get a view to work with
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customLayout = inflater.inflate(R.layout.save_theme_dialog, null);
// TODO add filename and text watcher for valid filename
final EditText titleText = (EditText) customLayout.findViewById(R.id.title_input_edittext);
final EditText summaryText = (EditText) customLayout.findViewById(R.id.summary_input_edittext);
// for that personal touch //TODO make setText not hint
if (makeThemFeelAtHome != null) titleText.setText(makeThemFeelAtHome);
// TODO add generic hint bs
AlertDialog.Builder getInfo = new AlertDialog.Builder(getActivity());
getInfo.setTitle(getString(R.string.name_theme_title));
getInfo.setView(customLayout);
String delimiter = "_";
Calendar mTimeStamp = Calendar.getInstance();
final String timeBasedThemeName = Calendar.MONTH + Calendar.DAY_OF_MONTH + Calendar.YEAR + delimiter
+ Calendar.HOUR_OF_DAY + Calendar.MINUTE + Calendar.SECOND + delimiter + java.lang.System.currentTimeMillis();
getInfo.setNegativeButton(getString(R.string.negative_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// just run a normal backup in the theme dir
runRestore();
}
});
getInfo.setPositiveButton(getString(R.string.positive_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// get supplied info
String value_title = ((Spannable) titleText.getText()).toString();
String value_summary = ((Spannable) summaryText.getText()).toString();
if (DEBUG) Log.d(TAG, String.format("found title: %s found summary: %s", value_title, value_summary));
String formatThemePath = String.format("%s/BlackICEControl/themes/%s",
Environment.getExternalStorageDirectory(), timeBasedThemeName);
runBackup(formatThemePath, value_title, value_summary);
}
});
AlertDialog ad_info = getInfo.create();
ad_info.show();
final Button makeThemeButton = (Button) ad_info.getButton(AlertDialog.BUTTON_POSITIVE);
makeThemeButton.setEnabled(false);
makeThemeButton.setText(TEXT_IS_EMPTY);
titleText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable e) {
}
public void beforeTextChanged(CharSequence cs, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
String text = titleText.getText().toString();
int textLength = titleText.getText().length();
if (textLength > 0) {
makeThemeButton.setEnabled(true);
makeThemeButton.setText(getText(R.string.positive_button));
} else {
makeThemeButton.setEnabled(false);
makeThemeButton.setText(TEXT_IS_EMPTY);
}
}
});
return ad_info;
case SAVE_CONFIG_DIALOG:
// ask if user wants to make a theme
AlertDialog.Builder askTheme = new AlertDialog.Builder(getActivity());
askTheme.setTitle(getString(R.string.want_to_make_theme_title));
askTheme.setMessage(getString(R.string.want_to_make_theme_message));
askTheme.setPositiveButton(getString(R.string.positive_theme_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// launch theme maker
showDialog(THEME_INFO_DIALOG);
}
});
askTheme.setNegativeButton(getString(R.string.negative_theme_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// just run a normal backup
Intent save_file = new Intent(mContext, com.blackice.control.tools.FilePicker.class);
save_file.putExtra(SAVE_FILENAME, BLANK);
// true because we are saving
save_file.putExtra("action", true);
// provide a path to start the user off on
save_file.putExtra("path", PATH_TO_CONFIGS);
// let users go where ever they want
save_file.putExtra("lock_dir", false);
// result code can be whatever but must match requestCode in onActivityResult
startActivityForResult(save_file, 2);
}
});
AlertDialog ad_theme = askTheme.create();
ad_theme.show();
return ad_theme;
default:
return null;
}
}
}