[Android Apps and Games] Wuby986:
Full Working Backup/Restore preferences

Hello there!!!

we're ready with next step for the backup/restore preferences.. so the idea behind this update is to make it more simple, error proof and adding some part that were missing in last code posted..

so again in details:

1 -

- we will add a case to the onNavigationDrawerItemSelected method in MainActivityView.java, for my current avail options i went for case 5;

this way we're calling a new method that is going to show the popup with singleChoiceItem

case 5:
showBackupDialog();
break;

also we must add the entry to StringArray in string.xml and to add the icons in:

public List<NavItem> getMenu() in NavigationDrawerFragment.class and same method in MainActivityView, exacly as explained to add any other entry of the navDrawer in OP

2-

- now we create the above mentioned method: and the one that will actually do the backup

private void showBackupDialog() {
AlertDialog.Builder b = new AlertDialog.Builder(this);
Adapter adapter = new ArrayAdapter<>(this, R.layout.simple_list_item_single_choice, getResources().getStringArray(R.array.backup_items));
b.setTitle(getString(R.string.backup_dialog_title))
.setSingleChoiceItems((ListAdapter) adapter, PreferenceManager.getDefaultSharedPreferences(this).getInt("backup", 0), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int position) {
//based on position we do something
if (position == 0) {
dialog.dismiss();
//close dialog and open a new one
AlertDialog.Builder confirm = new AlertDialog.Builder(MainViewActivity.this);
confirm.setMessage(R.string.confirm_backup)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
AlertDialog.Builder restore = new AlertDialog.Builder(MainViewActivity.this);
restore.setMessage(R.string.restore_next_boot)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
backupPreferences();
//if user say ok to restore on next boot we create an empty file
//if is present the receiver will prompt the restore confirm on next boot up
File file = new File(bkpdir + "/auto_restore.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}

)
.setNeutralButton(R.string.later, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
backupPreferences();
//if file for auto_restore is present we delete it
File file = new File(bkpdir + "/auto_restore.txt");
if (file.exists()) {
file.delete();
}
}
}
)
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();

}
});
restore.create();
restore.show();
}
}

)
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();

}
});
confirm.create();
confirm.show();
} else
if (position == 1 ){
dialog.dismiss();
RestorePreferences rp = new RestorePreferences(MainViewActivity.this);
//this is the call for constructor
rp.showConfirmDialog();
}
}
})

;
AlertDialog d = b.create();
d.show();

}

private void backupPreferences() {
//we go into the shared_prefs folder and we read the files name's
File prefdir = new File("/data/data/com.wubydax.romcontrol/shared_prefs");
File filesdir = new File("/data/data/com.wubydax.romcontrol/files/FilePrefs");
if (bkpdir.listFiles() != null) {
for (File deleteBkp : bkpdir.listFiles()) {
deleteBkp.delete();

}
}
for (File f : prefdir.listFiles()) {
if (f.isFile()) {
String name = f.getName();
//if file is defult pref we don't backup as it doesn't go in the bd
if (!name.equals("com.wubydax.romcontrol_preferences.xml")) {
//we remove the xml suffix from filename and we assign it in the loop to the shared prefs
//this way we can use the getAll method of shared prefs for all the existing files in the folder
name = name.replace(".xml", "");
SharedPreferences pref = getSharedPreferences(name, MODE_PRIVATE);
//now we write to the backup file
Map<String, ?> allEntries = pref.getAll();
for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
try(
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(bkpdir + "/prefs.txt", true)))) {
out.println(entry.getKey() + ": " + entry.getValue().toString());

}catch (IOException e) {

}
}
}
}
}
if (filesdir.exists()) {
for (File files : filesdir.listFiles()) {
if (files.isFile()) {
String name = files.getName();
if (!name.contains("com.wubydax")) {
File filebackup = new File(bkpdir + "/" + name);
try {
filebackup.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
finish();
this.overridePendingTransition(0, R.animator.fadeout);
startActivity(new Intent(this, MainViewActivity.class));
this.overridePendingTransition(R.animator.fadein, 0);
}

3-

adding this method will return some error till we add missing strings and files path

so just above the onCreate method on top on the MainViewActivity class we add:

File sddir = new File(Environment.getExternalStorageDirectory().getPath()+"/RomControl");
File bkpdir = new File(sddir +"/backup");

these directory must be created from given path.. so we do it in the CheckSu async task, during the background tread we create for check su..

@Override
protected Boolean doInBackground(String... params) {
//Accessing the ability of the device to get root and the ability of app to achieve su privileges.
// if root is given we create the folders if not existing
if (RootTools.isAccessGiven()) {
if (!sddir.exists()) {
Log.d("sddir", "sddir doesn't exists");
sddir.mkdir();
bkpdir.mkdir();
}
return null;

} else {
return false;
}
}

4 -

now we need to do a small adjustment to the FilePreference.class in the pref subfolder in project tree.. this is going to make easier to find and check files in it.. we will save those to a specific folder inside /data/.../files/FilePrefs

this is the edit we need to do to the filedir variable in "public FilePreference(Context context, AttributeSet attrs)" constructor on top of the class

note is not the complete method, only relevant part

...
...
summaryOff = getStringForAttr(attrs, defaultNameSpace, "summaryOff", "");
//We will store our files inside package default files dir in /data/data/packagename/files/FilePrefs
filedir = new File(c.getFilesDir() +"/FilePrefs");
if (!filedir.exists()) {
filedir.mkdir();
}
file = new File(filedir + File.separator + key);
..
..

5-

now we add the new classes we need, so we go to the tree and right-click we create a new java class named "RestorePreferences" and inside we can copy this:

public class RestorePreferences {
ContentResolver cr;
Context c;
File sddir = new File(Environment.getExternalStorageDirectory().getPath()+"/RomControl");
File bkpdir = new File(sddir +"/backup");

public RestorePreferences(Context context) {
c = context;
cr = c.getContentResolver();

}

public void showConfirmDialog() {
//first of all we will display a popup that if confirm will start the real restore
AlertDialog confirm = new AlertDialog.Builder(new ContextThemeWrapper(c, R.style.AppTheme))
.setMessage(R.string.confirm_restore)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//here we call the method that is going to restore
restoreSettings();
}
}

)
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();

}
})
.create();
confirm.show();
}

