web-dev-qa-db-ja.com

android:マシュマロでカメラが開かない

そのため、カメラを開いて画像をキャプチャし、SDCardに保存するコードを以下に示します。

public void getPhotoFromCamera() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File mediaStorageDir = new File(
            Environment.getExternalStorageDirectory()
                    + File.separator
                    + getString(R.string.directory_name_corp_chat)
                    + File.separator
                    + getString(R.string.directory_name_temp)
    );

    if (!mediaStorageDir.exists()) {
        mediaStorageDir.mkdirs();
    }

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
            Locale.getDefault()).format(new Date());
    try {
        mediaFile = File.createTempFile(
                "TEMP_FULL_IMG_" + timeStamp,
                ".jpg",
                mediaStorageDir
        );
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
        startActivityForResult(takePictureIntent, PICK_FROM_CAMERA);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void performCrop(Uri picUri) {
    try {
        Intent cropIntent = new Intent("com.Android.camera.action.CROP");
        cropIntent.setDataAndType(picUri, "image/*");
        cropIntent.putExtra("crop", "true");
        cropIntent.putExtra("aspectX", 1);
        cropIntent.putExtra("aspectY", 1);
        cropIntent.putExtra("outputX", 128);
        cropIntent.putExtra("outputY", 128);
        // retrieve data on return
        cropIntent.putExtra("return-data", true);

        File mediaStorageDir = new File(
                Environment.getExternalStorageDirectory()
                        + File.separator
                        + getString(R.string.directory_name_corp_chat)
                        + File.separator
                        + getString(R.string.directory_name_temp)
        );

        if (!mediaStorageDir.exists()) {
            mediaStorageDir.mkdirs();
        }

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                Locale.getDefault()).format(new Date());
        try {
            croppedFile = File.createTempFile(
                    "TEMP_CROPPED_IMG_" + timeStamp,
                    ".jpg",
                    mediaStorageDir
            );
            cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(croppedFile));
            startActivityForResult(cropIntent, PIC_CROP);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // respond to users whose devices do not support the crop action
    catch (ActivityNotFoundException anfe) {
        // display an error message
        String errorMessage = "Whoops - your device doesn't support the crop action!";
        Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
        toast.show();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == PICK_FROM_CAMERA) {
        if (resultCode == RESULT_OK) {
            performCrop(Uri.fromFile(mediaFile));
        } else {
            Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
            Log.i("File deleted ", mediaFile.delete() + "");
        }
    }

    if (requestCode == PICK_FROM_GALLERY) {
        if (resultCode == RESULT_OK) {
            performCrop(data.getData());
        } else {
            Log.i("Gallery", "result cancel");
        }
    }

    if (requestCode == PIC_CROP) {
        if (resultCode == RESULT_OK) {
            imageView.setImageBitmap(BitmapFactory.decodeFile(croppedFile.getAbsolutePath()));
            if (mediaFile != null) {
                Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
                Log.i("File deleted ", mediaFile.delete() + "");
            }
        } else {
            if (croppedFile != null) {
                Log.i("Camera", "result cancel. Hence, deleting file: " + croppedFile.getPath());
                Log.i("File deleted ", croppedFile.delete() + "");
            }
            if (mediaFile != null) {
                Log.i("Camera", "result cancel. Hence, deleting file: " + mediaFile.getPath());
                Log.i("File deleted ", mediaFile.delete() + "");
            }
        }
    }
}

すべてが以下のように完璧に動作しますAndroid 6.0。しかし、それはAndroid 6.0 Marshmallowで動作しません。実際、カメラを開くことさえしません:(

マシュマロのために何か特別なことをする必要があるかどうかはわかりません。私もここに投稿できるエラーはありません。私を助けてください。

ありがとう。

18
Chintan Soni

だから、私は次のように私のタスクを達成しました:

権限を確認するために、以下のように別のクラスを作成しました:

public class MarshMallowPermission {

    public static final int RECORD_PERMISSION_REQUEST_CODE = 1;
    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 2;
    public static final int CAMERA_PERMISSION_REQUEST_CODE = 3;
    Activity activity;

    public MarshMallowPermission(Activity activity) {
        this.activity = activity;
    }

    public boolean checkPermissionForRecord(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public boolean checkPermissionForExternalStorage(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public boolean checkPermissionForCamera(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public void requestPermissionForRecord(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.RECORD_AUDIO)){
           Toast.makeText(activity, "Microphone permission needed for recording. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.RECORD_AUDIO},RECORD_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForExternalStorage(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
            Toast.makeText(activity, "External Storage permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForCamera(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)){
            Toast.makeText(activity, "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.CAMERA},CAMERA_PERMISSION_REQUEST_CODE);
        }
    }
}

次に、取得するために

...
MarshMallowPermission marshMallowPermission = new MarshMallowPermission(this);
...

public void getPhotoFromCamera() {

    if (!marshMallowPermission.checkPermissionForCamera()) {
        marshMallowPermission.requestPermissionForCamera();
    } else {
        if (!marshMallowPermission.checkPermissionForExternalStorage()) {
            marshMallowPermission.requestPermissionForExternalStorage();
        } else {
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File mediaStorageDir = new File(
                    Environment.getExternalStorageDirectory()
                            + File.separator
                            + getString(R.string.directory_name_corp_chat)
                            + File.separator
                            + getString(R.string.directory_name_images)
            );

            if (!mediaStorageDir.exists()) {
                mediaStorageDir.mkdirs();
            }

            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                    Locale.getDefault()).format(new Date());
            try {
                mediaFile = File.createTempFile(
                        "IMG_" + timeStamp,  /* prefix */
                        ".jpg",         /* suffix */
                        mediaStorageDir      /* directory */
                );
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
                startActivityForResult(takePictureIntent, PICK_FROM_CAMERA);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
34
Chintan Soni

引用 developers.Android.com

Android 6.0(APIレベル23)以降、ユーザーはアプリのインストール時ではなく、アプリの実行中にアプリにアクセス許可を付与します。この方法では、アプリのインストールプロセスが合理化されます。アプリをインストールまたは更新するときにアクセス許可を付与する必要があります。また、ユーザーはアプリの機能をより細かく制御できます;たとえば、ユーザーはカメラアプリにカメラへのアクセスを許可しますが、デバイスの場所へのアクセスは許可しません。アプリの設定画面にアクセスして、いつでも権限を取り消すことができます。

システム権限は、通常と危険の2つのカテゴリに分類されます。

  • 通常の許可は、ユーザーのプライバシーを直接危険にさらしません。アプリのマニフェストに通常の許可がリストされている場合、システムは許可を自動的に付与します。

  • 危険なアクセス許可は、アプリにユーザーの機密データへのアクセスを許可します。アプリのマニフェストに通常の許可がリストされている場合、システムは許可を自動的に付与します。危険な許可をリストする場合、ユーザーはアプリに明示的に承認する必要があります。

_WRITE_EXTERNAL_STORAGE_はDangerousカテゴリに属しているため、mediaStorageDir.mkdirs()または_File.createTempFile_を呼び出す前にユーザーに許可を要求する必要があります。そうしないと、この例外でプログラムがクラッシュします。

_W/System.err: Java.io.IOException: open failed: EACCES (Permission denied)
W/System.err:     at Java.io.File.createNewFile(File.Java:939)
W/System.err:     at Java.io.File.createTempFile(File.Java:1004)
W/System.err:     at com.example.MainActivity.getPhotoFromCamera(MainActivity.Java:98)
W/System.err:     at com.example.MainActivity.onCreate(MainActivity.Java:48)
W/System.err:     at Android.app.Activity.performCreate(Activity.Java:6237)
W/System.err:     at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.
W/System.err:     at Android.app.ActivityThread.performLaunchActivity(ActivityThread.
W/System.err:     at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2476
W/System.err:     at Android.app.ActivityThread.-wrap11(ActivityThread.Java)
W/System.err:     at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1344)
W/System.err:     at Android.os.Handler.dispatchMessage(Handler.Java:102)
W/System.err:     at Android.os.Looper.loop(Looper.Java:148)
W/System.err:     at Android.app.ActivityThread.main(ActivityThread.Java:5417)
W/System.err:     at Java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.
W/System.err:     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)
W/System.err: Caused by: Android.system.ErrnoException: open failed: EACCES (Permission 
W/System.err:     at libcore.io.Posix.open(Native Method)
W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.Java:186)
W/System.err:     at Java.io.File.createNewFile(File.Java:932)
W/System.err:   ... 15 more
_
7