varios studio requestpermissions picture permission permisos pedir multiples example android android-camera android-permissions android-camera-intent android-6.0-marshmallow

studio - Intento de cámara Android M+error de permiso?



request permission android example (9)

Debe habilitar el permiso de la aplicación para el uso de la cámara. Prefiero agregar este método agregar comando que activa la cámara:

public static async Task<bool> HasPermission() { var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Camera); if (status == PermissionStatus.Granted) return true; if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Camera)) { ShowDialogOk("Error", "Please allow access to the camera.");//that is my custom method for allert } var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Camera); status = results[Permission.Camera]; return status == PermissionStatus.Granted; }

Estoy tratando de preparar mi aplicación para los nuevos cambios de permisos de Android M y encontré un comportamiento extraño. Mi aplicación utiliza el mecanismo de intención de la cámara para permitir al usuario obtener una imagen de la cámara. Pero en otra actividad necesita hacer uso de la cámara con el permiso de la cámara (debido a una dependencia de biblioteca card.io que lo requiere).

Sin embargo, con M en la actividad que solo necesita una intención de cámara cuando intento iniciar la intención de Cámara, veo el siguiente bloqueo (esto no sucede si elimino el permiso de Cámara del Manifiesto),

> 09-25 21:57:55.260 774-8053/? I/ActivityManager: START u0 > {act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras)} from uid 10098 on display 0 09-25 > 21:57:55.261 774-8053/? W/ActivityManager: Permission Denial: starting > Intent { act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked > permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/? > E/ResolverActivity: Unable to launch as uid 10098 package > com.example.me.mycamerselectapp, while running in android:ui 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: > java.lang.SecurityException: Permission Denial: starting Intent { > act=android.media.action.IMAGE_CAPTURE flg=0x3000003 > pkg=com.google.android.GoogleCamera > cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity > (has clip) (has extras) } from null (pid=-1, uid=10098) with revoked > permission android.permission.CAMERA 09-25 21:57:55.263 32657-32657/? > E/ResolverActivity: at > android.os.Parcel.readException(Parcel.java:1599) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Parcel.readException(Parcel.java:1552) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.app.ActivityManagerProxy.startActivityAsCaller(ActivityManagerNative.java:2730) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.app.Instrumentation.execStartActivityAsCaller(Instrumentation.java:1725) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.app.Activity.startActivityAsCaller(Activity.java:4047) 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity$DisplayResolveInfo.startAsCaller(ResolverActivity.java:983) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.safelyStartActivity(ResolverActivity.java:772) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.onTargetSelected(ResolverActivity.java:754) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity.onTargetSelected(ChooserActivity.java:305) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ResolverActivity.startSelected(ResolverActivity.java:603) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity.startSelected(ChooserActivity.java:310) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.app.ChooserActivity$ChooserRowAdapter$2.onClick(ChooserActivity.java:990) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > android.view.View.performClick(View.java:5198) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.view.View$PerformClick.run(View.java:21147) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Handler.handleCallback(Handler.java:739) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Handler.dispatchMessage(Handler.java:95) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.os.Looper.loop(Looper.java:148) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > android.app.ActivityThread.main(ActivityThread.java:5417) 09-25 > 21:57:55.263 32657-32657/? E/ResolverActivity: at > java.lang.reflect.Method.invoke(Native Method) 09-25 21:57:55.263 > 32657-32657/? E/ResolverActivity: at > com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) > 09-25 21:57:55.263 32657-32657/? E/ResolverActivity: at > com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 09-25 > 21:57:55.286 1159-1159/? I/Keyboard.Facilitator: onFinishInput() 09-25 > 21:57:55.297 32657-32676/? E/Surface: getSlotFromBufferLocked: unknown > buffer: 0xaec352e0 09-25 21:57:55.344 325-349/? V/RenderScript: > 0xb3693000 Launching thread(s), CPUs 4 09-25 21:57:57.290 325-349/? > E/Surface: getSlotFromBufferLocked: unknown buffer: 0xb3f88240