public void restoreSettings() {
//first of all we delete any existing file in our special file preference folder
//by check if list of files inside the folder is not null and if so delete each one
File deletecurr = new File(c.getFilesDir()+"/FilePrefs");
if (deletecurr.listFiles() != null) {
for (File deleteBkp : deletecurr.listFiles()) {
deleteBkp.delete();

}
}
//now we read the backup preference file
File file = new File(bkpdir +"/prefs.txt");
if (file.exists())
try {
BufferedReader br = new BufferedReader(new FileReader(file));
//for each line of the file we spilt it into before the ":" the key part and after the value
for (String line = br.readLine(); line != null; line = br.readLine()) {
String key = line.substring(0, line.indexOf(":"));
String value = line.substring(line.indexOf(" ") + 1, line.length());
//if value is a bolean we replace the preference value with a value suitable for database
//then we are ready to write into db
if (value.equals("false")) {
Settings.System.putString(cr, String.valueOf(key), "0");
} else if (value.equals("true")) {
Settings.System.putString(cr, String.valueOf(key), "1");
} else
Settings.System.putString(cr, String.valueOf(key), String.valueOf(value));
}
} catch (IOException e) {
}
//now we read the special prefs file
for (File files : bkpdir.listFiles()) {
if (files.isFile()) {
Log.d("restore", "found file"+ files);
String name = files.getName();
if (!name.endsWith(".txt")) {
Log.d("restore", "file is not txt");
File filerestore = new File(deletecurr +"/" + name);
Log.d("restore", name);
try {
filerestore.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
if (c instanceof MainViewActivity) {
((Activity) c).finish();
Intent start = new Intent(c, MainViewActivity.class);
start.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
c.startActivity(start);
}
}

}

it will ask you to import the class unless you didn't add the auto import

6-

other 2 class must be created:

BootRestoreService and BootCompleteReceiver..

these 2 are the receiver and the service that are going to start the restore on first boot, and only if user selected it on last backup..

let's add them!!

public class BootCompleteReceiver extends BroadcastReceiver {
File dir = new File(Environment.getExternalStorageDirectory().getPath()+"/RomControl");

@Override
public void onReceive(Context context, Intent intent) {
boolean firstTime = PreferenceManager.getDefaultSharedPreferences(context).getBoolean("first_time", true);
if (firstTime) {
File file = new File(dir +"/auto_restore.txt");
if (file.exists()) {
context.startService(new Intent(context, BootRestoreService.class));
}
}
}
}

public class BootRestoreService extends Service {

public BootRestoreService() {
}

@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}

@Override
public void onCreate() {
super.onCreate();
showConfirmDialog();
}

private void showConfirmDialog() {

AlertDialog confirm = new AlertDialog.Builder(this)
.setMessage(R.string.confirm_restore)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
RestorePreferences rp = new RestorePreferences(BootRestoreService.this);
rp.restoreSettings();
BootRestoreService.this.stopSelf();
}
}

)
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
BootRestoreService.this.stopSelf();

}
})
.create();
confirm.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
confirm.show();

}
}

last thing the manifest..

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wubydax.romcontrol">

<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.Transparent">
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

<activity
android:name=".MainViewActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name=".BootRestoreService"
android:enabled="true"
android:exported="true"></service>
</application>

</manifest>

so this is all.. since i am cherrypicking from current studio project, i might have forgot something.. so please let us know if is all fine once you tried, or if you find any bug or simply want to know something.. it should have been cleaned from debug log tag and so on, and been commented.. if not clear ,as said, just ask..

and enjoy!!!!