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

Commit 970bf275 authored by Tomasz Mikolajewski's avatar Tomasz Mikolajewski Committed by Android (Google) Code Review
Browse files

Merge "Simplify CopyService in DocumentsUI."

parents e16c2fb9 29d1ddd4
Loading
Loading
Loading
Loading
+62 −76
Original line number Original line Diff line number Diff line
@@ -170,8 +170,27 @@ public class CopyService extends IntentService {


            setupCopyJob(srcs, stack, transferMode);
            setupCopyJob(srcs, stack, transferMode);


            final String opDesc = transferMode == TRANSFER_MODE_COPY ? "copy" : "move";
            DocumentInfo srcInfo;
            DocumentInfo dstInfo;
            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
                copy(srcs.get(i), stack.peek(), transferMode);
                srcInfo = srcs.get(i);
                dstInfo = stack.peek();

                // Guard unsupported recursive operation.
                if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) {
                    if (DEBUG) Log.d(TAG,
                            "Skipping recursive " + opDesc + " of directory " + dstInfo.derivedUri);
                    mFailedFiles.add(srcInfo);
                    continue;
                }

                if (DEBUG) Log.d(TAG,
                        "Performing " + opDesc + " of " + srcInfo.displayName
                        + " (" + srcInfo.derivedUri + ")" + " to " + dstInfo.displayName
                        + " (" + dstInfo.derivedUri + ")");

                copy(srcInfo, dstInfo, 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.
@@ -447,22 +466,6 @@ public class CopyService extends IntentService {
     */
     */
    private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
    private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
            throws RemoteException {
            throws RemoteException {

        String opDesc = mode == TRANSFER_MODE_COPY ? "copy" : "move";

        // Guard unsupported recursive operation.
        if (dstDirInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstDirInfo)) {
            if (DEBUG) Log.d(TAG,
                    "Skipping recursive " + opDesc + " of directory " + dstDirInfo.derivedUri);
            mFailedFiles.add(srcInfo);
            return;
        }

        if (DEBUG) Log.d(TAG,
                "Performing " + opDesc + " of " + srcInfo.displayName
                + " (" + srcInfo.derivedUri + ")" + " to " + dstDirInfo.displayName
                + " (" + dstDirInfo.derivedUri + ")");

        // When copying within the same provider, try to use optimized copying and moving.
        // When copying within the same provider, try to use optimized copying and moving.
        // If not supported, then fallback to byte-by-byte copy/move.
        // If not supported, then fallback to byte-by-byte copy/move.
        if (srcInfo.authority.equals(dstDirInfo.authority)) {
        if (srcInfo.authority.equals(dstDirInfo.authority)) {
@@ -490,6 +493,8 @@ public class CopyService extends IntentService {
            }
            }
        }
        }


        // Create the target document (either a file or a directory), then copy recursively the
        // contents (bytes or children).
        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) {
@@ -498,10 +503,30 @@ public class CopyService extends IntentService {
            return;
            return;
        }
        }


        if (srcInfo.isDirectory()) {
        DocumentInfo dstInfo = null;
            copyDirectoryHelper(srcInfo.derivedUri, dstUri, mode);
        try {
            final DocumentInfo dstDocInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
        } catch (FileNotFoundException e) {
            mFailedFiles.add(srcInfo);
            return;
        }

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

        if (mode == TRANSFER_MODE_MOVE) {
            try {
                DocumentsContract.deleteDocument(mSrcClient, srcInfo.derivedUri);
            } 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: " + srcInfo.derivedUri, e);
                throw e;
            }
        }
        }
    }
    }


