X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/8aa10abb181ee596ffaa751b6dfcb0da10a51d9e..cdabcf7b34dfe47835fdf1bee5a538928d966dce:/src/com/owncloud/android/ui/activity/StorageMigrationActivity.java diff --git a/src/com/owncloud/android/ui/activity/StorageMigrationActivity.java b/src/com/owncloud/android/ui/activity/StorageMigrationActivity.java index c5dc59ba..5ff18c2d 100644 --- a/src/com/owncloud/android/ui/activity/StorageMigrationActivity.java +++ b/src/com/owncloud/android/ui/activity/StorageMigrationActivity.java @@ -20,12 +20,290 @@ */ package com.owncloud.android.ui.activity; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.owncloud.android.MainApp; +import com.owncloud.android.R; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.lib.common.utils.Log_OC; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; /** * Created by Bartosz Przybylski on 07.11.2015. */ public class StorageMigrationActivity extends AppCompatActivity { + private static final String TAG = StorageMigrationActivity.class.getName(); public static final String KEY_MIGRATION_TARGET_DIR = "MIGRATION_TARGET"; public static final String KEY_MIGRATION_SOURCE_DIR = "MIGRATION_SOURCE"; + + private ProgressBar mProgressBar; + private Button mFinishButton; + private TextView mFeedbackText; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.migration_layout); + mProgressBar = (ProgressBar)findViewById(R.id.migrationProgress); + mFinishButton = (Button)findViewById(R.id.finishButton); + mFeedbackText = (TextView)findViewById(R.id.migrationText); + + mProgressBar.setProgress(0); + mFinishButton.setVisibility(View.INVISIBLE); + mFeedbackText.setText(R.string.file_migration_preparing); + + mFinishButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + setResult(RESULT_CANCELED); + finish(); + } + }); + + String source = getIntent().getStringExtra(KEY_MIGRATION_SOURCE_DIR); + String destination = getIntent().getStringExtra(KEY_MIGRATION_TARGET_DIR); + + if (source == null || destination == null) { + Log_OC.e(TAG, "source or destination is null"); + finish(); + } + + new FileMigrationTask().execute(source, destination); + } + + private class FileMigrationTask extends AsyncTask { + + private String mStorageTarget; + private String mStorageSource; + + private class MigrationException extends Exception { + private int mResId; + /* + * @param resId resource identifier to use for displaying error + */ + MigrationException(int resId) { + super(); + this.mResId = resId; + } + + int getResId() { return mResId; } + } + + @Override + protected Integer doInBackground(String... args) { + + mStorageSource = args[0]; + mStorageTarget = args[1]; + + int progress = 0; + publishProgress(progress++, R.string.file_migration_preparing); + + Context context = StorageMigrationActivity.this; + String ocAuthority = context.getString(R.string.authority); + + Account[] ocAccounts = AccountManager.get(context).getAccountsByType(MainApp.getAccountType()); + boolean[] oldAutoSync = new boolean[ocAccounts.length]; + + try { + publishProgress(progress++, R.string.file_migration_checking_destination); + + checkDestinationAvailability(); + + publishProgress(progress++, R.string.file_migration_saving_accounts_configuration); + saveAccountsSyncStatus(ocAuthority, ocAccounts, oldAutoSync); + + publishProgress(progress++, R.string.file_migration_waiting_for_unfinished_sync); + stopAccountsSyncing(ocAuthority, ocAccounts); + waitForUnfinishedSynchronizations(ocAuthority, ocAccounts); + + publishProgress(progress++, R.string.file_migration_migrating); + copyFiles(); + + publishProgress(progress++, R.string.file_migration_updating_index); + updateIndex(context); + + publishProgress(progress++, R.string.file_migration_cleaning); + cleanup(); + + } catch (MigrationException e) { + return e.getResId(); + } finally { + publishProgress(progress++, R.string.file_migration_restoring_accounts_configuration); + restoreAccountsSyncStatus(ocAuthority, ocAccounts, oldAutoSync); + } + + publishProgress(progress++, R.string.file_migration_ok_finished); + + return 0; + } + + @Override + protected void onProgressUpdate(Integer... progress) { + mProgressBar.setProgress(progress[0]); + if (progress.length > 1) + mFeedbackText.setText(progress[1]); + } + + @Override + protected void onPostExecute(Integer code) { + mFinishButton.setVisibility(View.VISIBLE); + if (code != 0) { + mFeedbackText.setText(code); + } else { + mFeedbackText.setText(R.string.file_migration_ok_finished); + mFinishButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent resultIntent = new Intent(); + resultIntent.putExtra(KEY_MIGRATION_TARGET_DIR, mStorageTarget); + setResult(RESULT_OK, resultIntent); + finish(); + } + }); + } + } + + void checkDestinationAvailability() throws MigrationException { + File srcFile = new File(mStorageSource); + File dstFile = new File(mStorageTarget); + + if (!dstFile.canRead() || !srcFile.canRead()) + throw new MigrationException(R.string.file_migration_failed_not_readable); + + if (!dstFile.canWrite() || !srcFile.canWrite()) + throw new MigrationException(R.string.file_migration_failed_not_writable); + + if (new File(dstFile, MainApp.getDataFolder()).exists()) + throw new MigrationException(R.string.file_migration_failed_dir_already_exists); + + if (dstFile.getFreeSpace() < calculateUsedSpace(new File(srcFile, MainApp.getDataFolder()))) + throw new MigrationException(R.string.file_migration_failed_not_enough_space); + } + + void copyFiles() throws MigrationException { + File srcFile = new File(mStorageSource + File.separator + MainApp.getDataFolder()); + File dstFile = new File(mStorageTarget + File.separator + MainApp.getDataFolder()); + + copyDirs(srcFile, dstFile); + } + + private boolean copyFile(File src, File target) { + boolean ret = true; + + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(src); + out = new FileOutputStream(target); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } catch (IOException ex) { + ret = false; + } finally { + if (in != null) try { + in.close(); + } catch (IOException e) { + e.printStackTrace(System.err); + } + if (out != null) try { + out.close(); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + + return ret; + } + + void copyDirs(File src, File dst) throws MigrationException { + if (!dst.mkdirs()) + throw new MigrationException(R.string.file_migration_failed_while_coping); + + for (File f : src.listFiles()) { + if (f.isDirectory()) + copyDirs(f, new File(dst, f.getName())); + else if (!copyFile(f, new File(dst, f.getName()))) + throw new MigrationException(R.string.file_migration_failed_while_coping); + } + + } + + void updateIndex(Context context) throws MigrationException { + FileDataStorageManager manager = new FileDataStorageManager(null, context.getContentResolver()); + + try { + manager.migrateStoredFiles(mStorageSource, mStorageTarget); + } catch (Exception e) { + throw new MigrationException(R.string.file_migration_failed_while_updating_index); + } + + } + + void cleanup() { + + } + + long calculateUsedSpace(File dir) { + long result = 0; + + for (File f : dir.listFiles()) { + if (f.isDirectory()) + result += calculateUsedSpace(f); + else + result += f.length(); + } + + return result; + } + + void saveAccountsSyncStatus(String authority, Account accounts[], boolean syncs[]) { + for (int i = 0; i < accounts.length; ++i) { + syncs[i] = ContentResolver.getSyncAutomatically(accounts[i], authority); + } + } + + void stopAccountsSyncing(String authority, Account accounts[]) { + for (int i = 0; i < accounts.length; ++i) + ContentResolver.setSyncAutomatically(accounts[i], authority, false); + } + + void waitForUnfinishedSynchronizations(String authority, Account accounts[]) { + for (int i = 0; i < accounts.length; ++i) + while (ContentResolver.isSyncActive(accounts[i], authority)) + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Log_OC.w(TAG, "Thread interrupted while waiting for account to end syncing"); + } + } + + + void restoreAccountsSyncStatus(String authority, Account accounts[], boolean oldSync[]) { + for (int i = 0; i < accounts.length; ++i) + ContentResolver.setSyncAutomatically(accounts[i], authority, oldSync[i]); + } + + } }