商品作る場合では無く、テストで面倒なデバイス側での権限の付与の実装を避けたい場合のクラスを作ってみました。getRequestCount() のチェックをしなければ、権限を付与するまでループするようにする事もできます(許可しない場合の UI テスト等にも使えるかもしれません) CheckMyPermission クラス
package com.example.lightbox.cameratest; import android.content.pm.PackageManager; import android.support.v4.app.ActivityCompat; import java.util.ArrayList; public class CheckMyPermission { private ArrayList<MyPermission> myPermission_list; private MainActivity context; public CheckMyPermission(MainActivity context, ArrayList<MyPermission> myPermission_list) { this.myPermission_list = myPermission_list; this.context = context; } public boolean checkPermission( int requestCode, int[] grantResults ) { boolean result = false; for( MyPermission myPermission : myPermission_list) { if ( myPermission.getPermissionId() == requestCode ) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { myPermission.setFlg(true); } } } int resultCounter = 0; for( MyPermission myPermission : myPermission_list) { if ( !myPermission.getFlg() ) { if ( myPermission.getRequestCount() > 0 ) { break; } ActivityCompat.requestPermissions(context, new String[]{myPermission.getPermissionType()}, myPermission.getPermissionId()); myPermission.setRequestCount(myPermission.getRequestCount()+1); break; } else { resultCounter++; } } if ( resultCounter == myPermission_list.size() ) { result = true; } return result; } public boolean checkPermission(){ boolean result = false; int initCounter = 0; for( MyPermission myPermission : myPermission_list) { if (ActivityCompat.checkSelfPermission(context, myPermission.getPermissionType())== PackageManager.PERMISSION_GRANTED){ initCounter++; myPermission.setFlg(true); } } if ( initCounter == myPermission_list.size() ) { result = true; } else { for( MyPermission myPermission : myPermission_list) { if ( !myPermission.getFlg() ) { // 最初に許可されていないパーミッション用のダイアログを表示する ActivityCompat.requestPermissions(context, new String[]{myPermission.getPermissionType()}, myPermission.getPermissionId()); myPermission.setRequestCount(myPermission.getRequestCount()+1); // 一つだけ処理する break; } } } return result; } }
対象となる Permission を ArrayList にセットとして内部で殆どの処理を実行してもらいます。ArrayList にセットする MyPermission クラスは以下のような情報を保持しています MyPermission クラス
package com.example.lightbox.cameratest; public class MyPermission { private String permissionType; private int permissionId; private boolean flg = false; private int requestCount = 0; public MyPermission(String type, int id) { permissionType = type; permissionId = id; } public String getPermissionType() { return permissionType; } public int getPermissionId() { return permissionId; } public boolean getFlg() { return flg; } public void setFlg(boolean flg) { this.flg = flg; } public int getRequestCount() { return requestCount; } public void setRequestCount(int requestCount) { this.requestCount = requestCount; } }
主な処理はカメラと撮影した画像の保存ですが、カメラはテストを目的としているので 『非推奨』の 旧API を使用しています。 MainActivity
package com.example.lightbox.cameratest; import android.Manifest; import android.content.Intent; import android.hardware.Camera; import android.media.MediaScannerConnection; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; public class MainActivity extends AppCompatActivity { private String imagePath; private OldCamera camera; private CheckMyPermission checkMyPermission; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 必要なパーミッションのリスト ArrayList<MyPermission> myPermission_list = new ArrayList<MyPermission>(); myPermission_list.add(new MyPermission(Manifest.permission.CAMERA,100)); myPermission_list.add(new MyPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,101)); // Runtime Permission 用のクラスのインスタンス checkMyPermission = new CheckMyPermission(MainActivity.this,myPermission_list); // 全ての必要なパーミッションが既に許可されていた場合 if ( checkMyPermission.checkPermission() ) { cameraSettings(); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { // 全ての必要なパーミッションが許可された場合 if ( checkMyPermission.checkPermission( requestCode, grantResults )) { // onCreate で初期処理できるように、MainActivity をリスタート Intent intent = getIntent(); finish(); startActivity(intent); } } private void cameraSettings() { camera = new OldCamera(MainActivity.this.findViewById(R.id.surfaceView) ); // ************************************* // ギャラリーに保存する処理 // ************************************* Button galleryButton = (Button) MainActivity.this.findViewById(R.id.button); galleryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i("lightbox", "クリック"); // 撮影 camera.getCamera().takePicture(null, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { if (data != null) { // ギャラリー用に内部ストレージにフォルダを作成 String imageDir = Environment.getExternalStorageDirectory().getPath() + "/cameratest"; File file = new File(imageDir); // ディレクトリ初期作成 if (!file.exists()) { if (file.mkdir() == false) { Log.i("lightbox", "ディレクトリを作成できませんでした"); return; } } // ギャラリー用画像保存パス Calendar cal = Calendar.getInstance(); SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd_HHmmss"); imagePath = imageDir + "/" + sf.format(cal.getTime()) + ".jpg"; FileOutputStream jpg; try { jpg = new FileOutputStream(imagePath); jpg.write(data); jpg.close(); // ギャラリーに反映 MediaScannerConnection.scanFile( MainActivity.this, new String[] { imagePath }, new String[] { "image/jpeg" }, null); } catch (Exception e) { e.printStackTrace(); } // カメラ機能再開 camera.startPreview(); } } }); } }); } }
OldCamera クラス
package com.example.lightbox.cameratest; import android.content.Context; import android.hardware.Camera; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import java.io.IOException; import java.util.List; public class OldCamera implements SurfaceHolder.Callback { // 古いカメラAPI。カメラで何かしたいわけでは無いのでこれで実装 private Camera camera; private SurfaceHolder surfaceHolder; private List<Camera.Size> sizeList; public OldCamera(View view) { Log.i("lightbox", "コンストラクタ"); // SurfaceView から holder を取り出す surfaceHolder = ((SurfaceView)view).getHolder(); // この中でイベント処理を行う surfaceHolder.addCallback(OldCamera.this); } public Camera getCamera() { return camera; } @Override public void surfaceCreated(SurfaceHolder holder) { Log.i("lightbox", "開く"); // カメラを開く camera = Camera.open(); try { // カメラに holder を渡す camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } // 縦固定(AndroidManifest.xml) で、portrait 撮影を前提 camera.setDisplayOrientation(90); // カメラの情報 Camera.Parameters params = camera.getParameters(); // サポートされているサイズの一覧 sizeList = params.getSupportedPreviewSizes(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 縦固定(AndroidManifest.xml) なので一度しか通らない Log.i("lightbox", "開始"); // 縦横サイズの設定 Camera.Parameters params = camera.getParameters(); Camera.Size optimalSize = getOptimalPreviewSize(sizeList,width,height); params.setPreviewSize(optimalSize.width,optimalSize.height); camera.setParameters(params); camera.startPreview(); } // http://qiita.com/zaburo/items/b5d3815d3ec45b0daf4f private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio=(double)h / w; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.i("lightbox", "終了"); // プレビュー終了 if ( camera != null ) { camera.stopPreview(); camera.release(); camera = null; } } }
画面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.lightbox.cameratest.MainActivity"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Button" /> </LinearLayout> <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lightbox.cameratest"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>