@@ -520,48 +545,29 @@ public class CopyService extends IntentService {
     * Handles recursion into a directory and copying its contents. Note that in linux terms, this
     * Handles recursion into a directory and copying its contents. Note that in linux terms, this
     * does the equivalent of "cp src/* dst", not "cp -r src dst".
     * does the equivalent of "cp src/* dst", not "cp -r src dst".
     *
     *
     * @param srcDirUri URI of the directory to copy from. The routine will copy the directory's
     * @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's
     *            contents, not the directory itself.
     *            contents, not the directory itself.
     * @param dstDirUri URI of the directory to copy to. Must be created beforehand.
     * @param dstDirInfo Info of the directory to copy to. Must be created beforehand.
     * @throws RemoteException
     * @throws RemoteException
     */
     */
    private void copyDirectoryHelper(Uri srcDirUri, Uri dstDirUri, int mode)
    private void copyDirectoryHelper(DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode)
            throws RemoteException {
            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,
                Document.COLUMN_DOCUMENT_ID,
                Document.COLUMN_DOCUMENT_ID,
                Document.COLUMN_MIME_TYPE,
                Document.COLUMN_MIME_TYPE,
                Document.COLUMN_SIZE
                Document.COLUMN_SIZE,
                Document.COLUMN_FLAGS
        };
        };
        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirUri.getAuthority(),
                DocumentsContract.getDocumentId(srcDirUri));
        Cursor cursor = null;
        Cursor cursor = null;
        try {
        try {
            // Iterate over srcs in the directory; copy to the destination directory.
            // Iterate over srcs in the directory; copy to the destination directory.
            cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
            DocumentInfo srcInfo;
            cursor = mSrcClient.query(srcDirInfo.derivedUri, queryColumns, null, null, null);
            while (cursor.moveToNext()) {
            while (cursor.moveToNext()) {
                final String childMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority);
                final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirUri,
                copy(srcInfo, dstDirInfo, mode);
                        childMimeType, getCursorString(cursor, Document.COLUMN_DISPLAY_NAME));
                final Uri childUri = DocumentsContract.buildDocumentUri(srcDirUri.getAuthority(),
                        getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
                if (Document.MIME_TYPE_DIR.equals(childMimeType)) {
                    copyDirectoryHelper(childUri, dstUri, mode);
                } else {
                    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 {
            IoUtils.closeQuietly(cursor);
            IoUtils.closeQuietly(cursor);
@@ -571,11 +577,11 @@ public class CopyService extends IntentService {
    /**
    /**
     * Handles copying a single file.
     * Handles copying a single file.
     *
     *
     * @param srcUri URI of the file to copy from.
     * @param srcUriInfo Info of the file to copy from.
     * @param dstUri URI of the *file* to copy to. Must be created beforehand.
     * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
     * @throws RemoteException
     * @throws RemoteException
     */
     */
    private void copyFileHelper(Uri srcUri, Uri dstUri, int mode)
    private void copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, int mode)
            throws RemoteException {
            throws RemoteException {
        // Copy an individual file.
        // Copy an individual file.
        CancellationSignal canceller = new CancellationSignal();
        CancellationSignal canceller = new CancellationSignal();
@@ -586,8 +592,8 @@ public class CopyService extends IntentService {


        IOException copyError = null;
        IOException copyError = null;
        try {
        try {
            srcFile = mSrcClient.openFile(srcUri, "r", canceller);
            srcFile = mSrcClient.openFile(srcInfo.derivedUri, "r", canceller);
            dstFile = mDstClient.openFile(dstUri, "w", canceller);
            dstFile = mDstClient.openFile(dstInfo.derivedUri, "w", canceller);
            src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
            src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
            dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
            dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);


@@ -601,18 +607,7 @@ public class CopyService extends IntentService {
            srcFile.checkError();
            srcFile.checkError();
        } catch (IOException e) {
        } catch (IOException e) {
            copyError = e;
            copyError = e;

            mFailedFiles.add(srcInfo);
            try {
                DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
                mFailedFiles.add(info);
            } catch (FileNotFoundException ignore) {
                // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
                // file.
                DocumentInfo info = new DocumentInfo();
                info.derivedUri = srcUri;
                info.displayName = "Unknown [" + srcUri + "]";
                mFailedFiles.add(info);
            }


            if (dstFile != null) {
            if (dstFile != null) {
                try {
                try {
@@ -627,26 +622,17 @@ public class CopyService extends IntentService {
            IoUtils.closeQuietly(dst);
            IoUtils.closeQuietly(dst);
        }
        }



        if (copyError != null || mIsCancelled) {
        if (copyError != null || mIsCancelled) {
            // Clean up half-copied files.
            // Clean up half-copied files.
            canceller.cancel();
            canceller.cancel();
            try {
            try {
                DocumentsContract.deleteDocument(mDstClient, dstUri);
                DocumentsContract.deleteDocument(mDstClient, dstInfo.derivedUri);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Log.w(TAG, "Failed to clean up after copy error: " + dstUri, e);
                Log.w(TAG, "Failed to clean up after copy error: " + dstInfo.derivedUri, 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;
            }
        }
        }
    }
    }