summaryrefslogtreecommitdiffstats
path: root/packages/DocumentsUI/src
diff options
context:
space:
mode:
authorBen Kwa <kenobi@google.com>2015-04-07 15:43:39 -0700
committerBen Kwa <kenobi@google.com>2015-04-08 11:55:18 -0700
commitef3f2620b3a755856d70345fc7a90df896985c26 (patch)
tree683c8064ff06790a4704b03fc2edc804d4d159f3 /packages/DocumentsUI/src
parentd99109fca847895233b0bdfafa131ebca8dfe3d5 (diff)
downloadframeworks_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.java57
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java50
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) {