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

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

Merge "Prototype the destination picking."

parents 6d5c0ba9 ef3f2620
Loading
Loading
Loading
Loading
+35 −22
Original line number Diff line number Diff line
@@ -24,7 +24,11 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.text.format.DateUtils;
import android.util.Log;

@@ -82,18 +86,15 @@ public class CopyService extends IntentService {
        }

        ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
        // Use the app local files dir as a copy destination for now. This resolves to
        // /data/data/com.android.documentsui/files.
        // TODO: Add actual destination picking.
        File destinationDir = getFilesDir();
        Uri destinationUri = intent.getData();

        setupCopyJob(srcs, destinationDir);
        setupCopyJob(srcs, destinationUri);

        ArrayList<String> failedFilenames = new ArrayList<String>();
        for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
            DocumentInfo src = srcs.get(i);
            try {
                copyFile(src, destinationDir);
                copyFile(src, destinationUri);
            } catch (IOException e) {
                Log.e(TAG, "Failed to copy " + src.displayName, e);
                failedFilenames.add(src.displayName);
@@ -121,8 +122,9 @@ public class CopyService extends IntentService {
     * files.
     *
     * @param srcs A list of src files to copy.
     * @param destinationUri The URI of the destination directory.
     */
    private void setupCopyJob(ArrayList<DocumentInfo> srcs, File destinationDir) {
    private void setupCopyJob(ArrayList<DocumentInfo> srcs, Uri destinationUri) {
        // Create an ID for this copy job. Use the timestamp.
        mJobId = String.valueOf(SystemClock.elapsedRealtime());
        // Reset the cancellation flag.
@@ -238,42 +240,53 @@ public class CopyService extends IntentService {
     * Copies a file to a given location.
     *
     * @param srcInfo The source file.
     * @param destination The directory to copy into.
     * @param destinationUri The URI of the destination directory.
     * @throws IOException
     */
    private void copyFile(DocumentInfo srcInfo, File destinationDir)
            throws IOException {
    private void copyFile(DocumentInfo srcInfo, Uri destinationUri) throws IOException {
        final Context context = getApplicationContext();
        final ContentResolver resolver = context.getContentResolver();
        final File destinationFile = new File(destinationDir, srcInfo.displayName);
        final Uri destinationUri = Uri.fromFile(destinationFile);

        InputStream source = null;
        OutputStream destination = null;
        final Uri writableDstUri = DocumentsContract.buildDocumentUriUsingTree(destinationUri,
                DocumentsContract.getTreeDocumentId(destinationUri));
        final Uri dstFileUri = DocumentsContract.createDocument(resolver, writableDstUri,
                srcInfo.mimeType, srcInfo.displayName);

        CancellationSignal canceller = new CancellationSignal();
        ParcelFileDescriptor srcFile = null;
        ParcelFileDescriptor dstFile = null;
        InputStream src = null;
        OutputStream dst = null;

        boolean errorOccurred = false;
        try {
            source = resolver.openInputStream(srcInfo.derivedUri);
            destination = resolver.openOutputStream(destinationUri);
            srcFile = resolver.openFileDescriptor(srcInfo.derivedUri, "r", canceller);
            dstFile = resolver.openFileDescriptor(dstFileUri, "w", canceller);
            src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
            dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);

            byte[] buffer = new byte[8192];
            int len;
            while (!mIsCancelled && ((len = source.read(buffer)) != -1)) {
                destination.write(buffer, 0, len);
            while (!mIsCancelled && ((len = src.read(buffer)) != -1)) {
                dst.write(buffer, 0, len);
                makeProgress(len);
            }
            srcFile.checkError();
            dstFile.checkError();
        } catch (IOException e) {
            errorOccurred = true;
            Log.e(TAG, "Error while copying " + srcInfo.displayName, e);
        } finally {
            IoUtils.closeQuietly(source);
            IoUtils.closeQuietly(destination);
            // This also ensures the file descriptors are closed.
            IoUtils.closeQuietly(src);
            IoUtils.closeQuietly(dst);
        }

        if (errorOccurred || mIsCancelled) {
            // Clean up half-copied files.
            if (!destinationFile.delete()) {
                Log.w(TAG, "Failed to clean up partially copied file " + srcInfo.displayName);
            canceller.cancel();
            if (!DocumentsContract.deleteDocument(resolver, dstFileUri)) {
                Log.w(TAG, "Failed to clean up: " + srcInfo.displayName);
            }
        }
    }
+40 −10
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -99,6 +100,8 @@ public class DirectoryFragment extends Fragment {

    private AbsListView mCurrentView;

    private List<DocumentInfo> mSelectedDocumentsForCopy;

    public static final int TYPE_NORMAL = 1;
    public static final int TYPE_SEARCH = 2;
    public static final int TYPE_RECENT_OPEN = 3;
@@ -108,6 +111,8 @@ public class DirectoryFragment extends Fragment {
    public static final int ANIM_DOWN = 3;
    public static final int ANIM_UP = 4;

    public static final int REQUEST_COPY_DESTINATION = 1;

    private int mType = TYPE_NORMAL;
    private String mStateKey;

@@ -336,6 +341,36 @@ public class DirectoryFragment extends Fragment {
        updateDisplayState();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        final Context context = getActivity();
        final Resources res = context.getResources();

        // There's only one request code right now. Replace this with a switch statement or
        // something more scalable when more codes are added.
        if (requestCode != REQUEST_COPY_DESTINATION) {
            return;
        }
        if (resultCode == Activity.RESULT_CANCELED || data == null) {
            // User pressed the back button or otherwise cancelled the destination pick. Don't
            // proceed with the copy.
            return;
        }

        Uri destination = data.getData();

        List<DocumentInfo> docs = mSelectedDocumentsForCopy;
        Intent copyIntent = new Intent(context, CopyService.class);
        copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST,
                new ArrayList<DocumentInfo>(docs));
        copyIntent.setData(destination);

        Toast.makeText(context,
                res.getQuantityString(R.plurals.copy_begin, docs.size(), docs.size()),
                Toast.LENGTH_SHORT).show();
        context.startService(copyIntent);
    }

    @Override
    public void onStop() {
        super.onStop();
@@ -634,17 +669,12 @@ public class DirectoryFragment extends Fragment {
    }

    private void onCopyDocuments(List<DocumentInfo> docs) {
        final Context context = getActivity();
        final Resources res = context.getResources();
        mSelectedDocumentsForCopy = docs;

        Intent copyIntent = new Intent(context, CopyService.class);
        copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST,
                new ArrayList<DocumentInfo>(docs));

        Toast.makeText(context,
                res.getQuantityString(R.plurals.copy_begin, docs.size(), docs.size()),
                Toast.LENGTH_SHORT).show();
        context.startService(copyIntent);
        // Pop up a dialog to pick a destination.  This is inadequate but works for now.
        // TODO: Implement a picker that is to spec.
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
    }

    private static State getDisplayState(Fragment fragment) {