Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed6fcb59 authored by Ben Kwa's avatar Ben Kwa Committed by Android (Google) Code Review
Browse files

Merge "Add a move feature to DocumentsUI."

parents e83ab655 0b4a3c47
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -37,4 +37,8 @@
        android:id="@+id/menu_copy"
        android:id="@+id/menu_copy"
        android:title="@string/menu_copy"
        android:title="@string/menu_copy"
        android:showAsAction="never" />
        android:showAsAction="never" />
    <item
        android:id="@+id/menu_move"
        android:title="@string/menu_move"
        android:showAsAction="never" />
</menu>
</menu>
+6 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,8 @@
    <string name="menu_select_all">Select All</string>
    <string name="menu_select_all">Select All</string>
    <!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
    <!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
    <string name="menu_copy">Copy to\u2026</string>
    <string name="menu_copy">Copy to\u2026</string>
    <!-- Menu item title that moves the selected documents [CHAR LIMIT=24] -->
    <string name="menu_move">Move to\u2026</string>


    <!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
    <!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
    <string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
    <string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
@@ -124,6 +126,10 @@
        <item quantity="one">Copying <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
        <item quantity="one">Copying <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
        <item quantity="other">Copying <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
        <item quantity="other">Copying <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
    </plurals>
    </plurals>
    <plurals name="move_begin">
        <item quantity="one">Moving <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
        <item quantity="other">Moving <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
    </plurals>
    <!-- Text shown on the copy notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
    <!-- Text shown on the copy notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
    <string name="copy_preparing">Preparing for copy\u2026</string>
    <string name="copy_preparing">Preparing for copy\u2026</string>
    <!-- Title of the copy error notification [CHAR LIMIT=48] -->
    <!-- Title of the copy error notification [CHAR LIMIT=48] -->
+10 −8
Original line number Original line Diff line number Diff line
@@ -269,14 +269,16 @@ abstract class BaseActivity extends Activity {
        /** Derived after loader */
        /** Derived after loader */
        public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
        public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;


        public boolean allowMultiple = false;
        public boolean allowMultiple;
        public boolean showSize = false;
        public boolean showSize;
        public boolean localOnly = false;
        public boolean localOnly ;
        public boolean forceAdvanced = false;
        public boolean forceAdvanced ;
        public boolean showAdvanced = false;
        public boolean showAdvanced ;
        public boolean stackTouched = false;
        public boolean stackTouched ;
        public boolean restored = false;
        public boolean restored ;
        public boolean directoryCopy = false;
        public boolean directoryCopy ;
        /** Transfer mode for file copy/move operations. */
        public int transferMode;


        /** Current user navigation stack; empty implies recents. */
        /** Current user navigation stack; empty implies recents. */
        public DocumentStack stack = new DocumentStack();
        public DocumentStack stack = new DocumentStack();
+45 −14
Original line number Original line Diff line number Diff line
@@ -61,6 +61,11 @@ public class CopyService extends IntentService {
    public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
    public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
    public static final String EXTRA_STACK = "com.android.documentsui.STACK";
    public static final String EXTRA_STACK = "com.android.documentsui.STACK";
    public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
    public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
    public static final String EXTRA_TRANSFER_MODE = "com.android.documentsui.TRANSFER_MODE";

    public static final int TRANSFER_MODE_NONE = 0;
    public static final int TRANSFER_MODE_COPY = 1;
    public static final int TRANSFER_MODE_MOVE = 2;


    // TODO: Move it to a shared file when more operations are implemented.
    // TODO: Move it to a shared file when more operations are implemented.
    public static final int FAILURE_COPY = 1;
    public static final int FAILURE_COPY = 1;
@@ -101,15 +106,19 @@ public class CopyService extends IntentService {
     * @param srcDocs A list of src files to copy.
     * @param srcDocs A list of src files to copy.
     * @param dstStack The copy destination stack.
     * @param dstStack The copy destination stack.
     */
     */
    public static void start(Context context, List<DocumentInfo> srcDocs, DocumentStack dstStack) {
    public static void start(Context context, List<DocumentInfo> srcDocs, DocumentStack dstStack,
            int mode) {
        final Resources res = context.getResources();
        final Resources res = context.getResources();
        final Intent copyIntent = new Intent(context, CopyService.class);
        final Intent copyIntent = new Intent(context, CopyService.class);
        copyIntent.putParcelableArrayListExtra(
        copyIntent.putParcelableArrayListExtra(
                EXTRA_SRC_LIST, new ArrayList<DocumentInfo>(srcDocs));
                EXTRA_SRC_LIST, new ArrayList<DocumentInfo>(srcDocs));
        copyIntent.putExtra(EXTRA_STACK, (Parcelable) dstStack);
        copyIntent.putExtra(EXTRA_STACK, (Parcelable) dstStack);
        copyIntent.putExtra(EXTRA_TRANSFER_MODE, mode);


        int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin
                : R.plurals.move_begin;
        Toast.makeText(context,
        Toast.makeText(context,
                res.getQuantityString(R.plurals.copy_begin, srcDocs.size(), srcDocs.size()),
                res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()),
                Toast.LENGTH_SHORT).show();
                Toast.LENGTH_SHORT).show();
        context.startService(copyIntent);
        context.startService(copyIntent);
    }
    }
@@ -131,6 +140,8 @@ public class CopyService extends IntentService {


        final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
        final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
        final DocumentStack stack = intent.getParcelableExtra(EXTRA_STACK);
        final DocumentStack stack = intent.getParcelableExtra(EXTRA_STACK);
        // Copy by default.
        final int transferMode = intent.getIntExtra(EXTRA_TRANSFER_MODE, TRANSFER_MODE_COPY);


        try {
        try {
            // Acquire content providers.
            // Acquire content providers.
@@ -142,7 +153,7 @@ public class CopyService extends IntentService {
            setupCopyJob(srcs, stack);
            setupCopyJob(srcs, stack);


            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
                copy(srcs.get(i), stack.peek());
                copy(srcs.get(i), stack.peek(), transferMode);
            }
            }
        } catch (Exception e) {
        } catch (Exception e) {
            // Catch-all to prevent any copy errors from wedging the app.
            // Catch-all to prevent any copy errors from wedging the app.
@@ -173,8 +184,6 @@ public class CopyService extends IntentService {
                        .setAutoCancel(true);
                        .setAutoCancel(true);
                mNotificationManager.notify(mJobId, 0, errorBuilder.build());
                mNotificationManager.notify(mJobId, 0, errorBuilder.build());
            }
            }

            // TODO: Display a toast if the copy was cancelled.
        }
        }
    }
    }


