Эх сурвалжийг харах

Grant execution of temporary copy of content URIs in configuration changes (such as rotation)

David A. Velasco 9 жил өмнө
parent
commit
0f65e3a667

+ 80 - 8
src/com/owncloud/android/ui/activity/Uploader.java

@@ -74,7 +74,7 @@ import com.owncloud.android.syncadapter.FileSyncAdapter;
 import com.owncloud.android.ui.adapter.UploaderAdapter;
 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 import com.owncloud.android.ui.dialog.LoadingDialog;
-import com.owncloud.android.utils.CopyTmpFileAsyncTask;
+import com.owncloud.android.ui.asynctasks.CopyAndUploadContentUrisTask;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.UriUtils;
@@ -92,10 +92,12 @@ import java.util.Vector;
  */
 public class Uploader extends FileActivity
         implements OnItemClickListener, android.view.View.OnClickListener,
-    CopyTmpFileAsyncTask.OnCopyTmpFilesTaskListener {
+    CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener {
 
     private static final String TAG = Uploader.class.getSimpleName();
 
+    private static final String FTAG_TASK_RETAINER_FRAGMENT = "TASK_RETAINER_FRAGMENT";
+
     private AccountManager mAccountManager;
     private Stack<String> mParents;
     private ArrayList<Parcelable> mStreamsToUpload;
@@ -149,6 +151,15 @@ public class Uploader extends FileActivity
         syncIntentFilter.addAction(RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED);
         mSyncBroadcastReceiver = new SyncBroadcastReceiver();
         registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+
+        // Init Fragment without UI to retain AsyncTask across configuration changes
+        FragmentManager fm = getSupportFragmentManager();
+        TaskRetainerFragment taskRetainerFragment =
+            (TaskRetainerFragment) fm.findFragmentByTag(FTAG_TASK_RETAINER_FRAGMENT);
+        if (taskRetainerFragment == null) {
+            taskRetainerFragment = new TaskRetainerFragment();
+            fm.beginTransaction().add(taskRetainerFragment, FTAG_TASK_RETAINER_FRAGMENT).commit();
+        }   // else, Fragment already created and retained across configuration change
     }
 
     @Override
@@ -355,7 +366,7 @@ public class Uploader extends FileActivity
         Vector<OCFile> tmpfiles = getStorageManager().getFolderContent(mFile /*, false*/);
         if (tmpfiles.size() <= 0) return;
         // filter on dirtype
-        Vector<OCFile> files = new Vector<OCFile>();
+        Vector<OCFile> files = new Vector<>();
         for (OCFile f : tmpfiles)
                 files.add(f);
         if (files.size() < position) {
@@ -443,9 +454,9 @@ public class Uploader extends FileActivity
         if (mFile != null) {
             // TODO Enable when "On Device" is recovered ?
             Vector<OCFile> files = getStorageManager().getFolderContent(mFile/*, false*/);
-            List<HashMap<String, OCFile>> data = new LinkedList<HashMap<String,OCFile>>();
+            List<HashMap<String, OCFile>> data = new LinkedList<>();
             for (OCFile f : files) {
-                HashMap<String, OCFile> h = new HashMap<String, OCFile>();
+                HashMap<String, OCFile> h = new HashMap<>();
                     h.put("dirname", f);
                     data.add(h);
             }
@@ -568,9 +579,13 @@ public class Uploader extends FileActivity
     private void copyThenUpload(Uri[] sourceUris, String[] remotePaths) {
         showWaitingCopyDialog();
 
-        CopyTmpFileAsyncTask copyTask = new CopyTmpFileAsyncTask(this, this);
+        CopyAndUploadContentUrisTask copyTask = new CopyAndUploadContentUrisTask(this, this);
+        FragmentManager fm = getSupportFragmentManager();
+        TaskRetainerFragment taskRetainerFragment =
+            (TaskRetainerFragment) fm.findFragmentByTag(FTAG_TASK_RETAINER_FRAGMENT);
+        taskRetainerFragment.setTask(copyTask);
         copyTask.execute(
-            CopyTmpFileAsyncTask.makeParamsToExecute(
+            CopyAndUploadContentUrisTask.makeParamsToExecute(
                 getAccount(),
                 sourceUris,
                 remotePaths,
@@ -806,7 +821,7 @@ public class Uploader extends FileActivity
     }
 
     /**
-     * Process the result of CopyTmpFileAsyncTask
+     * Process the result of CopyAndUploadContentUrisTask
      */
     @Override
     public void onTmpFilesCopied(ResultCode result) {
@@ -843,4 +858,61 @@ public class Uploader extends FileActivity
             loading.dismiss();
         }
     }
+
+
+    /**
+     * Fragment retaining a background task across configuration changes.
+     */
+    public static class TaskRetainerFragment extends Fragment {
+
+        private CopyAndUploadContentUrisTask mTask;
+
+        /**
+         * Updates the listener of the retained task whenever the parent
+         * Activity is attached.
+         *
+         * Since its done in main thread, and provided the AsyncTask only accesses
+         * the listener in the main thread (should so), no sync problem should occur.
+         */
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            if (mTask != null) {
+                mTask.setListener((CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener) context);
+            }
+        }
+
+        /**
+         * Only called once, since the instance is retained across configuration changes
+         */
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setRetainInstance(true);    // the key point
+        }
+
+        /**
+         * Set the callback to null so we don't accidentally leak the
+         * Activity instance.
+         */
+        @Override
+        public void onDetach() {
+            super.onDetach();
+        }
+
+        /**
+         * Sets the task to retain accross configuration changes
+         *
+         * @param task  Task to retain
+         */
+        private void setTask(CopyAndUploadContentUrisTask task) {
+            if (mTask != null) {
+                mTask.setListener(null);
+            }
+            mTask = task;
+            if (mTask != null && getContext() != null) {
+                task.setListener((CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener) getContext());
+            }
+        }
+    }
 }

+ 17 - 8
src/com/owncloud/android/utils/CopyTmpFileAsyncTask.java → src/com/owncloud/android/ui/asynctasks/CopyAndUploadContentUrisTask.java

@@ -17,7 +17,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
-package com.owncloud.android.utils;
+package com.owncloud.android.ui.asynctasks;
 
 import android.accounts.Account;
 import android.content.ContentResolver;
@@ -31,6 +31,7 @@ import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.UploadFileOperation;
+import com.owncloud.android.utils.FileStorageUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -41,9 +42,9 @@ import java.lang.ref.WeakReference;
 /**
  * AsyncTask to copy a file from a uri in a temporal file
  */
-public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, ResultCode> {
+public class CopyAndUploadContentUrisTask extends AsyncTask<Object, Void, ResultCode> {
 
-    private final String TAG = CopyTmpFileAsyncTask.class.getSimpleName();
+    private final String TAG = CopyAndUploadContentUrisTask.class.getSimpleName();
 
     /**
      * Helper method building a correct array of parameters to be passed to {@link #execute(Object[])} )}
@@ -87,13 +88,12 @@ public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, ResultCode> {
         };
     }
 
-
     /**
      * Listener in main thread to be notified when the task ends. Held in a WeakReference assuming that its
      * lifespan is associated with an Activity context, that could be finished by the user before the AsyncTask
      * ends.
      */
-    private final WeakReference<OnCopyTmpFilesTaskListener> mListener;
+    private WeakReference<OnCopyTmpFilesTaskListener> mListener;
 
     /**
      * Reference to application context, used to access app resources. Holding it should not be a problem,
@@ -103,7 +103,7 @@ public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, ResultCode> {
     private final Context mAppContext;
 
 
-    public CopyTmpFileAsyncTask(
+    public CopyAndUploadContentUrisTask(
         OnCopyTmpFilesTaskListener listener,
         Context context
     ) {
@@ -225,7 +225,7 @@ public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, ResultCode> {
                                                 // into the OC folder so that appears as downloaded
             mimeType,
             false,      // do not create parent folder if not existent
-            UploadFileOperation.CREATED_BY_USER // TODO , different category?
+            UploadFileOperation.CREATED_BY_USER
         );
     }
 
@@ -262,7 +262,16 @@ public class CopyTmpFileAsyncTask  extends AsyncTask<Object, Void, ResultCode> {
         }
     }
 
-    /*
+    /**
+     * Sets the object waiting for progress report via callbacks.
+     *
+     * @param listener      New object to report progress via callbacks
+     */
+    public void setListener(OnCopyTmpFilesTaskListener listener) {
+        mListener = new WeakReference<>(listener);
+    }
+
+    /**
      * Interface to retrieve data from recognition task
      */
     public interface OnCopyTmpFilesTaskListener {