RuntimeDocumentClipper.java revision 30b0dc1896abc67a970b61ebfd420275a31c1e18
130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin/* 230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Copyright (C) 2016 The Android Open Source Project 330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * 430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Licensed under the Apache License, Version 2.0 (the "License"); 530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * you may not use this file except in compliance with the License. 630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * You may obtain a copy of the License at 730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * 830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * http://www.apache.org/licenses/LICENSE-2.0 930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * 1030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Unless required by applicable law or agreed to in writing, software 1130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * distributed under the License is distributed on an "AS IS" BASIS, 1230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * See the License for the specific language governing permissions and 1430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * limitations under the License. 1530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 1630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 1730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linpackage com.android.documentsui.clipping; 1830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 1930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.content.ClipData; 2030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.content.ClipDescription; 2130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.content.ClipboardManager; 2230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.content.ContentResolver; 2330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.content.Context; 2430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.net.Uri; 2530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.os.PersistableBundle; 2630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.provider.DocumentsContract; 2730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.support.annotation.Nullable; 2830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport android.util.Log; 2930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 3030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.base.DocumentInfo; 3130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.base.DocumentStack; 3230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.base.Features; 3330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.base.RootInfo; 3430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.base.Shared; 3530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.selection.Selection; 3630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.services.FileOperation; 3730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.services.FileOperationService; 3830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.services.FileOperationService.OpType; 3930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport com.android.documentsui.services.FileOperations; 4030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 4130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.io.IOException; 4230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.util.ArrayList; 4330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.util.HashSet; 4430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.util.List; 4530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.util.Set; 4630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linimport java.util.function.Function; 4730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 4830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin/** 4930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * ClipboardManager wrapper class providing higher level logical 5030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * support for dealing with Documents. 5130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 5230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Linfinal class RuntimeDocumentClipper implements DocumentClipper { 5330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 5430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private static final String TAG = "DocumentClipper"; 5530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private static final String SRC_PARENT_KEY = "srcParent"; 5630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private static final String OP_TYPE_KEY = "opType"; 5730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 5830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private final Context mContext; 5930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private final ClipStore mClipStore; 6030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private final ClipboardManager mClipboard; 6130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 6230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin RuntimeDocumentClipper(Context context, ClipStore clipStore) { 6330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mContext = context; 6430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mClipStore = clipStore; 6530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mClipboard = context.getSystemService(ClipboardManager.class); 6630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 6730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 6830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 6930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public boolean hasItemsToPaste() { 7030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (mClipboard.hasPrimaryClip()) { 7130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipData clipData = mClipboard.getPrimaryClip(); 7230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 7330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin int count = clipData.getItemCount(); 7430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (count > 0) { 7530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin for (int i = 0; i < count; ++i) { 7630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipData.Item item = clipData.getItemAt(i); 7730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Uri uri = item.getUri(); 7830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (isDocumentUri(uri)) { 7930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return true; 8030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 8130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 8230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 8330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 8430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return false; 8530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 8630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 8730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private boolean isDocumentUri(@Nullable Uri uri) { 8830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return uri != null && DocumentsContract.isDocumentUri(mContext, uri); 8930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 9030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 9130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 9230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public ClipData getClipDataForDocuments( 9330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Function<String, Uri> uriBuilder, Selection selection, @OpType int opType) { 9430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 9530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(selection != null); 9630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 9730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (selection.isEmpty()) { 9830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Log.w(TAG, "Attempting to clip empty selection. Ignoring."); 9930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return null; 10030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 10130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 10230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return (selection.size() > Shared.MAX_DOCS_IN_INTENT) 10330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ? createJumboClipData(uriBuilder, selection, opType) 10430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin : createStandardClipData(uriBuilder, selection, opType); 10530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 10630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 10730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin /** 10830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Returns ClipData representing the selection. 10930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 11030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private ClipData createStandardClipData( 11130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Function<String, Uri> uriBuilder, Selection selection, @OpType int opType) { 11230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 11330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(!selection.isEmpty()); 11430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(selection.size() <= Shared.MAX_DOCS_IN_INTENT); 11530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 11630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final ContentResolver resolver = mContext.getContentResolver(); 11730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final ArrayList<ClipData.Item> clipItems = new ArrayList<>(); 11830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final Set<String> clipTypes = new HashSet<>(); 11930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 12030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin PersistableBundle bundle = new PersistableBundle(); 12130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin bundle.putInt(OP_TYPE_KEY, opType); 12230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 12330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin for (String id : selection) { 12430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(id != null); 12530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Uri uri = uriBuilder.apply(id); 12630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentInfo.addMimeTypes(resolver, uri, clipTypes); 12730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin clipItems.add(new ClipData.Item(uri)); 12830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 12930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 13030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipDescription description = new ClipDescription( 13130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin "", // Currently "label" is not displayed anywhere in the UI. 13230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin clipTypes.toArray(new String[0])); 13330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin description.setExtras(bundle); 13430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 13530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return createClipData(description, clipItems); 13630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 13730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 13830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin /** 13930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Returns ClipData representing the list of docs 14030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 14130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private ClipData createJumboClipData( 14230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Function<String, Uri> uriBuilder, Selection selection, @OpType int opType) { 14330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 14430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(!selection.isEmpty()); 14530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(selection.size() > Shared.MAX_DOCS_IN_INTENT); 14630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 14730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final List<Uri> uris = new ArrayList<>(selection.size()); 14830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 14930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final int capacity = Math.min(selection.size(), Shared.MAX_DOCS_IN_INTENT); 15030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final ArrayList<ClipData.Item> clipItems = new ArrayList<>(capacity); 15130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 15230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin // Set up mime types for the first Shared.MAX_DOCS_IN_INTENT 15330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final ContentResolver resolver = mContext.getContentResolver(); 15430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final Set<String> clipTypes = new HashSet<>(); 15530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin int docCount = 0; 15630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin for (String id : selection) { 15730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(id != null); 15830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Uri uri = uriBuilder.apply(id); 15930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (docCount++ < Shared.MAX_DOCS_IN_INTENT) { 16030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentInfo.addMimeTypes(resolver, uri, clipTypes); 16130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin clipItems.add(new ClipData.Item(uri)); 16230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 16330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 16430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin uris.add(uri); 16530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 16630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 16730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin // Prepare metadata 16830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin PersistableBundle bundle = new PersistableBundle(); 16930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin bundle.putInt(OP_TYPE_KEY, opType); 17030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin bundle.putInt(OP_JUMBO_SELECTION_SIZE, selection.size()); 17130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 17230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin // Persists clip items and gets the slot they were saved under. 17330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin int tag = mClipStore.persistUris(uris); 17430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin bundle.putInt(OP_JUMBO_SELECTION_TAG, tag); 17530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 17630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipDescription description = new ClipDescription( 17730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin "", // Currently "label" is not displayed anywhere in the UI. 17830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin clipTypes.toArray(new String[0])); 17930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin description.setExtras(bundle); 18030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 18130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return createClipData(description, clipItems); 18230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 18330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 18430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 18530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void clipDocumentsForCopy(Function<String, Uri> uriBuilder, Selection selection) { 18630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipData data = 18730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin getClipDataForDocuments(uriBuilder, selection, FileOperationService.OPERATION_COPY); 18830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(data != null); 18930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 19030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mClipboard.setPrimaryClip(data); 19130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 19230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 19330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 19430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void clipDocumentsForCut( 19530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Function<String, Uri> uriBuilder, Selection selection, DocumentInfo parent) { 19630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(!selection.isEmpty()); 19730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(parent.derivedUri != null); 19830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 19930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipData data = getClipDataForDocuments(uriBuilder, selection, 20030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperationService.OPERATION_MOVE); 20130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin assert(data != null); 20230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 20330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin PersistableBundle bundle = data.getDescription().getExtras(); 20430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin bundle.putString(SRC_PARENT_KEY, parent.derivedUri.toString()); 20530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 20630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mClipboard.setPrimaryClip(data); 20730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 20830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 20930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 21030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 21130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void copyFromClipboard( 21230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentInfo destination, 21330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentStack docStack, 21430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperations.Callback callback) { 21530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 21630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin copyFromClipData(destination, docStack, mClipboard.getPrimaryClip(), callback); 21730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 21830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 21930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 22030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void copyFromClipboard( 22130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentStack docStack, 22230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperations.Callback callback) { 22330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 22430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin copyFromClipData(docStack, mClipboard.getPrimaryClip(), callback); 22530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 22630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 22730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 22830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void copyFromClipData( 22930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final RootInfo root, 23030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final @Nullable DocumentInfo destination, 23130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final @Nullable ClipData clipData, 23230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final FileOperations.Callback callback) { 23330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentStack dstStack = new DocumentStack(root, destination); 23430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin copyFromClipData(dstStack, clipData, callback); 23530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 23630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 23730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 23830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public void copyFromClipData( 23930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final @Nullable DocumentInfo destination, 24030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final DocumentStack docStack, 24130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final @Nullable ClipData clipData, 24230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final FileOperations.Callback callback) { 24330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 24430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin DocumentStack dstStack = new DocumentStack(docStack, destination); 24530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin copyFromClipData(dstStack, clipData, callback); 24630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 24730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 24830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin /** 24930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Copies documents from given clip data to a folder. 25030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * 25130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * @param dstStack the document stack to the destination folder, including the destination 25230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * folder. 25330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * @param clipData the clipData to copy from 25430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * @param callback callback to notify when operation finishes 25530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 25630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private void copyFromClipData( 25730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final DocumentStack dstStack, 25830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final @Nullable ClipData clipData, 25930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin final FileOperations.Callback callback) { 26030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 26130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (clipData == null) { 26230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Log.i(TAG, "Received null clipData. Ignoring."); 26330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return; 26430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 26530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 26630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin PersistableBundle bundle = clipData.getDescription().getExtras(); 26730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @OpType int opType = getOpType(bundle); 26830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin try { 26930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (!canCopy(dstStack.peek())) { 27030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin callback.onOperationResult( 27130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperations.Callback.STATUS_REJECTED, getOpType(clipData), 0); 27230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return; 27330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 27430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 27530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin UrisSupplier uris = UrisSupplier.create(clipData, mClipStore); 27630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (uris.getItemCount() == 0) { 27730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin callback.onOperationResult( 27830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperations.Callback.STATUS_ACCEPTED, opType, 0); 27930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return; 28030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 28130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 28230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin String srcParentString = bundle.getString(SRC_PARENT_KEY); 28330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Uri srcParent = srcParentString == null ? null : Uri.parse(srcParentString); 28430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 28530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperation operation = new FileOperation.Builder() 28630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin .withOpType(opType) 28730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin .withSrcParent(srcParent) 28830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin .withDestination(dstStack) 28930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin .withSrcs(uris) 29030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin .build(); 29130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 29230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin FileOperations.start(mContext, operation, callback); 29330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } catch(IOException e) { 29430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin Log.e(TAG, "Cannot create uris supplier.", e); 29530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin callback.onOperationResult(FileOperations.Callback.STATUS_REJECTED, opType, 0); 29630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return; 29730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 29830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 29930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 30030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin /** 30130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * Returns true if the list of files can be copied to destination. Note that this 30230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * is a policy check only. Currently the method does not attempt to verify 30330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * available space or any other environmental aspects possibly resulting in 30430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * failure to copy. 30530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * 30630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin * @return true if the list of files can be copied to destination. 30730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin */ 30830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private static boolean canCopy(@Nullable DocumentInfo dest) { 30930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return dest != null && dest.isDirectory() && dest.isCreateSupported(); 31030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 31130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 31230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin @Override 31330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin public @OpType int getOpType(ClipData data) { 31430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin PersistableBundle bundle = data.getDescription().getExtras(); 31530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return getOpType(bundle); 31630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 31730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 31830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private @OpType int getOpType(PersistableBundle bundle) { 31930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return bundle.getInt(OP_TYPE_KEY); 32030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 32130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 32230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin private static ClipData createClipData( 32330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipDescription description, ArrayList<ClipData.Item> clipItems) { 32430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 32530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin // technically we want to check >= O, but we'd need to patch back the O version code :| 32630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin if (Features.OMC_RUNTIME) { 32730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return new ClipData(description, clipItems); 32830b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 32930b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin 33030b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin ClipData clip = new ClipData(description, clipItems.get(0)); 33130b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin for (int i = 1; i < clipItems.size(); i++) { 33230b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin clip.addItem(clipItems.get(i)); 33330b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 33430b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin return clip; 33530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin } 33630b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin} 337