Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2013 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.example.android.apis.content;
     18 
     19 import android.app.Activity;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.database.Cursor;
     24 import android.net.Uri;
     25 import android.os.Bundle;
     26 import android.provider.DocumentsContract;
     27 import android.provider.DocumentsContract.Document;
     28 import android.util.Log;
     29 import android.view.View;
     30 import android.view.View.OnClickListener;
     31 import android.widget.Button;
     32 import android.widget.CheckBox;
     33 import android.widget.LinearLayout;
     34 import android.widget.ScrollView;
     35 import android.widget.TextView;
     36 
     37 import java.io.ByteArrayOutputStream;
     38 import java.io.IOException;
     39 import java.io.InputStream;
     40 import java.io.OutputStream;
     41 
     42 /**
     43  * Example that exercises client side of {@link DocumentsContract}.
     44  */
     45 public class DocumentsSample extends Activity {
     46     private static final String TAG = "DocumentsSample";
     47 
     48     private static final int CODE_READ = 42;
     49     private static final int CODE_WRITE = 43;
     50     private static final int CODE_TREE = 44;
     51     private static final int CODE_RENAME = 45;
     52 
     53     private TextView mResult;
     54 
     55     @Override
     56     public void onCreate(Bundle icicle) {
     57         super.onCreate(icicle);
     58 
     59         final Context context = this;
     60 
     61         final LinearLayout view = new LinearLayout(context);
     62         view.setOrientation(LinearLayout.VERTICAL);
     63 
     64         mResult = new TextView(context);
     65         view.addView(mResult);
     66 
     67         final CheckBox multiple = new CheckBox(context);
     68         multiple.setText("ALLOW_MULTIPLE");
     69         view.addView(multiple);
     70         final CheckBox localOnly = new CheckBox(context);
     71         localOnly.setText("LOCAL_ONLY");
     72         view.addView(localOnly);
     73 
     74         Button button;
     75         button = new Button(context);
     76         button.setText("OPEN_DOC */*");
     77         button.setOnClickListener(new OnClickListener() {
     78             @Override
     79             public void onClick(View v) {
     80                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
     81                 intent.addCategory(Intent.CATEGORY_OPENABLE);
     82                 intent.setType("*/*");
     83                 if (multiple.isChecked()) {
     84                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
     85                 }
     86                 if (localOnly.isChecked()) {
     87                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
     88                 }
     89                 startActivityForResult(intent, CODE_READ);
     90             }
     91         });
     92         view.addView(button);
     93 
     94         button = new Button(context);
     95         button.setText("OPEN_DOC image/*");
     96         button.setOnClickListener(new OnClickListener() {
     97             @Override
     98             public void onClick(View v) {
     99                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    100                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    101                 intent.setType("image/*");
    102                 if (multiple.isChecked()) {
    103                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    104                 }
    105                 if (localOnly.isChecked()) {
    106                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    107                 }
    108                 startActivityForResult(intent, CODE_READ);
    109             }
    110         });
    111         view.addView(button);
    112 
    113         button = new Button(context);
    114         button.setText("OPEN_DOC audio/ogg");
    115         button.setOnClickListener(new OnClickListener() {
    116             @Override
    117             public void onClick(View v) {
    118                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    119                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    120                 intent.setType("audio/ogg");
    121                 if (multiple.isChecked()) {
    122                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    123                 }
    124                 if (localOnly.isChecked()) {
    125                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    126                 }
    127                 startActivityForResult(intent, CODE_READ);
    128             }
    129         });
    130         view.addView(button);
    131 
    132         button = new Button(context);
    133         button.setText("OPEN_DOC text/plain, application/msword");
    134         button.setOnClickListener(new OnClickListener() {
    135             @Override
    136             public void onClick(View v) {
    137                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    138                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    139                 intent.setType("*/*");
    140                 intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
    141                         "text/plain", "application/msword" });
    142                 if (multiple.isChecked()) {
    143                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    144                 }
    145                 if (localOnly.isChecked()) {
    146                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    147                 }
    148                 startActivityForResult(intent, CODE_READ);
    149             }
    150         });
    151         view.addView(button);
    152 
    153         button = new Button(context);
    154         button.setText("CREATE_DOC text/plain");
    155         button.setOnClickListener(new OnClickListener() {
    156             @Override
    157             public void onClick(View v) {
    158                 Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    159                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    160                 intent.setType("text/plain");
    161                 intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
    162                 if (localOnly.isChecked()) {
    163                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    164                 }
    165                 startActivityForResult(intent, CODE_WRITE);
    166             }
    167         });
    168         view.addView(button);
    169 
    170         button = new Button(context);
    171         button.setText("CREATE_DOC image/png");
    172         button.setOnClickListener(new OnClickListener() {
    173             @Override
    174             public void onClick(View v) {
    175                 Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    176                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    177                 intent.setType("image/png");
    178                 intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png");
    179                 if (localOnly.isChecked()) {
    180                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    181                 }
    182                 startActivityForResult(intent, CODE_WRITE);
    183             }
    184         });
    185         view.addView(button);
    186 
    187         button = new Button(context);
    188         button.setText("GET_CONTENT */*");
    189         button.setOnClickListener(new OnClickListener() {
    190             @Override
    191             public void onClick(View v) {
    192                 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    193                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    194                 intent.setType("*/*");
    195                 if (multiple.isChecked()) {
    196                     intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
    197                 }
    198                 if (localOnly.isChecked()) {
    199                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    200                 }
    201                 startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_READ);
    202             }
    203         });
    204         view.addView(button);
    205 
    206         button = new Button(context);
    207         button.setText("OPEN_DOC_TREE");
    208         button.setOnClickListener(new OnClickListener() {
    209             @Override
    210             public void onClick(View v) {
    211                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    212                 if (localOnly.isChecked()) {
    213                     intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    214                 }
    215                 startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_TREE);
    216             }
    217         });
    218         view.addView(button);
    219 
    220         button = new Button(context);
    221         button.setText("OPEN_DOC */* for rename");
    222         button.setOnClickListener(new OnClickListener() {
    223             @Override
    224             public void onClick(View v) {
    225                 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    226                 intent.addCategory(Intent.CATEGORY_OPENABLE);
    227                 intent.setType("*/*");
    228                 startActivityForResult(intent, CODE_RENAME);
    229             }
    230         });
    231         view.addView(button);
    232 
    233         final ScrollView scroll = new ScrollView(context);
    234         scroll.addView(view);
    235 
    236         setContentView(scroll);
    237     }
    238 
    239     @Override
    240     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    241         final ContentResolver cr = getContentResolver();
    242 
    243         clearLog();
    244 
    245         log("resultCode=" + resultCode);
    246         log("data=" + String.valueOf(data));
    247 
    248         final Uri uri = data != null ? data.getData() : null;
    249         if (uri != null) {
    250             log("isDocumentUri=" + DocumentsContract.isDocumentUri(this, uri));
    251         } else {
    252             log("missing URI?");
    253             return;
    254         }
    255 
    256         if (requestCode == CODE_READ) {
    257             try {
    258                 cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
    259             } catch (SecurityException e) {
    260                 log("FAILED TO TAKE PERMISSION", e);
    261             }
    262             InputStream is = null;
    263             try {
    264                 is = cr.openInputStream(uri);
    265                 log("read length=" + readFullyNoClose(is).length);
    266             } catch (Exception e) {
    267                 log("FAILED TO READ", e);
    268             } finally {
    269                 closeQuietly(is);
    270             }
    271         } else if (requestCode == CODE_WRITE) {
    272             try {
    273                 cr.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    274             } catch (SecurityException e) {
    275                 log("FAILED TO TAKE PERMISSION", e);
    276             }
    277             OutputStream os = null;
    278             try {
    279                 os = cr.openOutputStream(uri);
    280                 os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
    281                 log("wrote data");
    282             } catch (Exception e) {
    283                 log("FAILED TO WRITE", e);
    284             } finally {
    285                 closeQuietly(os);
    286             }
    287         } else if (requestCode == CODE_TREE) {
    288             // Find existing docs
    289             Uri doc = DocumentsContract.buildDocumentUriUsingTree(uri,
    290                     DocumentsContract.getTreeDocumentId(uri));
    291             Uri child = DocumentsContract.buildChildDocumentsUriUsingTree(uri,
    292                     DocumentsContract.getTreeDocumentId(uri));
    293             Cursor c = cr.query(child, new String[] {
    294                     Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE }, null, null, null);
    295             try {
    296                 while (c.moveToNext()) {
    297                     log("found child=" + c.getString(0) + ", mime=" + c.getString(1));
    298                 }
    299             } finally {
    300                 closeQuietly(c);
    301             }
    302 
    303             // Create some documents
    304             Uri pic = createDocument(cr, doc, "image/png", "pic.png");
    305             Uri dir = createDocument(cr, doc, Document.MIME_TYPE_DIR, "my dir");
    306             Uri dirPic = createDocument(cr, dir, "image/png", "pic2.png");
    307 
    308             log("created " + pic);
    309             log("created " + dir);
    310             log("created " + dirPic);
    311 
    312             // Write to one of them
    313             OutputStream os = null;
    314             try {
    315                 os = cr.openOutputStream(dirPic);
    316                 os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
    317                 log("wrote data");
    318             } catch (Exception e) {
    319                 log("FAILED TO WRITE", e);
    320             } finally {
    321                 closeQuietly(os);
    322             }
    323 
    324             // And delete the first pic
    325             if (deleteDocument(cr, pic)) {
    326                 log("deleted untouched pic");
    327             } else {
    328                 log("FAILED TO DELETE PIC");
    329             }
    330         } else if (requestCode == CODE_RENAME) {
    331             final Uri newUri = renameDocument(cr, uri, "MEOW.TEST");
    332             log("rename result=" + newUri);
    333 
    334             InputStream is = null;
    335             try {
    336                 is = cr.openInputStream(newUri);
    337                 log("read length=" + readFullyNoClose(is).length);
    338             } catch (Exception e) {
    339                 log("FAILED TO READ", e);
    340             } finally {
    341                 closeQuietly(is);
    342             }
    343         }
    344     }
    345 
    346     private Uri createDocument(ContentResolver resolver, Uri documentUri, String mimeType,
    347             String displayName) {
    348         Uri uri;
    349         try {
    350             uri = DocumentsContract.createDocument(resolver, documentUri, mimeType, displayName);
    351         } catch (Exception e) {
    352             uri = null;
    353         }
    354         return uri;
    355     }
    356 
    357     private boolean deleteDocument(ContentResolver resolver, Uri documentUri) {
    358         try {
    359             return DocumentsContract.deleteDocument(resolver, documentUri);
    360         } catch (Exception e) {
    361             return false;
    362         }
    363     }
    364 
    365     private Uri renameDocument(ContentResolver resolver, Uri uri, String newName) {
    366         try {
    367             return DocumentsContract.renameDocument(resolver, uri, newName);
    368         } catch (Exception e) {
    369             return null;
    370         }
    371     }
    372 
    373     private void clearLog() {
    374         mResult.setText(null);
    375     }
    376 
    377     private void log(String msg) {
    378         log(msg, null);
    379     }
    380 
    381     private void log(String msg, Throwable t) {
    382         Log.d(TAG, msg, t);
    383         mResult.setText(mResult.getText() + "\n" + msg);
    384     }
    385 
    386     public static byte[] readFullyNoClose(InputStream in) throws IOException {
    387         ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    388         byte[] buffer = new byte[1024];
    389         int count;
    390         while ((count = in.read(buffer)) != -1) {
    391             bytes.write(buffer, 0, count);
    392         }
    393         return bytes.toByteArray();
    394     }
    395 
    396     public static void closeQuietly(AutoCloseable closeable) {
    397         if (closeable != null) {
    398             try {
    399                 closeable.close();
    400             } catch (RuntimeException rethrown) {
    401                 throw rethrown;
    402             } catch (Exception ignored) {
    403             }
    404         }
    405     }
    406 }
    407