商品作る場合では無く、テストで面倒なデバイス側での権限の付与の実装を避けたい場合のクラスを作ってみました。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>
|
|
【2017 Android Studioの最新記事】
- 別に納品するわけでは無いので、Android の ListView のカスタマイズなんてこれで十分でしょ / TestArrayAdapter バージョン2
- Java : Class 構造より、update 文を作成する
- ViewSwitcher を使用した2画面アプリ (5) : SQLiteデータを更新する
- ViewSwitcher を使用した2画面アプリ (4) : SQLiteデータをインポートしてリストビューに表示する
- Android Studio にインポートして使用する SQLite データベースを MDB より作成する VBScript
- ViewSwitcher を使用した2画面アプリ (3) : 画面部分の作成と画面切り替えテスト『画面をコントロールする Helper クラスの作成』
- ViewSwitcher を使用した2画面アプリ (2) : 画面部分の作成と画面切り替えテスト『画面の作成』
- ViewSwitcher を使用した2画面アプリ (1) : 画面部分の作成と画面切り替えテスト『メニューの作成』
- OkHttp を使用した HttpAccess クラスで Web 上の 画像をダウンロードして表示するテンプレート
- OkHttp を使用した HttpAccess クラスで Web 上の PHP アプリに対してファイルをアップロードするテンプレート
- OkHttp を使用した HttpAccess クラスで Web 上の掲示板に投稿(POST)するテンプレート
- OkHttp を使用した HttpAccess クラスで Web 上のデータを取得(GET)して ListView を表示するテンプレート
- Okhttp を使用した、GET、POST、ファイルアップロードを楽に実装できる HttpAccess クラス
- Android の assets フォルダーに保存した 400x320 の画像ファイルの扱い
- Android の drawable フォルダーに保存した 400x320 の画像ファイルの6種類の扱いと Density
- Android での保存用テキストデータの扱いを okio で簡素化する
- Android 6.0 : テストの為の Runtime Permission の対応を自動化するテンプレート
- Android Studio : Runtime Permission 等の裏方作業を MainActivity にさせて、本来の処理は継承したサブクラスで行う( カメラを呼び出して画像を保存させ、I..
- Android 6.0 の Runtime Permission に対応する前に、AndroidManifest.xml に権限の記述の必要無いプライベートな書き込みで情報を収集する
- Android Studio : エミュレータで Notification(通知)のテスト






