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に画像を渡す。
- CPSample.java
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/