¿Es este un problema conocido con Android M? Y lo más importante, ¿cómo puedo solucionar esto?

en el manifiesto tengo lo siguiente,

<uses-permission android:name="android.permission.CAMERA" />

y este es el código que uso para permitir que el usuario haga clic en una foto con la cámara y / o seleccione una imagen

public static Intent openImageIntent(Context context, Uri cameraOutputFile) { // Camera. final List<Intent> cameraIntents = new ArrayList<Intent>(); final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); final PackageManager packageManager = context.getPackageManager(); final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0); for(ResolveInfo res : listCam) { final String packageName = res.activityInfo.packageName; final Intent intent = new Intent(captureIntent); intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); intent.setPackage(packageName); intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraOutputFile); cameraIntents.add(intent); } // Filesystem. final Intent galleryIntent = new Intent(); galleryIntent.setType("image/*"); galleryIntent.setAction(Intent.ACTION_GET_CONTENT); // Chooser of filesystem options. final Intent chooserIntent = Intent.createChooser(galleryIntent, "Take or select pic"); // Add the camera options. chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{})); return chooserIntent; }

Llamo a openImageIntent() con un clic de botón en mi actividad. Cuando no tengo el permiso CÁMARA en mi aplicación, funciona bien, pero con eso agregado obtengo la excepción publicada anteriormente.

@Override public void onClick(View v) { Intent picCaptureIntenet = openImageIntent(MainActivity.this, getTempImageFileUri(MainActivity.this)); try { startActivityForResult(picCaptureIntenet, 100); } catch(Exception e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }


En cuanto a su pregunta ''¿Es este un problema conocido en M?'' Un desarrollador de Google respondió a alguien que informaba este problema como un error.

Ver aquí: https://code.google.com/p/android/issues/detail?id=188073&q=label%3APriority-Medium&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&start=100

Aquí está la palabra del tipo de Google: “Este es un comportamiento intencionado para evitar la frustración del usuario cuando revocó el permiso de la cámara de una aplicación y la aplicación aún puede tomar fotos a través de la intención. Los usuarios no saben que la foto tomada después de la revocación del permiso se realiza a través de un mecanismo diferente y cuestionarían la exactitud del modelo de permiso. Esto se aplica a MediaStore.ACTION_IMAGE_CAPTURE, MediaStore.ACTION_VIDEO_CAPTURE y Intent.ACTION_CALL los documentos para los cuales se documenta el cambio de comportamiento para las aplicaciones dirigidas a M. "

Dado que a Google no le importa abstraer la mecánica del uso de la cámara de su usuario, también podría activar estratégicamente la primera solicitud de permiso de la cámara y hacer referencia a la funcionalidad de la Actividad que utiliza la Cámara como su razonamiento para la solicitud. Si permite que su aplicación realice primero esta solicitud de permiso cuando el usuario simplemente está intentando tomar una foto, el usuario puede pensar que su aplicación se está comportando de manera extraña, ya que tomar una foto generalmente no requiere otorgar permiso.


Es un poco tarde. Pero quiero agregar una cosa más. siempre que llame a métodos que contengan funcionalidad de cámara, úselos en try catch block. de lo contrario, la aplicación se bloqueará en algunos dispositivos como Moto G4 plus o one plus.

private static final int CAMERA_REQUEST_CODE = 10; //TODO add camera opening functionality here. try { captureImage(); Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); startActivityForResult(intent,CAMERA_REQUEST_CODE); } catch (Exception e){ e.printStackTrace(); } private void captureImage(){ if( ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(new String[]{android.Manifest.permission.CAMERA}, CAMERA_REQUEST_CODE); } else { // Open your camera here. } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == CAMERA_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Now user should be able to use camera } else { // Your app will not have this permission. Turn off all functions // that require this permission or it will force close like your // original question } } }

PD: asegúrese de no copiar y pegar el método anulado.


Este método mío no comprueba solo la cámara, sino todos los permisos requeridos por mi aplicación durante el inicio ... Tengo esto en mi archivo Helper.java, también tenga en cuenta que para el cuadro de diálogo estoy usando esta biblioteca: https://github.com/afollestad/material-dialogs

///check camera permission public static boolean hasPermissions(final Activity activity){ //add your permissions here String[] AppPermissions = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; //ungranted permissions ArrayList<String> ungrantedPerms = new ArrayList<String>(); //loop //lets set a boolean of hasUngrantedPerm to false Boolean needsPermRequest = false; //permissionGranted int permGranted = PackageManager.PERMISSION_GRANTED; //permission required content String permRequestStr = activity.getString(R.string.the_following_perm_required); //loop for(String permission : AppPermissions){ //check if perm is granted int checkPerm = ContextCompat.checkSelfPermission(activity,permission); //if the permission is not granted if(ContextCompat.checkSelfPermission(activity,permission) != permGranted){ needsPermRequest = true; //add the permission to the ungranted permission list ungrantedPerms.add(permission); //permssion name String[] splitPerm = permission.split(Pattern.quote(".")); String permName = splitPerm[splitPerm.length-1].concat("/n"); permRequestStr = permRequestStr.concat(permName); }//end if }//end loop //if all permission is granted end exec //then continue code exec if(!needsPermRequest) { return true; }//end if //convert array list to array string final String[] ungrantedPermsArray = ungrantedPerms.toArray(new String[ungrantedPerms.size()]); //show alert Dialog requesting permission new MaterialDialog.Builder(activity) .title(R.string.permission_required) .content(permRequestStr) .positiveText(R.string.enable) .negativeText(R.string.cancel) .onPositive(new MaterialDialog.SingleButtonCallback(){ @Override public void onClick(@NonNull MaterialDialog dialog,@NonNull DialogAction which){ //request the permission now ActivityCompat.requestPermissions(activity,ungrantedPermsArray,0); } }) .show(); //return false so that code exec in that script will not be allowed //to continue return false; }//end checkPermissions

así que agregará o eliminará sus listas de permisos aquí:

//add your permissions here String[] AppPermissions = { Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };

En mi archivo de actividad verifico el permiso de esta manera, la clase Helper es donde guardé el método hasPermissions

if(Helper.hasPermissions(this) == false){ return; }//end if

Significa que no necesitamos continuar la ejecución si no se otorga ningún permiso. Una vez más, tendremos que escuchar la solicitud de permiso una vez que haya finalizado, para ello, agregue el siguiente código a su archivo de actividad (opcional)

//Listen to Permission request completion //put in your activity file @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { int permGranted = PackageManager.PERMISSION_GRANTED; Boolean permissionRequired = false; for(int perm : grantResults){ if(perm != permGranted){ permissionRequired = true; } } //if permission is still required if(permissionRequired){ //recheck and enforce permission again Helper.hasPermissions(this); }//end if }//end method


Me quedé atrapado en este problema y ya estaba usando la respuesta de JTY. El problema es que en algún momento el cuadro de diálogo de permiso de solicitud se verificó en "Nunca volver a preguntar". Estoy desarrollando en SDK 24.

Mi código completo para manejar los permisos (la cámara en mi caso) fue el siguiente:

public void checksCameraPermission(View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Log.d("MyApp", "SDK >= 23"); if (this.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { Log.d("MyApp", "Request permission"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_REQUEST_CODE); if (! shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { showMessageOKCancel("You need to allow camera usage", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(FotoPerfil.this, new String[] {Manifest.permission.CAMERA}, MY_REQUEST_CODE); } }); } } else { Log.d("MyApp", "Permission granted: taking pic"); takePicture(); } } else { Log.d("MyApp", "Android < 6.0"); } }

entonces

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(this) .setMessage(message) .setPositiveButton("OK", okListener) .setNegativeButton("Cancel", null) .create() .show(); }

