修行その壱「フォトメモ」(4)
ここまでの実装で、ちょっと前に買った本 - GraveDollの備忘録ブログでは模範演技の一部がが掲載されていたので、それを手本に今までのプログラムを直していきます。
今回はonCreate()内を直します。今までのプログラムはエラー処理があまりできていなかったみたいです。
import java.io.File; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.view.Display; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; // メイン画面(Activity) public class PhotoMemoActivity extends Activity { static final int REQUEST_CAPTURE_IMAGE = 100;/* onActivityResult内で識別するためのID */ // 描画対象のViewを保持するメンバ変数 private PhotoMemoView view; private Uri saveUri;// 写真を格納場所を示すURI String directory;// 写真を格納するディレクトリ String fileName;// 写真のファイル名 // 画面(Activity)が生成されるときの処理 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 外部ストレージがない場合、メッセージを出して終了 if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { Toast.makeText(this, R.string.message_externalstorage_not_mounted, Toast.LENGTH_SHORT).show(); finish(); } else { fileName = "IMG" + String.valueOf(System.currentTimeMillis()) + ".png";// IMG+現在時刻.pngというファイル名で保存される directory = Environment.getExternalStorageDirectory() + getPackageName();// パッケージ名のディレクトリに格納 // 撮影した写真を格納するディレクトリを作成する(すでに存在する場合は、作成されない) new File(Environment.getExternalStorageDirectory() + getPackageName()).mkdir(); saveUri = Uri.fromFile(new File(directory, fileName));// URI設定 view = null;// Viewを初期化 if (!callCamera(saveUri)) { // カメラアプリを呼び出せなかった旨を表示し、 Toast.makeText(this, R.string.message_no_camera, Toast.LENGTH_SHORT).show(); // 写真のないViewを生成 view = new PhotoMemoView(this); // Viewを画面に表示する setContentView(view); } } } private boolean callCamera(Uri saveUri) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// カメラアプリ呼び出しインテント生成 intent.putExtra(MediaStore.EXTRA_OUTPUT, saveUri);// カメラアプリをインテントで呼び出すときに写真格納場所情報を渡すよう設定 // 暗黙的インテントに応答できるアプリが1つ以上あるなら、 if (getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0) { // カメラアプリ起動 startActivityForResult(intent, REQUEST_CAPTURE_IMAGE); return true; } else { return false; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (REQUEST_CAPTURE_IMAGE == requestCode && resultCode == Activity.RESULT_OK) { File file = new File(directory, fileName);// 写真を格納するディレクトリ if (file.exists()) { Bitmap capturedImage = BitmapFactory.decodeFile(file.getPath()); // 描画対象のViewを生成し、 view = new PhotoMemoView(this, capturedImage); // 描画対象のViewを画面に表示する setContentView(view); view.setImageBitmap(capturedImage);// ビットマップ画像をimageViewに表示 } else { // 存在しない場合 view = new PhotoMemoView(this); setContentView(view); } } } // 端末のメニューボタンが押されたときの処理 @Override public boolean onCreateOptionsMenu(Menu menu) { // res/menu/menu.xmlを読み込み、メニューを生成する getMenuInflater().inflate(R.menu.menu, menu); return super.onCreateOptionsMenu(menu); } // メニューの項目が選ばれたときの処理 @Override public boolean onOptionsItemSelected(MenuItem item) { // 選ばれたメニューの種類(ID)に応じて、処理する switch (item.getItemId()) { // メニュー「線の太さ」の処理 case R.id.menu_paintwidth: // まだ処理を実装していない旨のメッセージを表示する Toast.makeText(this, R.string.message_no_function, Toast.LENGTH_SHORT).show(); break; // メニュー「線の色」の処理 case R.id.menu_paintcolor: // まだ処理を実装していない旨のメッセージを表示する Toast.makeText(this, R.string.message_no_function, Toast.LENGTH_SHORT).show(); break; default: break; } return super.onOptionsItemSelected(item); } }
- SDカードが挿入されていない場合、写真を保存できないのでエラーメッセージを出します。
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
これで外部メディアがマウントされているかどうかを判定します。
- 今までは写真のファイル名をtmp.jpgという固定の名前にしていましたが、これでは撮影するたびに同じ名前で上書きされてしまします。
System.currentTimeMillis()
現在の時刻を取得して、ファイル名にすることでこの問題を回避しています。
getPackageManager().queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY).size()
で、使用可能なカメラアプリの数を取得しています。
queryIntentActivities()について developersサイトを見ると、
public abstract List<ResolveInfo> queryIntentActivities (Intent intent, int flags)
セットしたインテントから呼び出せるアプリリストを取得できます。第一引数に対象のインテント、第二引数のflagsはアプリのカテゴリをセットできるみたいです。PackageManager.MATCH_DEFAULT_ONLYだと、android.intent.category.DEFAULTカテゴリのアプリからリストを取得できます。