diff options
author | Ben Kwa <kenobi@google.com> | 2015-04-07 15:43:39 -0700 |
---|---|---|
committer | Ben Kwa <kenobi@google.com> | 2015-04-08 11:55:18 -0700 |
commit | ef3f2620b3a755856d70345fc7a90df896985c26 (patch) | |
tree | 683c8064ff06790a4704b03fc2edc804d4d159f3 /packages/DocumentsUI/src | |
parent | d99109fca847895233b0bdfafa131ebca8dfe3d5 (diff) | |
download | frameworks_base-ef3f2620b3a755856d70345fc7a90df896985c26.zip frameworks_base-ef3f2620b3a755856d70345fc7a90df896985c26.tar.gz frameworks_base-ef3f2620b3a755856d70345fc7a90df896985c26.tar.bz2 |
Prototype the destination picking.
- Add an intent to open a destination picker, and refactor
DocumentsActivity accordingly.
- Modify CopyService to take a destination for the copy, and to use URIs
and PFDs instead of Files and Streams, for better error handling &
cleanup.
Change-Id: I69dc43823a703674dc29d2215e2df23b33ad7882
Diffstat (limited to 'packages/DocumentsUI/src')
-rw-r--r-- | packages/DocumentsUI/src/com/android/documentsui/CopyService.java | 57 | ||||
-rw-r--r-- | packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java | 50 |
2 files changed, 75 insertions, 32 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index f7d8cc4..f135af49b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -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); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index d6d691f..83071bd 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -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; @@ -337,6 +342,36 @@ public class DirectoryFragment extends Fragment { } @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) { |