Home | History | Annotate | Download | only in documentsui
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.documentsui;
     18 
     19 import android.content.ClipData;
     20 import android.content.ClipboardManager;
     21 import android.content.ContentProviderClient;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.database.Cursor;
     25 import android.net.Uri;
     26 import android.provider.DocumentsContract;
     27 import android.support.annotation.Nullable;
     28 import android.util.Log;
     29 
     30 import com.android.documentsui.model.DocumentInfo;
     31 
     32 import libcore.io.IoUtils;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.Collections;
     37 import java.util.HashSet;
     38 import java.util.List;
     39 
     40 /**
     41  * ClipboardManager wrapper class providing higher level logical
     42  * support for dealing with Documents.
     43  */
     44 public final class DocumentClipper {
     45 
     46     private static final String TAG = "DocumentClipper";
     47 
     48     private Context mContext;
     49     private ClipboardManager mClipboard;
     50 
     51     public DocumentClipper(Context context) {
     52         mContext = context;
     53         mClipboard = context.getSystemService(ClipboardManager.class);
     54     }
     55 
     56     public boolean hasItemsToPaste() {
     57         if (mClipboard.hasPrimaryClip()) {
     58             ClipData clipData = mClipboard.getPrimaryClip();
     59             int count = clipData.getItemCount();
     60             if (count > 0) {
     61                 for (int i = 0; i < count; ++i) {
     62                     ClipData.Item item = clipData.getItemAt(i);
     63                     Uri uri = item.getUri();
     64                     if (isDocumentUri(uri)) {
     65                         return true;
     66                     }
     67                 }
     68             }
     69         }
     70         return false;
     71     }
     72 
     73     private boolean isDocumentUri(@Nullable Uri uri) {
     74         return uri != null && DocumentsContract.isDocumentUri(mContext, uri);
     75     }
     76 
     77     /**
     78      * Returns a list of Documents as decoded from Clipboard primary clipdata.
     79      * This should be run from inside an AsyncTask.
     80      */
     81     public List<DocumentInfo> getClippedDocuments() {
     82         ClipData data = mClipboard.getPrimaryClip();
     83         return data == null ? Collections.EMPTY_LIST : getDocumentsFromClipData(data);
     84     }
     85 
     86     /**
     87      * Returns a list of Documents as decoded in clipData.
     88      * This should be run from inside an AsyncTask.
     89      */
     90     public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
     91         assert(clipData != null);
     92         final List<DocumentInfo> srcDocs = new ArrayList<>();
     93 
     94         int count = clipData.getItemCount();
     95         if (count == 0) {
     96             return srcDocs;
     97         }
     98 
     99         ContentResolver resolver = mContext.getContentResolver();
    100         for (int i = 0; i < count; ++i) {
    101             ClipData.Item item = clipData.getItemAt(i);
    102             Uri itemUri = item.getUri();
    103             if (itemUri != null && DocumentsContract.isDocumentUri(mContext, itemUri)) {
    104                 ContentProviderClient client = null;
    105                 Cursor cursor = null;
    106                 try {
    107                     client = DocumentsApplication.acquireUnstableProviderOrThrow(
    108                             resolver, itemUri.getAuthority());
    109                     cursor = client.query(itemUri, null, null, null, null);
    110                     cursor.moveToPosition(0);
    111                     srcDocs.add(DocumentInfo.fromCursor(cursor, itemUri.getAuthority()));
    112                 } catch (Exception e) {
    113                     Log.e(TAG, e.getMessage());
    114                 } finally {
    115                     IoUtils.closeQuietly(cursor);
    116                     ContentProviderClient.releaseQuietly(client);
    117                 }
    118             }
    119         }
    120 
    121         return srcDocs;
    122     }
    123 
    124     /**
    125      * Returns ClipData representing the list of docs, or null if docs is empty,
    126      * or docs cannot be converted.
    127      */
    128     public @Nullable ClipData getClipDataForDocuments(List<DocumentInfo> docs) {
    129         final ContentResolver resolver = mContext.getContentResolver();
    130         final String[] mimeTypes = getMimeTypes(resolver, docs);
    131         ClipData clipData = null;
    132         for (DocumentInfo doc : docs) {
    133             if (clipData == null) {
    134                 // TODO: figure out what this string should be.
    135                 // Currently it is not displayed anywhere in the UI, but this might change.
    136                 final String label = "";
    137                 clipData = new ClipData(label, mimeTypes, new ClipData.Item(doc.derivedUri));
    138             } else {
    139                 // TODO: update list of mime types in ClipData.
    140                 clipData.addItem(new ClipData.Item(doc.derivedUri));
    141             }
    142         }
    143         return clipData;
    144     }
    145 
    146     private static String[] getMimeTypes(ContentResolver resolver, List<DocumentInfo> docs) {
    147         final HashSet<String> mimeTypes = new HashSet<>();
    148         for (DocumentInfo doc : docs) {
    149             assert(doc != null);
    150             assert(doc.derivedUri != null);
    151             final Uri uri = doc.derivedUri;
    152             if ("content".equals(uri.getScheme())) {
    153                 mimeTypes.add(resolver.getType(uri));
    154                 final String[] streamTypes = resolver.getStreamTypes(uri, "*/*");
    155                 if (streamTypes != null) {
    156                     mimeTypes.addAll(Arrays.asList(streamTypes));
    157                 }
    158             }
    159         }
    160         return mimeTypes.toArray(new String[0]);
    161     }
    162 
    163     public void clipDocuments(List<DocumentInfo> docs) {
    164         ClipData data = getClipDataForDocuments(docs);
    165         mClipboard.setPrimaryClip(data);
    166     }
    167 }
    168