y entonces

@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_REQUEST_CODE: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { criarFoto(); } else { Toast.makeText(this, "You did not allow camera usage :(", Toast.LENGTH_SHORT).show(); noFotoTaken(); } return; } } }

El comportamiento previsto es que, en caso de que el usuario, por error, haya marcado "Nunca preguntar de nuevo", su aplicación se atasque (no se muestra el Diálogo de solicitud) y el usuario puede sentirse frustrado. De esta manera, un mensaje le dice que necesita este permiso.


Quite:

uses-permission android:name="android.permission.CAMERA"

y solo se basó en:

uses-feature android:name="android.hardware.camera" android:required="true"

en el archivo de manifiesto.


Si está utilizando Google M, vaya a Configuración -> Aplicaciones -> su aplicación -> y otorgue los permisos correspondientes.


Si está utilizando el modelo de permiso de Android M, primero debe verificar si la aplicación tiene este permiso durante el tiempo de ejecución y debe solicitar al usuario este permiso durante el tiempo de ejecución. El permiso que defina en su manifiesto no se otorgará automáticamente en el momento de la instalación.

if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_REQUEST_CODE); }

MY_REQUEST_CODE es una constante estática que puede definir, que se usará nuevamente para la devolución de llamada del diálogo requestPermission.

Necesitará una devolución de llamada para el resultado del diálogo:

