Loading src/com/android/documentsui/DocumentClipper.java +127 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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; Loading src/com/android/documentsui/DocumentsApplication.java +8 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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(); Loading @@ -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); Loading src/com/android/documentsui/FilesActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading src/com/android/documentsui/Snackbars.java +17 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading src/com/android/documentsui/dirlist/DirectoryFragment.java +36 −120 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; } Loading Loading
src/com/android/documentsui/DocumentClipper.java +127 −15 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading Loading @@ -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; Loading Loading @@ -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; Loading
src/com/android/documentsui/DocumentsApplication.java +8 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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(); Loading @@ -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); Loading
src/com/android/documentsui/FilesActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
src/com/android/documentsui/Snackbars.java +17 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading
src/com/android/documentsui/dirlist/DirectoryFragment.java +36 −120 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; } Loading