@@ -377,7 +386,8 @@ public class CopyService extends IntentService {
     * @param dstDirInfo The destination directory.
     * @param dstDirInfo The destination directory.
     * @throws RemoteException
     * @throws RemoteException
     */
     */
    private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo) throws RemoteException {
    private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
            throws RemoteException {
        final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
        final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
                srcInfo.mimeType, srcInfo.displayName);
                srcInfo.mimeType, srcInfo.displayName);
        if (dstUri == null) {
        if (dstUri == null) {
@@ -388,9 +398,9 @@ public class CopyService extends IntentService {
        }
        }


        if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
        if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
            copyDirectoryHelper(srcInfo.derivedUri, dstUri);
            copyDirectoryHelper(srcInfo.derivedUri, dstUri, mode);
        } else {
        } else {
            copyFileHelper(srcInfo.derivedUri, dstUri);
            copyFileHelper(srcInfo.derivedUri, dstUri, mode);
        }
        }
    }
    }


@@ -403,7 +413,8 @@ public class CopyService extends IntentService {
     * @param dstDirUri URI of the directory to copy to. Must be created beforehand.
     * @param dstDirUri URI of the directory to copy to. Must be created beforehand.
     * @throws RemoteException
     * @throws RemoteException
     */
     */
    private void copyDirectoryHelper(Uri srcDirUri, Uri dstDirUri) throws RemoteException {
    private void copyDirectoryHelper(Uri srcDirUri, Uri dstDirUri, int mode)
            throws RemoteException {
        // Recurse into directories. Copy children into the new subdirectory.
        // Recurse into directories. Copy children into the new subdirectory.
        final String queryColumns[] = new String[] {
        final String queryColumns[] = new String[] {
                Document.COLUMN_DISPLAY_NAME,
                Document.COLUMN_DISPLAY_NAME,
@@ -424,9 +435,20 @@ public class CopyService extends IntentService {
                final Uri childUri = DocumentsContract.buildDocumentUri(srcDirUri.getAuthority(),
                final Uri childUri = DocumentsContract.buildDocumentUri(srcDirUri.getAuthority(),
                        getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
                        getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
                if (Document.MIME_TYPE_DIR.equals(childMimeType)) {
                if (Document.MIME_TYPE_DIR.equals(childMimeType)) {
                    copyDirectoryHelper(childUri, dstUri);
                    copyDirectoryHelper(childUri, dstUri, mode);
                } else {
                } else {
                    copyFileHelper(childUri, dstUri);
                    copyFileHelper(childUri, dstUri, mode);
                }
            }
            if (mode == TRANSFER_MODE_MOVE) {
                try {
                    DocumentsContract.deleteDocument(mSrcClient, srcDirUri);
                } catch (RemoteException e) {
                    // RemoteExceptions usually signal that the connection is dead, so there's no
                    // point attempting to continue. Propagate the exception up so the copy job is
                    // cancelled.
                    Log.w(TAG, "Failed to clean up after move: " + srcDirUri, e);
                    throw e;
                }
                }
            }
            }
        } finally {
        } finally {
@@ -441,7 +463,8 @@ public class CopyService extends IntentService {
     * @param dstUri URI of the *file* to copy to. Must be created beforehand.
     * @param dstUri URI of the *file* to copy to. Must be created beforehand.
     * @throws RemoteException
     * @throws RemoteException
     */
     */
    private void copyFileHelper(Uri srcUri, Uri dstUri) throws RemoteException {
    private void copyFileHelper(Uri srcUri, Uri dstUri, int mode)
            throws RemoteException {
        // Copy an individual file.
        // Copy an individual file.
        CancellationSignal canceller = new CancellationSignal();
        CancellationSignal canceller = new CancellationSignal();
        ParcelFileDescriptor srcFile = null;
        ParcelFileDescriptor srcFile = null;
@@ -494,11 +517,19 @@ public class CopyService extends IntentService {
            try {
            try {
                DocumentsContract.deleteDocument(mDstClient, dstUri);
                DocumentsContract.deleteDocument(mDstClient, dstUri);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Log.w(TAG, "Failed to clean up: " + srcUri, e);
                Log.w(TAG, "Failed to clean up after copy error: " + dstUri, e);
                // RemoteExceptions usually signal that the connection is dead, so there's no point
                // RemoteExceptions usually signal that the connection is dead, so there's no point
                // attempting to continue. Propagate the exception up so the copy job is cancelled.
                // attempting to continue. Propagate the exception up so the copy job is cancelled.
                throw e;
                throw e;
            }
            }
        } else if (mode == TRANSFER_MODE_MOVE) {
            // Clean up src files after a successful move.
            try {
                DocumentsContract.deleteDocument(mSrcClient, srcUri);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed to clean up after move: " + srcUri, e);
                throw e;
            }
        }
        }
    }
    }
}
}
+13 −5
Original line number Original line Diff line number Diff line
@@ -369,7 +369,8 @@ public class DirectoryFragment extends Fragment {
        }
        }


        CopyService.start(getActivity(), getDisplayState(this).selectedDocumentsForCopy,
        CopyService.start(getActivity(), getDisplayState(this).selectedDocumentsForCopy,
                (DocumentStack) data.getParcelableExtra(CopyService.EXTRA_STACK));
                (DocumentStack) data.getParcelableExtra(CopyService.EXTRA_STACK),
                data.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_NONE));
    }
    }


    @Override
    @Override