@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_REQUEST_CODE) { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Now user should be able to use camera } else { // Your app will not have this permission. Turn off all functions // that require this permission or it will force close like your // original question } } }

editar

Al leer el seguimiento de la pila, parece que Google Camera no tiene habilitado el permiso CAMERA. Esto podría parecer una compatibilidad con versiones anteriores después de todo.

Supongamos que Google Camera (o cualquier otra aplicación que maneje su intención de ACCIÓN) requiere un cierto permiso.

Cuando su aplicación no tiene el permiso CÁMARA, solo está dejando que Google Camera haga lo suyo con el modelo de permisos anterior.

Sin embargo, con el permiso CAMERA declarado en su manifiesto, también está aplicando el permiso CAMERA dentro de Google Camera (que no tiene el modelo de permisos Android M) para usar el modelo de permisos Android M (creo).

Entonces, eso significa que utilizando el método anterior, deberá proporcionar el permiso de su aplicación durante el tiempo de ejecución, lo que significa que su tarea secundaria (en este caso, Google Camera) ahora también tendrá ese permiso.


Tuve el mismo problema y encuentro este documento de google: https://developer.android.com/reference/android/provider/MediaStore.html#ACTION_IMAGE_CAPTURE

"Nota: si su aplicación se dirige a M y superiores y declara que usa el permiso CAMERA que no se otorga, entonces intentar usar esta acción dará como resultado una excepción de seguridad".

Esto es muy extraño. No tiene sentido en absoluto. La aplicación declara el permiso de la cámara utilizando la intención con la acción IMAGE_CAPTURE solo se ejecuta en SecurityException. Pero si su aplicación no declara el permiso de la cámara utilizando la intención con la acción IMAGE_CAPTURE puede iniciar la aplicación de la cámara sin problemas.

La solución alternativa sería verificar si la aplicación tiene permiso de cámara incluido en el manifiesto, si es así, solicite permiso de cámara antes de iniciar el intento.

Esta es la forma de verificar si el permiso está incluido en el manifiesto, no importa si el permiso se otorga o no.

public boolean hasPermissionInManifest(Context context, String permissionName) { final String packageName = context.getPackageName(); try { final PackageInfo packageInfo = context.getPackageManager() .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); final String[] declaredPermisisons = packageInfo.requestedPermissions; if (declaredPermisisons != null && declaredPermisisons.length > 0) { for (String p : declaredPermisisons) { if (p.equals(permissionName)) { return true; } } } } catch (NameNotFoundException e) { } return false; }