Wednesday, May 7, 2014

Using Intent.ACTION_OPEN_DOCUMENT, for KitKat API 19 or higher

Android 4.4 KitKat, API 19, introduce new Intent.ACTION_OPEN_DOCUMENT, allow the user to select and return one or more existing documents. When invoked, the system will display the various DocumentsProvider instances installed on the device, letting the user interactively navigate through them. These documents include local media, such as photos and video, and documents provided by installed cloud storage providers.

Each document is represented as a content://

This example show how to select image file by calling startActivityForResult() with Intent of ACTION_OPEN_DOCUMENT, then load it in ImageView from the returned Uri.
  • To load image Intent.ACTION_OPEN_DOCUMENT, setType("image/*")
  • This example haven't handle resize of the image, so may be fail if load ImageView with large image.
  • If the app run on pre-KitKat devices, it will use old Intent.ACTION_GET_CONTENT.


package com.example.androidkitkatdocument;

import java.io.FileNotFoundException;

import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

public class MainActivity extends Activity {

 private static final int RQS_OPEN_IMAGE = 1;

 Button buttonOpen;
 TextView textUri;
 ImageView imageView;
 
 Uri targetUri = null;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  buttonOpen = (Button) findViewById(R.id.opendocument);
  buttonOpen.setOnClickListener(buttonOpenOnClickListener);
  
  textUri = (TextView) findViewById(R.id.texturi);
  textUri.setOnClickListener(textUriOnClickListener);
  
  imageView = (ImageView)findViewById(R.id.image);
 }

 OnClickListener buttonOpenOnClickListener = 
  new OnClickListener() {

  @TargetApi(Build.VERSION_CODES.KITKAT)
  @Override
  public void onClick(View v) {
   Intent intent = new Intent();

   if (Build.VERSION.SDK_INT >= 
     Build.VERSION_CODES.KITKAT) {
    intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
   } else {
    intent.setAction(Intent.ACTION_GET_CONTENT);
   }

   intent.addCategory(Intent.CATEGORY_OPENABLE);

   // set MIME type for image
   intent.setType("image/*");

   startActivityForResult(intent, RQS_OPEN_IMAGE);
  }

 };
 
 OnClickListener textUriOnClickListener = 
  new OnClickListener(){

  @Override
  public void onClick(View v) {
   if (targetUri != null){
    Bitmap bm;
    try {
     bm = BitmapFactory.decodeStream(
      getContentResolver()
      .openInputStream(targetUri));
     imageView.setImageBitmap(bm);
    } catch (FileNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  
 };

 @TargetApi(Build.VERSION_CODES.KITKAT)
 @Override
 protected void onActivityResult(int requestCode, 
   int resultCode, Intent data) {

  if (resultCode == Activity.RESULT_OK) {

   Uri dataUri = data.getData();

   if (requestCode == RQS_OPEN_IMAGE) {
    targetUri = dataUri;
    textUri.setText(dataUri.toString());
   }
  }

 }

}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidkitkatdocument.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Button 
        android:id="@+id/opendocument"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Document of Image" />
    
    <TextView
        android:id="@+id/texturi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    
    <ImageView
        android:id="@+id/image"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidkitkatdocument"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidkitkatdocument.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


download filesDownload the files.

More examples:
Using Intent.ACTION_OPEN_DOCUMENT with EXTRA_MIME_TYPES to open file of multi mime types
Open multi files using Intent.ACTION_OPEN_DOCUMENT, with EXTRA_ALLOW_MULTIPLE and getClipData()
Intent.ACTION_OPEN_DOCUMENT to load images in RecyclerView + CardView
Hello World to open photo using Intent.ACTION_OPEN_DOCUMENT, with FloatingActionButton and Snackbar
Read Exif tag of JPG using ExifInterface(FileDescriptor)


3 comments:

  1. thank you, it is helpful for me.

    ReplyDelete
  2. Is it possible to show both images and videos in picker UI using the ACTION_OPEN_DOCUMENT....? By setting type like setType("image/* video/*");

    ReplyDelete