ContentProviderでアプリ内のファイルを公開するサンプル

ContentProviderを使って、asset内のファイルをGMailに添付ファイルとして渡すサンプルです。
アプリ内のassets配下のファイルをIntent経由でほかのアプリに渡したい場合も動作します。
当時、ContentProviderがよくわかっていないこともあり、プロジェクトのassets配下のファイルが添付できなくてかなり悩みましたが、ContentProviderのリファレンスにちゃんと書いてあった・・・。

概要

Intent経由でアプリからGMailを起動したときに、ContentProviderを使って添付ファイルを渡します。
実装するものは以下のとおりです。

  • AssetFileProvider

  コンテンツプロバイダ。
  アプリ内のAssetファイルを渡します。insert,update,deleteなどは実装しません。

  • FileProvider

  コンテンツプロバイダ。
  SDカードなどのファイルを渡します。insert,update,deleteなどは実装しません。

  • AndroidManifest.xmlの編集

  コンテントプロバイダをAndroidManifest.xmlに登録します。

  • その他リソース

  res/layout/main.xml
  res/values/strings.xml
  画像ファイル

  • CPSampleの作成

  メインActivityクラス、CPSampleにGmailを起動するコードを追加します。

実装

AssetFileProviderの作成

アプリ内のAssetファイルを返す、ContentProviderを実装します。
onCreate、getType、insert、update、deleteは使用しません。
ここではAssetファイルを返すにはopenAssetFileを実装します。

  • FileContentProvider.java
package com.ttshrk.provider;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;

public class AssetFileProvider extends ContentProvider {

	public static final String AUTHORITY = "com.ttshrk.provider.AssetFile";
	public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
	public static final String TAG = "AssetFileProvider";

	@Override
	public boolean onCreate() {
		return false;
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

	@Override
	public AssetFileDescriptor openAssetFile(Uri uri, String mode)
			throws FileNotFoundException {
		Log.i(TAG, "open Asset file");
		try {
			return getContext().getAssets().openFd("sample_01.gif");
		} catch (IOException e) {
			e.printStackTrace();
			Log.e(TAG, "ERROR: " + e);
			throw new FileNotFoundException(e.getMessage());
		}
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		return 0;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		return null;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		return null;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		return 0;
	}
}
FileProviderの作成

SDカードなどのファイルを返す、ContentProviderを実装します。
onCreate、getType、insert、update、deleteは使用しません。
ここではopenFileを実装します。

  • FileProviderr.java
package com.ttshrk.provider;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;

public class FileProvider extends ContentProvider {

	public static final String AUTHORITY = "com.ttshrk.provider.File";
	public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
	public static final String TAG = "FileProvider";

	@Override
	public boolean onCreate() {
		return false;
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

	@Override
	public ParcelFileDescriptor openFile(Uri uri, String mode)
			throws FileNotFoundException {
		Log.i(TAG, "open file");
		URI path = URI.create("file:///sdcard/sample_02.jpg");

		ParcelFileDescriptor parcel = ParcelFileDescriptor.open(new File(path),
				ParcelFileDescriptor.MODE_READ_ONLY);
		return parcel;
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		return 0;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		return null;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		return null;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		return 0;
	}
}
AndroidManifest.xmlの編集

providerを追加します。

  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.ttshrk.cp_sample" android:versionCode="1"
	android:versionName="1.0">
	<uses-sdk android:minSdkVersion="3" />

	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<activity android:name=".CPSample" android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<provider android:name="com.ttshrk.provider.FileProvider" android:authorities="com.ttshrk.provider.File" />
		<provider android:name="com.ttshrk.provider.AssetFileProvider" android:authorities="com.ttshrk.provider.AssetFile" />
	</application>

	<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

</manifest>
その他リソース
  • res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout1">
    <Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:id="@+id/button1" android:text="@string/attach_mail"></Button>
    <Button android:text="@string/action_02" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>
<ImageView android:src="@drawable/icon" android:id="@+id/imageView1" android:layout_height="fill_parent" android:layout_width="fill_parent"></ImageView>
</LinearLayout>
  • res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">cp_sample</string>
    <string name="attach_mail">メール送信</string>
    <string name="action_02">View表示</string>
</resources>
  • 画像ファイル

以下のファイルを設置
assets/sample_01.gif
/sdcard/sample_02.jpg

CPSampleの作成

コンテントプロバイダのテストコードを書きます。
実装例は以下のとおりです。

    • Gmailに画像を添付する。
    • ImageViewに画像を渡す。
package com.ttshrk.cp_sample;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class CPSample extends Activity {
	ImageView imageView;
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button button1 = (Button) findViewById(R.id.button1);
		button1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				buttonClick1();
			}
		});
		
		Button button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				buttonClick2();
			}
		});
		
		imageView = (ImageView)findViewById(R.id.imageView1);
	}

	/**
	 * GMailにAssetFileProvider経由でAssetのファイル(sample_01.gif)を添付
	 */
	private void buttonClick1() {
		Intent intent = new Intent(Intent.ACTION_SEND);

		// subject
		intent.putExtra(Intent.EXTRA_SUBJECT, "さぶじぇくと");
		// text
		intent.putExtra(Intent.EXTRA_TEXT, "テキスト");

		// attachment
		intent.setType("image/gif");
		Uri uri = Uri.parse("content://com.ttshrk.provider.AssetFile/sample_01.gif");
		intent.putExtra(Intent.EXTRA_STREAM, uri);
		
		startActivity(Intent.createChooser(intent, null));
	}

	/**
	 * imageViewにFileProvider経由でSDカードのファイル(sample_02.jpg)を表示
	 */
	private void buttonClick2() {
		imageView.setImageURI(Uri.parse("content://com.ttshrk.provider.File/"));
	}
}


以上で、実装は終了です。
起動すると、「メール送信」と「View表示」のボタンが表示されます。

  • メール送信

GMailにファイルを添付してを起動します。送信するとAssetのファイル(assets/sample_01.gif)が添付されます。
 uriを「content://com.ttshrk.provider.AssetFile/sample_01.gif」のように指定していますが、GMailに添付ファイル名を渡すため、sample_01.gifをつけています。上記の実装では、AssetFileProvider側で「sample_01.gif」の部分を無視しています。

  • View表示

→アプリ上に、SDカードから読み込んだファイル(/sdcard/sample_02.jpg)が表示されます。ContentProvider経由でImageViewを表示するサンプルとしてみてもらえれば・・・。


以上です・・・。


上記のサンプルコードです。(すこしコードが変わってしまっていますが・・・)
cp_sample.zip 直

参考サイト

Android content provider example
http://www.xinotes.org/notes/note/1294/