Separate paste code from DirectoryFragment.
Also untie DocumentClipper from activities. We'll have a single DocumentClipper across the app from now on. Bug: 28742120 Change-Id: Ib9e2537c3499ba2fa0a203ddad3ae71246d5b009 (cherry picked from commit 0cd92d35c533c16b301bd228cce8c68a289407a1)
This commit is contained in:
committed by
Garfield Tan
parent
438266a4f7
commit
6d0b46eb12
@@ -18,21 +18,21 @@ package com.android.documentsui;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.PersistableBundle;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.documentsui.model.DocumentInfo;
|
||||
import com.android.documentsui.model.DocumentStack;
|
||||
import com.android.documentsui.model.RootInfo;
|
||||
import com.android.documentsui.services.FileOperationService;
|
||||
import com.android.documentsui.services.FileOperationService.OpType;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import com.android.documentsui.services.FileOperations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -53,7 +53,7 @@ public final class DocumentClipper {
|
||||
private Context mContext;
|
||||
private ClipboardManager mClipboard;
|
||||
|
||||
public DocumentClipper(Context context) {
|
||||
DocumentClipper(Context context) {
|
||||
mContext = context;
|
||||
mClipboard = context.getSystemService(ClipboardManager.class);
|
||||
}
|
||||
@@ -114,7 +114,13 @@ public final class DocumentClipper {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ClipData.Item item = clipData.getItemAt(i);
|
||||
Uri itemUri = item.getUri();
|
||||
srcDocs.add(createDocument(itemUri));
|
||||
DocumentInfo docInfo = createDocument(itemUri);
|
||||
if (docInfo != null) {
|
||||
srcDocs.add(docInfo);
|
||||
} else {
|
||||
// This uri either doesn't exist, or is invalid.
|
||||
Log.w(TAG, "Can't create document info from uri: " + itemUri);
|
||||
}
|
||||
}
|
||||
|
||||
return srcDocs;
|
||||
@@ -196,23 +202,129 @@ public final class DocumentClipper {
|
||||
DocumentInfo doc = null;
|
||||
if (uri != null && DocumentsContract.isDocumentUri(mContext, uri)) {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
ContentProviderClient client = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, uri.getAuthority());
|
||||
cursor = client.query(uri, null, null, null, null);
|
||||
cursor.moveToPosition(0);
|
||||
doc = DocumentInfo.fromCursor(cursor, uri.getAuthority());
|
||||
doc = DocumentInfo.fromUri(resolver, uri);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
} finally {
|
||||
IoUtils.closeQuietly(cursor);
|
||||
ContentProviderClient.releaseQuietly(client);
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies documents from clipboard. It's the same as {@link #copyFromClipData} with clipData
|
||||
* returned from {@link ClipboardManager#getPrimaryClip()}.
|
||||
*
|
||||
* @param destination destination document.
|
||||
* @param docStack the document stack to the destination folder,
|
||||
* @param callback callback to notify when operation finishes.
|
||||
*/
|
||||
public void copyFromClipboard(DocumentInfo destination, DocumentStack docStack,
|
||||
FileOperations.Callback callback) {
|
||||
copyFromClipData(destination, docStack, mClipboard.getPrimaryClip(), callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies documents from given clip data.
|
||||
*
|
||||
* @param destination destination document
|
||||
* @param docStack the document stack to the destination folder
|
||||
* @param clipData the clipData to copy from, or null to copy from clipboard
|
||||
* @param callback callback to notify when operation finishes
|
||||
*/
|
||||
public void copyFromClipData(final DocumentInfo destination, DocumentStack docStack,
|
||||
@Nullable final ClipData clipData, final FileOperations.Callback callback) {
|
||||
if (clipData == null) {
|
||||
Log.i(TAG, "Received null clipData. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask<Void, Void, ClipDetails>() {
|
||||
|
||||
@Override
|
||||
protected ClipDetails doInBackground(Void... params) {
|
||||
return getClipDetails(clipData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ClipDetails clipDetails) {
|
||||
if (clipDetails == null) {
|
||||
Log.w(TAG, "Received null clipDetails. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<DocumentInfo> docs = clipDetails.docs;
|
||||
@OpType int type = clipDetails.opType;
|
||||
DocumentInfo srcParent = clipDetails.parent;
|
||||
moveDocuments(docs, destination, docStack, type, srcParent, callback);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves {@code docs} from {@code srcParent} to {@code destination}.
|
||||
* operationType can be copy or cut
|
||||
* srcParent Must be non-null for move operations.
|
||||
*/
|
||||
private void moveDocuments(
|
||||
List<DocumentInfo> docs,
|
||||
DocumentInfo destination,
|
||||
DocumentStack docStack,
|
||||
@OpType int operationType,
|
||||
DocumentInfo srcParent,
|
||||
FileOperations.Callback callback) {
|
||||
|
||||
RootInfo destRoot = docStack.root;
|
||||
if (!canCopy(docs, destRoot, destination)) {
|
||||
callback.onOperationResult(FileOperations.Callback.STATUS_REJECTED, operationType, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (docs.isEmpty()) {
|
||||
callback.onOperationResult(FileOperations.Callback.STATUS_ACCEPTED, operationType, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
DocumentStack dstStack = new DocumentStack();
|
||||
dstStack.push(destination);
|
||||
dstStack.addAll(docStack);
|
||||
switch (operationType) {
|
||||
case FileOperationService.OPERATION_MOVE:
|
||||
FileOperations.move(mContext, docs, srcParent, dstStack, callback);
|
||||
break;
|
||||
case FileOperationService.OPERATION_COPY:
|
||||
FileOperations.copy(mContext, docs, dstStack, callback);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported operation: " + operationType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the list of files can be copied to destination. Note that this
|
||||
* is a policy check only. Currently the method does not attempt to verify
|
||||
* available space or any other environmental aspects possibly resulting in
|
||||
* failure to copy.
|
||||
*
|
||||
* @return true if the list of files can be copied to destination.
|
||||
*/
|
||||
private boolean canCopy(List<DocumentInfo> files, RootInfo root, DocumentInfo dest) {
|
||||
if (dest == null || !dest.isDirectory() || !dest.isCreateSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can't copy folders to downloads, because we don't show folders there.
|
||||
if (root.isDownloads()) {
|
||||
for (DocumentInfo docs : files) {
|
||||
if (docs.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class ClipDetails {
|
||||
public final @OpType int opType;
|
||||
public final List<DocumentInfo> docs;
|
||||
|
||||
@@ -35,6 +35,8 @@ public class DocumentsApplication extends Application {
|
||||
|
||||
private ThumbnailCache mThumbnailCache;
|
||||
|
||||
private DocumentClipper mClipper;
|
||||
|
||||
public static RootsCache getRootsCache(Context context) {
|
||||
return ((DocumentsApplication) context.getApplicationContext()).mRoots;
|
||||
}
|
||||
@@ -55,6 +57,10 @@ public class DocumentsApplication extends Application {
|
||||
return client;
|
||||
}
|
||||
|
||||
public static DocumentClipper getDocumentClipper(Context context) {
|
||||
return ((DocumentsApplication) context.getApplicationContext()).mClipper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@@ -67,6 +73,8 @@ public class DocumentsApplication extends Application {
|
||||
|
||||
mThumbnailCache = new ThumbnailCache(memoryClassBytes / 4);
|
||||
|
||||
mClipper = new DocumentClipper(this);
|
||||
|
||||
final IntentFilter packageFilter = new IntentFilter();
|
||||
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
||||
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
|
||||
|
||||
@@ -76,7 +76,7 @@ public class FilesActivity extends BaseActivity {
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mClipper = new DocumentClipper(this);
|
||||
mClipper = DocumentsApplication.getDocumentClipper(this);
|
||||
|
||||
RootsFragment.show(getFragmentManager(), null);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.annotation.StringRes;
|
||||
import android.app.Activity;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.view.View;
|
||||
@@ -23,7 +24,22 @@ import android.view.View;
|
||||
public final class Snackbars {
|
||||
private Snackbars() {}
|
||||
|
||||
public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
|
||||
public static final void showMove(Activity activity, int docCount) {
|
||||
CharSequence message = Shared.getQuantityString(activity, R.plurals.move_begin, docCount);
|
||||
makeSnackbar(activity, message, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static final void showCopy(Activity activity, int docCount) {
|
||||
CharSequence message = Shared.getQuantityString(activity, R.plurals.copy_begin, docCount);
|
||||
makeSnackbar(activity, message, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static final void showPasteFailed(Activity activity) {
|
||||
makeSnackbar(activity, R.string.clipboard_files_cannot_paste, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public static final Snackbar makeSnackbar(Activity activity, @StringRes int messageId,
|
||||
int duration) {
|
||||
return Snackbars.makeSnackbar(
|
||||
activity, activity.getResources().getText(messageId), duration);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.StringRes;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlertDialog;
|
||||
@@ -53,6 +52,7 @@ import android.os.Parcelable;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v13.view.DragStartHelper;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
@@ -181,6 +181,32 @@ public class DirectoryFragment extends Fragment
|
||||
|
||||
private DirectoryDragListener mOnDragListener;
|
||||
|
||||
/**
|
||||
* A callback to show snackbar at the beginning of moving and copying.
|
||||
*/
|
||||
private final FileOperations.Callback mFileOpCallback = (status, opType, docCount) -> {
|
||||
if (status == FileOperations.Callback.STATUS_REJECTED) {
|
||||
Snackbars.showPasteFailed(getActivity());
|
||||
return;
|
||||
}
|
||||
|
||||
if (docCount == 0) {
|
||||
// Nothing has been pasted, so there is no need to show a snackbar.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (opType) {
|
||||
case FileOperationService.OPERATION_MOVE:
|
||||
Snackbars.showMove(getActivity(), docCount);
|
||||
break;
|
||||
case FileOperationService.OPERATION_COPY:
|
||||
Snackbars.showCopy(getActivity(), docCount);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported Operation: " + opType);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public View onCreateView(
|
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
@@ -283,7 +309,7 @@ public class DirectoryFragment extends Fragment
|
||||
mFocusManager = new FocusManager(context, mRecView, mModel);
|
||||
|
||||
mTuner = FragmentTuner.pick(getContext(), state);
|
||||
mClipper = new DocumentClipper(context);
|
||||
mClipper = DocumentsApplication.getDocumentClipper(getContext());
|
||||
|
||||
final ActivityManager am = (ActivityManager) context.getSystemService(
|
||||
Context.ACTIVITY_SERVICE);
|
||||
@@ -343,11 +369,12 @@ public class DirectoryFragment extends Fragment
|
||||
FileOperationService.OPERATION_COPY);
|
||||
|
||||
FileOperations.start(
|
||||
getActivity(),
|
||||
getContext(),
|
||||
getDisplayState().selectedDocumentsForCopy,
|
||||
getDisplayState().stack.peek(),
|
||||
(DocumentStack) data.getParcelableExtra(Shared.EXTRA_STACK),
|
||||
operationType);
|
||||
operationType,
|
||||
mFileOpCallback);
|
||||
}
|
||||
|
||||
protected boolean onDoubleTap(MotionEvent e) {
|
||||
@@ -1035,94 +1062,6 @@ public class DirectoryFragment extends Fragment
|
||||
return commonType[0] + "/" + commonType[1];
|
||||
}
|
||||
|
||||
private void copyFromClipboard(final DocumentInfo destination) {
|
||||
new AsyncTask<Void, Void, ClipDetails>() {
|
||||
|
||||
@Override
|
||||
protected ClipDetails doInBackground(Void... params) {
|
||||
return mClipper.getClipDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ClipDetails clipDetails) {
|
||||
if (clipDetails == null) {
|
||||
Log.w(TAG, "Received null clipDetails from primary clipboard. Ignoring.");
|
||||
return;
|
||||
}
|
||||
List<DocumentInfo> docs = clipDetails.docs;
|
||||
@OpType int type = clipDetails.opType;
|
||||
DocumentInfo srcParent = clipDetails.parent;
|
||||
moveDocuments(docs, destination, type, srcParent);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private void copyFromClipData(final ClipData clipData, final DocumentInfo destination) {
|
||||
assert(clipData != null);
|
||||
|
||||
new AsyncTask<Void, Void, ClipDetails>() {
|
||||
|
||||
@Override
|
||||
protected ClipDetails doInBackground(Void... params) {
|
||||
return mClipper.getClipDetails(clipData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ClipDetails clipDetails) {
|
||||
if (clipDetails == null) {
|
||||
Log.w(TAG, "Received null clipDetails. Ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<DocumentInfo> docs = clipDetails.docs;
|
||||
@OpType int type = clipDetails.opType;
|
||||
DocumentInfo srcParent = clipDetails.parent;
|
||||
moveDocuments(docs, destination, type, srcParent);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves {@code docs} from {@code srcParent} to {@code destination}.
|
||||
* operationType can be copy or cut
|
||||
* srcParent Must be non-null for move operations.
|
||||
*/
|
||||
private void moveDocuments(final List<DocumentInfo> docs, final DocumentInfo destination,
|
||||
final @OpType int operationType, final DocumentInfo srcParent) {
|
||||
BaseActivity activity = (BaseActivity) getActivity();
|
||||
if (!canCopy(docs, activity.getCurrentRoot(), destination)) {
|
||||
Snackbars.makeSnackbar(
|
||||
getActivity(),
|
||||
R.string.clipboard_files_cannot_paste,
|
||||
Snackbar.LENGTH_SHORT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (docs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DocumentStack curStack = getDisplayState().stack;
|
||||
DocumentStack dstStack = new DocumentStack();
|
||||
if (destination != null) {
|
||||
dstStack.push(destination);
|
||||
dstStack.addAll(curStack);
|
||||
} else {
|
||||
dstStack = curStack;
|
||||
}
|
||||
switch (operationType) {
|
||||
case FileOperationService.OPERATION_MOVE:
|
||||
FileOperations.move(getActivity(), docs, srcParent, dstStack);
|
||||
break;
|
||||
case FileOperationService.OPERATION_COPY:
|
||||
FileOperations.copy(getActivity(), docs, dstStack);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported operation: " + operationType);
|
||||
}
|
||||
}
|
||||
|
||||
public void copySelectedToClipboard() {
|
||||
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_COPY_CLIPBOARD);
|
||||
|
||||
@@ -1147,6 +1086,7 @@ public class DirectoryFragment extends Fragment
|
||||
|
||||
public void cutSelectedToClipboard() {
|
||||
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_CUT_CLIPBOARD);
|
||||
|
||||
Selection selection = mSelectionManager.getSelection(new Selection());
|
||||
if (selection.isEmpty()) {
|
||||
return;
|
||||
@@ -1171,36 +1111,12 @@ public class DirectoryFragment extends Fragment
|
||||
public void pasteFromClipboard() {
|
||||
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_PASTE_CLIPBOARD);
|
||||
|
||||
DocumentInfo destination = ((BaseActivity) getActivity()).getCurrentDirectory();
|
||||
copyFromClipboard(destination);
|
||||
BaseActivity activity = (BaseActivity) getActivity();
|
||||
DocumentInfo destination = activity.getCurrentDirectory();
|
||||
mClipper.copyFromClipboard(destination, activity.getDisplayState().stack, mFileOpCallback);
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the list of files can be copied to destination. Note that this
|
||||
* is a policy check only. Currently the method does not attempt to verify
|
||||
* available space or any other environmental aspects possibly resulting in
|
||||
* failure to copy.
|
||||
*
|
||||
* @return true if the list of files can be copied to destination.
|
||||
*/
|
||||
private boolean canCopy(List<DocumentInfo> files, RootInfo root, DocumentInfo dest) {
|
||||
if (dest == null || !dest.isDirectory() || !dest.isCreateSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can't copy folders to downloads, because we don't show folders there.
|
||||
if (root.isDownloads()) {
|
||||
for (DocumentInfo docs : files) {
|
||||
if (docs.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void selectAllFiles() {
|
||||
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SELECT_ALL);
|
||||
|
||||
@@ -1316,7 +1232,7 @@ public class DirectoryFragment extends Fragment
|
||||
src == null ? Metrics.USER_ACTION_DRAG_N_DROP_MULTI_WINDOW
|
||||
: Metrics.USER_ACTION_DRAG_N_DROP);
|
||||
|
||||
copyFromClipData(clipData, dst);
|
||||
mClipper.copyFromClipData(dst, getDisplayState().stack, clipData, mFileOpCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import static android.os.SystemClock.elapsedRealtime;
|
||||
import static com.android.documentsui.Shared.DEBUG;
|
||||
import static com.android.documentsui.Shared.EXTRA_STACK;
|
||||
import static com.android.documentsui.Shared.asArrayList;
|
||||
import static com.android.documentsui.Shared.getQuantityString;
|
||||
import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL;
|
||||
import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
|
||||
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
|
||||
@@ -30,21 +29,20 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_CO
|
||||
import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
|
||||
import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.documentsui.R;
|
||||
import com.android.documentsui.Snackbars;
|
||||
import com.android.documentsui.model.DocumentInfo;
|
||||
import com.android.documentsui.model.DocumentStack;
|
||||
import com.android.documentsui.services.FileOperationService.OpType;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -65,15 +63,14 @@ public final class FileOperations {
|
||||
/**
|
||||
* Tries to start the activity. Returns the job id.
|
||||
*/
|
||||
public static String start(
|
||||
Activity activity, List<DocumentInfo> srcDocs,
|
||||
DocumentStack stack, int operationType) {
|
||||
public static String start(Context context, List<DocumentInfo> srcDocs, DocumentStack stack,
|
||||
@OpType int operationType, Callback callback) {
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
|
||||
|
||||
switch (operationType) {
|
||||
case OPERATION_COPY:
|
||||
return FileOperations.copy(activity, srcDocs, stack);
|
||||
return FileOperations.copy(context, srcDocs, stack, callback);
|
||||
case OPERATION_MOVE:
|
||||
throw new IllegalArgumentException("Moving requires providing the source parent.");
|
||||
case OPERATION_DELETE:
|
||||
@@ -86,17 +83,16 @@ public final class FileOperations {
|
||||
/**
|
||||
* Tries to start the activity. Returns the job id.
|
||||
*/
|
||||
public static String start(
|
||||
Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
|
||||
DocumentStack stack, int operationType) {
|
||||
public static String start(Context context, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
|
||||
DocumentStack stack, @OpType int operationType, Callback callback) {
|
||||
|
||||
if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
|
||||
|
||||
switch (operationType) {
|
||||
case OPERATION_COPY:
|
||||
return FileOperations.copy(activity, srcDocs, stack);
|
||||
return FileOperations.copy(context, srcDocs, stack, callback);
|
||||
case OPERATION_MOVE:
|
||||
return FileOperations.move(activity, srcDocs, srcParent, stack);
|
||||
return FileOperations.move(context, srcDocs, srcParent, stack, callback);
|
||||
case OPERATION_DELETE:
|
||||
throw new UnsupportedOperationException("Delete isn't currently supported.");
|
||||
default:
|
||||
@@ -116,17 +112,16 @@ public final class FileOperations {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static String copy(
|
||||
Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) {
|
||||
public static String copy(Context context, List<DocumentInfo> srcDocs,
|
||||
DocumentStack destination, Callback callback) {
|
||||
String jobId = createJobId();
|
||||
if (DEBUG) Log.d(TAG, "Initiating 'copy' operation id: " + jobId);
|
||||
|
||||
Intent intent = createBaseIntent(OPERATION_COPY, activity, jobId, srcDocs, destination);
|
||||
Intent intent = createBaseIntent(OPERATION_COPY, context, jobId, srcDocs, destination);
|
||||
|
||||
createSharedSnackBar(activity, R.plurals.copy_begin, srcDocs.size())
|
||||
.show();
|
||||
callback.onOperationResult(Callback.STATUS_ACCEPTED, OPERATION_COPY, srcDocs.size());
|
||||
|
||||
activity.startService(intent);
|
||||
context.startService(intent);
|
||||
|
||||
return jobId;
|
||||
}
|
||||
@@ -140,19 +135,17 @@ public final class FileOperations {
|
||||
* @param srcParent Parent of all the source documents.
|
||||
* @param destination The move destination stack.
|
||||
*/
|
||||
public static String move(
|
||||
Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
|
||||
DocumentStack destination) {
|
||||
public static String move(Context context, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
|
||||
DocumentStack destination, Callback callback) {
|
||||
String jobId = createJobId();
|
||||
if (DEBUG) Log.d(TAG, "Initiating 'move' operation id: " + jobId);
|
||||
|
||||
Intent intent = createBaseIntent(OPERATION_MOVE, activity, jobId, srcDocs, srcParent,
|
||||
Intent intent = createBaseIntent(OPERATION_MOVE, context, jobId, srcDocs, srcParent,
|
||||
destination);
|
||||
|
||||
createSharedSnackBar(activity, R.plurals.move_begin, srcDocs.size())
|
||||
.show();
|
||||
callback.onOperationResult(Callback.STATUS_ACCEPTED, OPERATION_MOVE, srcDocs.size());
|
||||
|
||||
activity.startService(intent);
|
||||
context.startService(intent);
|
||||
|
||||
return jobId;
|
||||
}
|
||||
@@ -223,14 +216,6 @@ public final class FileOperations {
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static Snackbar createSharedSnackBar(Activity activity, int contentId, int fileCount) {
|
||||
Resources res = activity.getResources();
|
||||
return Snackbars.makeSnackbar(
|
||||
activity,
|
||||
getQuantityString(activity, contentId, fileCount),
|
||||
Snackbar.LENGTH_SHORT);
|
||||
}
|
||||
|
||||
private static final class IdBuilder {
|
||||
|
||||
// Remember last job time so we can guard against collisions.
|
||||
@@ -250,4 +235,25 @@ public final class FileOperations {
|
||||
return String.valueOf(mLastJobTime) + "-" + String.valueOf(mSubId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A functional callback called when the file operation starts or fails to start.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Callback {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({STATUS_ACCEPTED, STATUS_REJECTED})
|
||||
@interface Status {}
|
||||
static final int STATUS_ACCEPTED = 0;
|
||||
static final int STATUS_REJECTED = 1;
|
||||
|
||||
/**
|
||||
* Performs operation when the file operation starts or fails to start.
|
||||
*
|
||||
* @param status {@link Status} of this operation
|
||||
* @param opType file operation type {@link OpType}.
|
||||
* @param docCount number of documents operated.
|
||||
*/
|
||||
void onOperationResult(@Status int status, @OpType int opType, int docCount);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user