@@ -502,6 +503,7 @@ public class DirectoryFragment extends Fragment {
            final MenuItem share = menu.findItem(R.id.menu_share);
            final MenuItem share = menu.findItem(R.id.menu_share);
            final MenuItem delete = menu.findItem(R.id.menu_delete);
            final MenuItem delete = menu.findItem(R.id.menu_delete);
            final MenuItem copy = menu.findItem(R.id.menu_copy);
            final MenuItem copy = menu.findItem(R.id.menu_copy);
            final MenuItem move = menu.findItem(R.id.menu_move);


            final boolean manageOrBrowse = (state.action == ACTION_MANAGE
            final boolean manageOrBrowse = (state.action == ACTION_MANAGE
                    || state.action == ACTION_BROWSE || state.action == ACTION_BROWSE_ALL);
                    || state.action == ACTION_BROWSE || state.action == ACTION_BROWSE_ALL);
@@ -511,7 +513,7 @@ public class DirectoryFragment extends Fragment {
            delete.setVisible(manageOrBrowse);
            delete.setVisible(manageOrBrowse);
            // Disable copying from the Recents view.
            // Disable copying from the Recents view.
            copy.setVisible(manageOrBrowse && mType != TYPE_RECENT_OPEN);
            copy.setVisible(manageOrBrowse && mType != TYPE_RECENT_OPEN);

            move.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
            return true;
            return true;
        }
        }


@@ -536,7 +538,12 @@ public class DirectoryFragment extends Fragment {
                return true;
                return true;


            } else if (id == R.id.menu_copy) {
            } else if (id == R.id.menu_copy) {
                onCopyDocuments(docs);
                onTransferDocuments(docs, CopyService.TRANSFER_MODE_COPY);
                mode.finish();
                return true;

            } else if (id == R.id.menu_move) {
                onTransferDocuments(docs, CopyService.TRANSFER_MODE_MOVE);
                mode.finish();
                mode.finish();
                return true;
                return true;


@@ -665,7 +672,7 @@ public class DirectoryFragment extends Fragment {
        }
        }
    }
    }


    private void onCopyDocuments(List<DocumentInfo> docs) {
    private void onTransferDocuments(List<DocumentInfo> docs, int mode) {
        getDisplayState(this).selectedDocumentsForCopy = docs;
        getDisplayState(this).selectedDocumentsForCopy = docs;


        // Pop up a dialog to pick a destination.  This is inadequate but works for now.
        // Pop up a dialog to pick a destination.  This is inadequate but works for now.
@@ -683,6 +690,7 @@ public class DirectoryFragment extends Fragment {
            }
            }
        }
        }
        intent.putExtra(BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, directoryCopy);
        intent.putExtra(BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, directoryCopy);
        intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mode);
        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    }
    }


@@ -1241,7 +1249,7 @@ public class DirectoryFragment extends Fragment {
            tmpStack = curStack;
            tmpStack = curStack;
        }
        }


        CopyService.start(getActivity(), srcDocs, tmpStack);
        CopyService.start(getActivity(), srcDocs, tmpStack, CopyService.TRANSFER_MODE_COPY);
    }
    }


    private List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
    private List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
Loading