Give the user the option to move all the foreign files into the ownCloud local folder...
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / activity / ErrorsWhileCopyingHandlerActivity.java
diff --git a/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java b/src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
new file mode 100644 (file)
index 0000000..01e4574
--- /dev/null
@@ -0,0 +1,258 @@
+package com.owncloud.android.ui.activity;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.DialogFragment;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.dialog.IndeterminateProgressDialog;
+import com.owncloud.android.utils.FileStorageUtils;
+
+
+/**
+ * Activity reporting errors occurred when local files uploaded to an ownCloud account with an app in
+ * version under 1.3.16 where being copied to the ownCloud local folder.
+ * 
+ * Allows the user move the files to the ownCloud local folder, or let them unlinked to the remote
+ * files.
+ * 
+ * Shown when the error notification summarizing the list of errors is clicked by the user.
+ * 
+ * @author David A. Velasco
+ */
+public class ErrorsWhileCopyingHandlerActivity  extends SherlockFragmentActivity implements OnClickListener {
+
+    private static final String TAG = ErrorsWhileCopyingHandlerActivity.class.getSimpleName();
+    
+    public static final String EXTRA_ACCOUNT = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_ACCOUNT";
+    public static final String EXTRA_LOCAL_PATHS = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_LOCAL_PATHS";
+    public static final String EXTRA_REMOTE_PATHS = ErrorsWhileCopyingHandlerActivity.class.getCanonicalName() + ".EXTRA_REMOTE_PATHS";
+
+    private static final String WAIT_DIALOG_TAG = "WAIT_DIALOG";
+    
+    protected Account mAccount;
+    protected FileDataStorageManager mStorageManager;
+    protected ArrayList<String> mLocalPaths;
+    protected ArrayList<String> mRemotePaths;
+    protected ArrayAdapter<String> mAdapter;
+    protected Handler mHandler;
+    private DialogFragment mCurrentDialog;
+    
+    /**
+     * {@link}
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        /// read extra parameters in intent
+        Intent intent = getIntent();
+        mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT);
+        mRemotePaths = intent.getStringArrayListExtra(EXTRA_REMOTE_PATHS);
+        mLocalPaths = intent.getStringArrayListExtra(EXTRA_LOCAL_PATHS);
+        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+        mHandler = new Handler();
+        if (mCurrentDialog != null) {
+            mCurrentDialog.dismiss();
+            mCurrentDialog = null;
+        }
+        
+        /// load generic layout
+        setContentView(R.layout.generic_explanation);
+        
+        /// customize text message
+        TextView textView = (TextView) findViewById(R.id.message);
+        String appName = getString(R.string.app_name);
+        String message = String.format(getString(R.string.sync_foreign_files_forgotten_explanation), appName, appName, appName, appName, mAccount.name);
+        textView.setText(message);
+        textView.setMovementMethod(new ScrollingMovementMethod());
+        
+        /// load the list of local and remote files that failed
+        ListView listView = (ListView) findViewById(R.id.list);
+        if (mLocalPaths != null && mLocalPaths.size() > 0) {
+            mAdapter = new ErrorsWhileCopyingListAdapter();
+            listView.setAdapter(mAdapter);
+        } else {
+            listView.setVisibility(View.GONE);
+            mAdapter = null;
+        }
+        
+        /// customize buttons
+        Button cancelBtn = (Button) findViewById(R.id.cancel);
+        Button okBtn = (Button) findViewById(R.id.ok);
+        okBtn.setText(R.string.foreign_files_move);
+        cancelBtn.setOnClickListener(this);
+        okBtn.setOnClickListener(this);
+    }
+    
+    
+    /**
+     * Customized adapter, showing the local files as main text in two-lines list item and the remote files
+     * as the secondary text. 
+     * 
+     * @author David A. Velasco
+     */
+    public class ErrorsWhileCopyingListAdapter extends ArrayAdapter<String> {
+        
+        ErrorsWhileCopyingListAdapter() {
+            super(ErrorsWhileCopyingHandlerActivity.this, android.R.layout.two_line_list_item, android.R.id.text1, mLocalPaths);
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return false;
+        }
+        
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public View getView (int position, View convertView, ViewGroup parent) {
+            View view = convertView;
+            if (view == null) {
+                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                view = vi.inflate(android.R.layout.two_line_list_item, null);
+            }
+            if (view != null)  {
+                String localPath = getItem(position);
+                if (localPath != null) {
+                    TextView text1 = (TextView) view.findViewById(android.R.id.text1);
+                    if (text1 != null) {
+                        text1.setText(String.format(getString(R.string.foreign_files_local_text), localPath));
+                    }
+                }
+                if (mRemotePaths != null && mRemotePaths.size() > 0 && position >= 0 && position < mRemotePaths.size()) {
+                    TextView text2 = (TextView) view.findViewById(android.R.id.text2);
+                    String remotePath = mRemotePaths.get(position);
+                    if (text2 != null && remotePath != null) {
+                        text2.setText(String.format(getString(R.string.foreign_files_remote_text), remotePath));
+                    }
+                }
+            }
+            return view;
+        }
+    }
+
+
+    /**
+     * Listener method to perform the MOVE / CANCEL action available in this activity.
+     * 
+     * @param v     Clicked view (button MOVE or CANCEL)
+     */
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.ok) {
+            /// perform movement operation in background thread
+            Log.d(TAG, "Clicked MOVE, start movement");
+            new MoveFilesTask().execute();            
+            
+        } else if (v.getId() == R.id.cancel) {
+            /// just finish
+            Log.d(TAG, "Clicked CANCEL, bye");
+            finish();
+            
+        } else {
+            Log.e(TAG, "Clicked phantom button, id: " + v.getId());
+        }
+    }
+
+    
+    /**
+     * Asynchronous task performing the move of all the local files to the ownCloud folder.
+     * 
+     * @author David A. Velasco
+     */
+    private class MoveFilesTask extends AsyncTask<Void, Void, Boolean> {
+
+        /**
+         * Updates the UI before trying the movement
+         */
+        @Override
+        protected void onPreExecute () {
+            /// progress dialog and disable 'Move' button
+            mCurrentDialog = IndeterminateProgressDialog.newInstance(R.string.wait_a_moment, false);
+            mCurrentDialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);
+            findViewById(R.id.ok).setEnabled(false);
+        }
+        
+        
+        /**
+         * Performs the movement
+         * 
+         * @return     'False' when the movement of any file fails.
+         */
+        @Override
+        protected Boolean doInBackground(Void... params) {
+            while (!mLocalPaths.isEmpty()) {
+                String currentPath = mLocalPaths.get(0);
+                File currentFile = new File(currentPath);
+                String expectedPath = FileStorageUtils.getSavePath(mAccount.name) + mRemotePaths.get(0);
+                File expectedFile = new File(expectedPath);
+
+                if (expectedFile.equals(currentFile) || currentFile.renameTo(expectedFile)) {
+                    // SUCCESS
+                    OCFile file = mStorageManager.getFileByPath(mRemotePaths.get(0));
+                    file.setStoragePath(expectedPath);
+                    mStorageManager.saveFile(file);
+                    mRemotePaths.remove(0);
+                    mLocalPaths.remove(0);
+                        
+                } else {
+                    // FAIL
+                    return false;   
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Updates the activity UI after the movement of local files is tried.
+         * 
+         * If the movement was successful for all the files, finishes the activity immediately.
+         * 
+         * In other case, the list of remaining files is still available to retry the movement.
+         * 
+         * @result      'True' when the movement was successful.
+         */
+        @Override
+        protected void onPostExecute(Boolean result) {
+            mAdapter.notifyDataSetChanged();
+            mCurrentDialog.dismiss();
+            mCurrentDialog = null;
+            findViewById(R.id.ok).setEnabled(true);
+            
+            if (result) {
+                // nothing else to do in this activity
+                Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this, getString(R.string.foreign_files_success), Toast.LENGTH_LONG);
+                t.show();
+                finish();
+                
+            } else {
+                Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this, getString(R.string.foreign_files_fail), Toast.LENGTH_LONG);
+                t.show();
+            }
+        }
+    }    
+
+}