package me.ccrama.redditslide.Activities; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.support.design.widget.Snackbar; import android.util.Log; import android.view.View; import android.widget.TextView; import android.graphics.Color; import com.afollestad.materialdialogs.AlertDialogWrapper; import com.afollestad.materialdialogs.MaterialDialog; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.drive.Drive; import com.google.android.gms.drive.DriveApi; import com.google.android.gms.drive.DriveContents; import com.google.android.gms.drive.DriveFile; import com.google.android.gms.drive.DriveFolder; import com.google.android.gms.drive.DriveId; import com.google.android.gms.drive.Metadata; import com.google.android.gms.drive.MetadataChangeSet; import com.jakewharton.processphoenix.ProcessPhoenix; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Closeable; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Calendar; import me.ccrama.redditslide.R; import me.ccrama.redditslide.SettingValues; import me.ccrama.redditslide.util.LogUtil; /** * Created by ccrama on 3/5/2015. */ public class SettingsBackup extends BaseActivityAnim implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { MaterialDialog progress; DriveFolder appFolder; String title; final private ResultCallback<DriveApi.MetadataBufferResult> newCallback = new ResultCallback<DriveApi.MetadataBufferResult>() { @Override public void onResult(DriveApi.MetadataBufferResult result) { int i = 0; for (Metadata a : result.getMetadataBuffer()) { i++; title = a.getTitle(); new RetrieveDriveFileContentsAsyncTask(title).execute(a.getDriveId()); } progress = new MaterialDialog.Builder(SettingsBackup.this).title(R.string.backup_restoring).progress(false, i).build(); progress.show(); } }; final private ResultCallback<DriveApi.MetadataBufferResult> newCallback2 = new ResultCallback<DriveApi.MetadataBufferResult>() { @Override public void onResult(DriveApi.MetadataBufferResult result) { int i = 0; for (Metadata a : result.getMetadataBuffer()) { i++; title = a.getTitle(); DriveFile file = a.getDriveId().asDriveFile(); file.delete(mGoogleApiClient); } Drive.DriveApi.requestSync(mGoogleApiClient); File prefsdir = new File(getApplicationInfo().dataDir, "shared_prefs"); if (prefsdir.exists() && prefsdir.isDirectory()) { String[] list = prefsdir.list(); for (final String s : list) { if (!s.contains("com.google") && !s.contains("cache") && !s.contains("STACKTRACE")) { title = s; Drive.DriveApi.newDriveContents(mGoogleApiClient) .setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() { @Override public void onResult(DriveApi.DriveContentsResult result) { final String copy = getApplicationInfo().dataDir + File.separator + "shared_prefs" + File.separator + s; Log.v(LogUtil.getTag(), "LOCATION IS " + copy); if (!result.getStatus().isSuccess()) { return; } final DriveContents driveContents = result.getDriveContents(); // Perform I/O off the UI thread. new Thread() { @Override public void run() { // write content to DriveContents OutputStream outputStream = driveContents.getOutputStream(); Writer writer = new OutputStreamWriter(outputStream); String content = null; File file = new File(copy); //for ex foo.txt FileReader reader = null; try { try { reader = new FileReader(file); char[] chars = new char[(int) file.length()]; reader.read(chars); content = new String(chars); Log.v(LogUtil.getTag(), content); reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { reader.close(); } } writer.write(content); writer.close(); } catch (Exception e) { Log.e(LogUtil.getTag(), e.getMessage()); } MetadataChangeSet changeSet = new MetadataChangeSet.Builder() .setTitle(s) .setMimeType("text/xml") .build(); // create a file on root folder appFolder .createFile(mGoogleApiClient, changeSet, driveContents) .setResultCallback(fileCallback); } }.start(); } }); } else { progress.setProgress(progress.getCurrentProgress() + 1); if (progress.getCurrentProgress() == progress.getMaxProgress()) { new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(R.string.backup_success) .setPositiveButton(R.string.btn_close, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); } } } } } }; int errors; final private ResultCallback<DriveFolder.DriveFileResult> fileCallback = new ResultCallback<DriveFolder.DriveFileResult>() { @Override public void onResult(DriveFolder.DriveFileResult result) { progress.setProgress(progress.getCurrentProgress() + 1); if (!result.getStatus().isSuccess()) { errors += 1; return; } if (progress.getCurrentProgress() == progress.getMaxProgress()) { new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(R.string.backup_success) .setPositiveButton(R.string.btn_close, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }).show(); } } }; private GoogleApiClient mGoogleApiClient; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 24) { if (resultCode == RESULT_OK) { mGoogleApiClient.connect(); } } else if (requestCode == 42) { progress = new MaterialDialog.Builder(SettingsBackup.this) .title(R.string.backup_restoring) .content(R.string.misc_please_wait) .cancelable(false) .progress(true, 1) .build(); progress.show(); if (data != null) { Uri fileUri = data.getData(); Log.v(LogUtil.getTag(), "WORKED! " + fileUri.toString()); File path = new File(fileUri.getPath()); StringWriter fw = new StringWriter(); try { FileReader fr = new FileReader(path); int c = fr.read(); while (c != -1) { fw.write(c); c = fr.read(); } String read = fw.toString(); if (read.contains("Slide_backupEND>")) { String[] files = read.split("END>"); progress.dismiss(); progress = new MaterialDialog.Builder(SettingsBackup.this).title(R.string.backup_restoring).progress(false, files.length - 1).build(); progress.show(); for (int i = 1; i < files.length; i++) { String innerFile = files[i]; String t = innerFile.substring(6, innerFile.indexOf(">")); innerFile = innerFile.substring(innerFile.indexOf(">") + 1, innerFile.length()); File newF = new File(getApplicationInfo().dataDir + File.separator + "shared_prefs" + File.separator + t); Log.v(LogUtil.getTag(), "WRITING TO " + newF.getAbsolutePath()); try { FileWriter newfw = new FileWriter(newF); BufferedWriter bw = new BufferedWriter(newfw); bw.write(innerFile); bw.close(); progress.setProgress(progress.getCurrentProgress() + 1); } catch (IOException e) { e.printStackTrace(); } } new AlertDialogWrapper.Builder(SettingsBackup.this) .setCancelable(false) .setTitle(R.string.backup_restore_settings) .setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { ProcessPhoenix.triggerRebirth(SettingsBackup.this); } }) .setMessage(R.string.backup_restarting).setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { ProcessPhoenix.triggerRebirth(SettingsBackup.this); } }).setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ProcessPhoenix.triggerRebirth(SettingsBackup.this); } }).show(); } else { progress.hide(); new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(getString(me.ccrama.redditslide.R.string.err_not_valid_backup)) .setMessage(getString(me.ccrama.redditslide.R.string.err_not_valid_backup_msg)) .setPositiveButton(R.string.btn_ok, null).show(); } } catch (Exception e) { progress.hide(); e.printStackTrace(); new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(getString(me.ccrama.redditslide.R.string.err_file_not_found)) .setMessage(getString(me.ccrama.redditslide.R.string.err_file_not_found_msg)) .setPositiveButton(R.string.btn_ok, null).show(); } } else { progress.dismiss(); new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(getString(me.ccrama.redditslide.R.string.err_file_not_found)) .setMessage(getString(me.ccrama.redditslide.R.string.err_file_not_found_msg)) .setPositiveButton(R.string.btn_ok, null).show(); } } } @Override protected void onStart() { super.onStart(); if (SettingValues.tabletUI) mGoogleApiClient.connect(); } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); applyColorTheme(); setContentView(R.layout.activity_settings_sync); setupAppBar(R.id.toolbar, R.string.settings_title_backup, true, true); if (SettingValues.tabletUI) { mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Drive.API) .addScope(Drive.SCOPE_FILE) .addScope(Drive.SCOPE_APPFOLDER) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); findViewById(R.id.back).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mGoogleApiClient.isConnected()) { File prefsdir = new File(getApplicationInfo().dataDir, "shared_prefs"); if (prefsdir.exists() && prefsdir.isDirectory()) { String[] list = prefsdir.list(); progress = new MaterialDialog.Builder(SettingsBackup.this).title(R.string.backup_backing_up).progress(false, list.length).cancelable(false).build(); progress.show(); appFolder.listChildren(mGoogleApiClient).setResultCallback(newCallback2); } } else { new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(R.string.settings_google) .setMessage(R.string.settings_google_msg) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { } }) .setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }).show(); } } }); findViewById(R.id.restore).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mGoogleApiClient.isConnected()) { progress = new MaterialDialog.Builder(SettingsBackup.this) .title(R.string.backup_restoring) .content(R.string.misc_please_wait) .cancelable(false) .progress(true, 1) .build(); progress.show(); appFolder.listChildren(mGoogleApiClient).setResultCallback(newCallback); } else { new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(R.string.settings_google) .setMessage(R.string.settings_google_msg) //avoid that the dialog can be closed .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { } }) .setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { } }).show(); } } }); findViewById(R.id.backfile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(getString(me.ccrama.redditslide.R.string.include_personal_info)) .setMessage(getString(me.ccrama.redditslide.R.string.include_personal_info_msg)) .setPositiveButton(R.string.btn_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { backupToDir(false); } }) .setNegativeButton(R.string.btn_no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { backupToDir(true); } }) .setNeutralButton(R.string.btn_cancel, null) .show(); } }); findViewById(R.id.restorefile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("file/txt"); startActivityForResult(intent, 42); } }); } else { new AlertDialogWrapper.Builder(this).setTitle( "Settings Backup is a Pro feature") .setMessage(R.string.pro_upgrade_msg) //avoid that the dialog can be closed .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { finish(); } }) .setPositiveButton(R.string.btn_yes_exclaim, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=me.ccrama.slideforreddittabletuiunlock"))); } catch (android.content.ActivityNotFoundException anfe) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=me.ccrama.slideforreddittabletuiunlock"))); } } }).setNegativeButton(R.string.btn_no_danks, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { finish(); } }).show(); } } File file; public void backupToDir(final boolean personal) { new AsyncTask<Void, Void, Void>() { @Override protected void onPreExecute() { progress = new MaterialDialog.Builder(SettingsBackup.this).title(R.string.backup_backing_up).progress(false, 40).cancelable(false).build(); progress.show(); } @Override protected Void doInBackground(Void... params) { File prefsdir = new File(getApplicationInfo().dataDir, "shared_prefs"); if (prefsdir.exists() && prefsdir.isDirectory()) { String[] list = prefsdir.list(); Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdirs(); File backedup = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "Slide" + new SimpleDateFormat("MMddyy-hh:mm").format(Calendar.getInstance().getTime()) + (!personal ? "-personal" : "") + ".txt"); file = backedup; FileWriter fw = null; try { backedup.createNewFile(); fw = new FileWriter(backedup); fw.write("Slide_backupEND>"); for (String s : list) { if (!s.contains("cache") && !s.contains("ion-cookies") && !s.contains("albums") && !s.contains("STACKTRACE") && !s.contains("com.google") && (((personal && !s.contains("SUBSNEW") && !s.contains("appRestart") && !s.contains("AUTH") && !s.contains("TAGS") && !s.contains("SEEN") && !s.contains("HIDDEN") && !s.contains("HIDDEN_POSTS"))) || !personal)) { FileReader fr = null; try { fr = new FileReader(new File(prefsdir + File.separator + s)); int c = fr.read(); fw.write("<START" + new File(s).getName() + ">"); while (c != -1) { fw.write(c); c = fr.read(); } fw.write("END>"); } catch (IOException e) { e.printStackTrace(); } finally { close(fr); } } } return null; } catch (Exception e) { e.printStackTrace(); //todo error } finally { close(fw); } } return null; } @Override protected void onPostExecute(Void aVoid) { progress.dismiss(); new AlertDialogWrapper.Builder(SettingsBackup.this).setTitle(getString(me.ccrama.redditslide.R.string.backup_complete)) .setMessage(getString(me.ccrama.redditslide.R.string.backup_saved_downloads)) .setPositiveButton(R.string.btn_view, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Uri selectedUri = Uri.parse("file://" + file.getAbsolutePath()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(selectedUri); if (intent.resolveActivityInfo(getPackageManager(), 0) != null) { startActivity(Intent.createChooser(intent, "View backup")); } else { Snackbar s = Snackbar.make(findViewById(R.id.restorefile), "No file explorer found, file located at " + file.getAbsolutePath(), Snackbar.LENGTH_INDEFINITE); View view = s.getView(); TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text); tv.setTextColor(Color.WHITE); s.show(); } } }) .setNegativeButton(R.string.btn_close, null) .show(); } }.execute(); } public static void close(Closeable stream) { try { if (stream != null) { stream.close(); } } catch (IOException e) { } } @Override public void onConnected(Bundle bundle) { appFolder = Drive.DriveApi.getAppFolder(mGoogleApiClient); Drive.DriveApi.requestSync(mGoogleApiClient); } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { if (connectionResult.hasResolution()) { try { connectionResult.startResolutionForResult(this, 24); } catch (IntentSender.SendIntentException e) { // Unable to resolve, message user appropriately } } else { GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(), this, 0).show(); } } final private class RetrieveDriveFileContentsAsyncTask extends AsyncTask<DriveId, Boolean, String> { String t; public RetrieveDriveFileContentsAsyncTask(String title) { t = title; } @Override protected String doInBackground(DriveId... params) { String contents = null; DriveFile file = params[0].asDriveFile(); DriveApi.DriveContentsResult driveContentsResult = file.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).await(); if (!driveContentsResult.getStatus().isSuccess()) { return null; } DriveContents driveContents = driveContentsResult.getDriveContents(); BufferedReader reader = new BufferedReader( new InputStreamReader(driveContents.getInputStream())); StringBuilder builder = new StringBuilder(); String line; try { while ((line = reader.readLine()) != null) { builder.append(line); } contents = builder.toString(); } catch (IOException e) { Log.e(LogUtil.getTag(), "IOException while reading from the stream", e); } File newF = new File(getApplicationInfo().dataDir + File.separator + "shared_prefs" + File.separator + t); Log.v(LogUtil.getTag(), "WRITING TO " + newF.getAbsolutePath()); try { FileWriter fw = new FileWriter(newF); BufferedWriter bw = new BufferedWriter(fw); bw.write(contents); bw.close(); progress.setProgress(progress.getCurrentProgress() + 1); } catch (IOException e) { e.printStackTrace(); } driveContents.discard(mGoogleApiClient); return contents; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); if (progress.getCurrentProgress() == progress.getMaxProgress()) { progress.dismiss(); new AlertDialogWrapper.Builder(SettingsBackup.this) .setTitle(R.string.backup_restore_settings) .setMessage(R.string.backup_restarting).setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { ProcessPhoenix.triggerRebirth(SettingsBackup.this); } }).setPositiveButton(R.string.btn_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ProcessPhoenix.triggerRebirth(SettingsBackup.this); } }).show(); } if (result == null) { //showMessage("Error while reading from the file"); return; } Log.v(LogUtil.getTag(), "File contents: " + result); } } }