studio permission_granted permission permisos dar camara almacenamiento android permissions android-6.0-marshmallow

permission_granted - permisos android studio gps



Permisos de Android M: Confundido sobre el uso de la función shouldShowRequestPermissionRationale() (11)

¿Podemos hacerlo de esta manera?

@Retention(RetentionPolicy.SOURCE) @IntDef({GRANTED, DENIED, NEVER}) public @interface PermissionStatus { } public static final int GRANTED = 0; public static final int DENIED = 1; public static final int NEVER = 2; @PermissionStatus public static int getPermissionStatus(Activity activity, String permission) { if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { return DENIED; } else { if (ActivityCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED) { return GRANTED; } else { return NEVER; } } }

Estaba revisando el documento oficial sobre el nuevo modelo de permisos en Android M. Habla sobre la función shouldShowRequestPermissionRationale() que devuelve true si la aplicación ha solicitado este permiso anteriormente y el usuario rechazó la solicitud. Si el usuario rechazó la solicitud de permiso en el pasado y eligió la opción No volver a preguntar, este método devuelve false .

Pero, ¿cómo podemos diferenciar entre los siguientes dos casos?

Caso 1 : la aplicación no tiene permiso y no se le ha pedido permiso al usuario antes. En este caso, shouldShowRequestPermissionRationale () devolverá false porque es la primera vez que le preguntamos al usuario.

Caso 2 : el usuario ha denegado el permiso y ha seleccionado "No volver a preguntar", en este caso también shouldShowRequestPermissionRationale () devolverá false.

Me gustaría enviar al usuario a la página de configuración de la aplicación en el Caso 2. ¿Cómo hago para diferenciar estos dos casos?


ACTUALIZAR

Creo que la answer de CanC a continuación es la correcta que debe seguirse. La única forma de saberlo con certeza es verificar esto en la devolución de llamada onRequestPermissionResult usando shouldShowPermissionRationale.

==

Mi respuesta original:

La única manera que he encontrado es hacer un seguimiento por su cuenta de si es la primera vez o no (por ejemplo, usando preferencias compartidas). Si no es la primera vez, use shouldShowRequestPermissionRationale() para diferenciar.

Ver también: Android M: verifique el permiso de tiempo de ejecución: ¿cómo determinar si el usuario marcó "Nunca preguntar de nuevo"?


Después de M Vista previa 1, si el cuadro de diálogo se muestra por primera vez , no hay ninguna casilla de verificación Preguntar nunca más .

Si el usuario rechaza la solicitud de permiso, habrá una casilla de verificación Nunca preguntar nuevamente en el cuadro de diálogo de permisos la segunda vez que se solicite el permiso.

Entonces la lógica debería ser así:

  1. Pedir permiso:

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE); } else { //Do the stuff that requires permission... }

  2. Compruebe si el permiso fue denegado o concedido en onRequestPermissionsResult .

    Si el permiso fue denegado anteriormente, esta vez habrá una casilla de verificación Nunca preguntar nuevamente en el cuadro de diálogo de permisos.

    Llame a shouldShowRequestPermissionRationale para ver si el usuario marcó No preguntar nunca más . shouldShowRequestPermissionRationale método shouldShowRequestPermissionRationale devuelve falso solo si el usuario seleccionó Nunca preguntar de nuevo o la política del dispositivo prohíbe que la aplicación tenga ese permiso:

    if (grantResults.length > 0){ if(grantResults[0] == PackageManager.PERMISSION_GRANTED) { //Do the stuff that requires permission... }else if (grantResults[0] == PackageManager.PERMISSION_DENIED){ // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { //Show permission explanation dialog... }else{ //Never ask again selected, or device policy prohibits the app from having that permission. //So, disable that feature, or fall back to another situation... } } }

Por lo tanto, no tendrá que rastrear si un usuario marcó Nunca preguntar de nuevo o no.


Este código le pide al usuario que pida permiso durante el tiempo de ejecución, si el usuario lo permite, ejecuta el método de resultado, si el usuario lo niega, vuelve a preguntar con la descripción con el usuario denegar (pregunta nuevamente con instrucciones), pero si el usuario elige, nunca pregunte nuevamente maneja no preguntar nunca más, muestra la opción de configuración abierta con instrucciones.

public String storagePermissions = Manifest.permission.READ_EXTERNAL_STORAGE; private static final int REQUEST_ACCESS =101; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(checkSelfPermission(storagePermissions)== PackageManager.PERMISSION_GRANTED){ result(); // result is your block of code }else { requestPermissions(new String[]{storagePermissions},REQUEST_ACCESS); } } else{ result(); //so if user is lower than api verison M, no permission is requested } } private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) { new AlertDialog.Builder(MainActivity.this) .setMessage(message) .setTitle("Hi User..") .setPositiveButton("Ok", okListener) .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //idea calling showMessage funtion again Snackbar mySnackbar = Snackbar.make( findViewById(R.id.coordinatorlayout),"You Press Cancel.. ", Snackbar.LENGTH_INDEFINITE); mySnackbar.setAction("Exit", new cancelButton()); mySnackbar.show(); } }) .create() .show(); } private void result(){ //your code } @RequiresApi(api = Build.VERSION_CODES.M) public class NeverAskAgain implements View.OnClickListener{ @Override public void onClick(View view) { goToSettings(); } } @RequiresApi(api = Build.VERSION_CODES.M) private void goToSettings() { Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName())); finish(); myAppSettings.addCategory(Intent.CATEGORY_DEFAULT); myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(myAppSettings, REQUEST_APP_SETTINGS); } public class cancelButton implements View.OnClickListener{ @Override public void onClick(View view){ Toast.makeText(MainActivity.this,"To use this app , you must grant storage permission",Toast.LENGTH_SHORT); finish(); } } @Override @RequiresApi(api = Build.VERSION_CODES.M) public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode,permissions,grantResults); switch(requestCode) { case REQUEST_ACCESS: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission is granted result(); break; } else if (!shouldShowRequestPermissionRationale(permissions[0])){ showMessageOKCancel("You choose Never Ask Again,option", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Snackbar mySnackbar = Snackbar.make(findViewById(R.id.coordinatorlayout), "Permission=>Storage=>On", Snackbar.LENGTH_INDEFINITE); mySnackbar.setAction("Settings", new NeverAskAgain()); mySnackbar.show(); } }); break; } else { showMessageOKCancel("You Denid permission Request..", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { requestPermissions(new String[]{storagePermissions}, REQUEST_ACCESS); } }); break; } } }


Puede ser útil para alguien: -

Lo que he notado es que si marcamos el indicador shouldShowRequestPermissionRationale () en el método de devolución de llamada onRequestPermissionsResult (), muestra solo dos estados.

Estado 1: -Return true: - Cada vez que el usuario hace clic en Denegar permisos (incluida la primera vez).

Estado 2: - Devuelve falso: - si el usuario selecciona "nunca pregunta de nuevo".

Enlace para un ejemplo de trabajo detallado .


Según tengo entendido, shouldShowRequestPermissionRationale () ejecuta una serie de casos de uso bajo el capó, y notifica a la aplicación si mostrar o no una explicación sobre los permisos solicitados.

La idea detrás de los permisos de Tiempo de ejecución es que la mayoría de las veces, el usuario dirá Sí a la solicitud de permiso. De esta forma, el usuario tendrá que hacer solo un clic. Por supuesto, la solicitud debe usarse en el contexto correcto, es decir, solicitar el permiso de la Cámara cuando se presiona el botón "Cámara".

Si el usuario rechaza la solicitud, pero después de un tiempo aparece y presiona el botón "Cámara" nuevamente, shouldShowRequestPermissionRationale () volverá verdadero, por lo que la aplicación puede mostrar una explicación significativa de por qué se solicita el permiso y por qué no funciona correctamente sin ella. Normalmente mostraría en esa ventana de diálogo un botón para negar / decidir más tarde, y un botón para otorgar los permisos. El botón de otorgar permisos en el cuadro de diálogo de justificación, debe iniciar la solicitud de permiso nuevamente. Esta vez, el usuario también tendrá la casilla de verificación "Nunca volver a mostrar". Si decide seleccionarlo y volver a denegar el permiso, notificará al sistema Android que el usuario y la aplicación no están en la misma página. Esa acción tendría dos consecuencias: shouldShowRequestPermissionRationale () siempre devolverá false, y el método requestPermissions () no mostrará ningún diálogo, pero devolverá directamente denegado a la devolución de llamada onRequestPermissionsResult.

Pero también hay otro posible escenario en el que onRequestPermissionsResult podría usarse. Por ejemplo, algunos dispositivos pueden tener una política de dispositivos que deshabilita la cámara (funciona para CIA, DARPA, etc.). En estos dispositivos, onRequestPermissionsResult siempre devolverá falso, y el método requestPermissions () denegará silenciosamente la solicitud.

Eso es lo que obtuve al escuchar el podcast con Ben Poiesz, un gerente de producto en el marco de Android.
http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html


Si alguien está interesado en una solución de Kotlin, refactoré la respuesta de @muthuraj para estar en Kotlin. También se modernizó un poco para tener un bloque de finalización en lugar de oyentes.

Permiso hasta

object PermissionUtil { private val PREFS_FILE_NAME = "preference" fun firstTimeAskingPermission(context: Context, permission: String, isFirstTime: Boolean) { val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE) sharedPreference.preferences.edit().putBoolean(permission, isFirstTime).apply() } fun isFirstTimeAskingPermission(context: Context, permission: String): Boolean { val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE) return sharedPreference.preferences.getBoolean(permission, true) } }

Permiso Manejador

enum class CheckPermissionResult { PermissionAsk, PermissionPreviouslyDenied, PermissionDisabled, PermissionGranted } typealias PermissionCheckCompletion = (CheckPermissionResult) -> Unit object PermissionHandler { private fun shouldAskPermission(context: Context, permission: String): Boolean { return ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED } fun checkPermission(context: Context, permission: String, completion: PermissionCheckCompletion) { // If permission is not granted if (shouldAskPermission(context, permission)) { //If permission denied previously if ((context as Activity).shouldShowRequestPermissionRationale(permission)) { completion(CheckPermissionResult.PermissionPreviouslyDenied) } else { // Permission denied or first time requested if (PermissionUtil.isFirstTimeAskingPermission(context, permission)) { PermissionUtil.firstTimeAskingPermission(context, permission, false) completion(CheckPermissionResult.PermissionAsk) } else { // Handle the feature without permission or ask user to manually allow permission completion(CheckPermissionResult.PermissionDisabled) } } } else { completion(CheckPermissionResult.PermissionGranted) } } }

Implementación

PermissionHandler.checkPermission(activity, Manifest.permission.CAMERA) { result -> when (result) { CheckPermissionResult.PermissionGranted -> { // openCamera() } CheckPermissionResult.PermissionDisabled -> { // displayAlert(noPermissionAlert) } CheckPermissionResult.PermissionAsk -> { // requestCameraPermissions() } CheckPermissionResult.PermissionPreviouslyDenied -> { // displayAlert(permissionRequestAlert) } } }


Simplemente publique otra opción, si alguien puede sentirlo. Puede usar EasyPermissions que fue proporcionado por el propio Google, para, como se dijo, "Simplificar los permisos del sistema Android M".

Entonces no tiene que manejar shouldShowRequestPermissionRationale directamente.


Tuve el mismo problema y lo resolví. Para simplificar la vida, escribí una clase util para manejar los permisos de tiempo de ejecución.

public class PermissionUtil { /* * Check if version is marshmallow and above. * Used in deciding to ask runtime permission * */ public static boolean shouldAskPermission() { return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M); } private static boolean shouldAskPermission(Context context, String permission){ if (shouldAskPermission()) { int permissionResult = ActivityCompat.checkSelfPermission(context, permission); if (permissionResult != PackageManager.PERMISSION_GRANTED) { return true; } } return false; } public static void checkPermission(Context context, String permission, PermissionAskListener listener){ /* * If permission is not granted * */ if (shouldAskPermission(context, permission)){ /* * If permission denied previously * */ if (((Activity) context).shouldShowRequestPermissionRationale(permission)) { listener.onPermissionPreviouslyDenied(); } else { /* * Permission denied or first time requested * */ if (PreferencesUtil.isFirstTimeAskingPermission(context, permission)) { PreferencesUtil.firstTimeAskingPermission(context, permission, false); listener.onPermissionAsk(); } else { /* * Handle the feature without permission or ask user to manually allow permission * */ listener.onPermissionDisabled(); } } } else { listener.onPermissionGranted(); } } /* * Callback on various cases on checking permission * * 1. Below M, runtime permission not needed. In that case onPermissionGranted() would be called. * If permission is already granted, onPermissionGranted() would be called. * * 2. Above M, if the permission is being asked first time onPermissionAsk() would be called. * * 3. Above M, if the permission is previously asked but not granted, onPermissionPreviouslyDenied() * would be called. * * 4. Above M, if the permission is disabled by device policy or the user checked "Never ask again" * check box on previous request permission, onPermissionDisabled() would be called. * */ public interface PermissionAskListener { /* * Callback to ask permission * */ void onPermissionAsk(); /* * Callback on permission denied * */ void onPermissionPreviouslyDenied(); /* * Callback on permission "Never show again" checked and denied * */ void onPermissionDisabled(); /* * Callback on permission granted * */ void onPermissionGranted(); } }

Y los métodos PreferenceUtil son los siguientes.

public static void firstTimeAskingPermission(Context context, String permission, boolean isFirstTime){ SharedPreferences sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE; sharedPreference.edit().putBoolean(permission, isFirstTime).apply(); } public static boolean isFirstTimeAskingPermission(Context context, String permission){ return context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE).getBoolean(permission, true); }

Ahora, todo lo que necesita es usar el método checkPermission con los argumentos adecuados.

Aquí hay un ejemplo,

PermissionUtil.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE, new PermissionUtil.PermissionAskListener() { @Override public void onPermissionAsk() { ActivityCompat.requestPermissions( thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_EXTERNAL_STORAGE ); } @Override public void onPermissionPreviouslyDenied() { //show a dialog explaining permission and then request permission } @Override public void onPermissionDisabled() { Toast.makeText(context, "Permission Disabled.", Toast.LENGTH_SHORT).show(); } @Override public void onPermissionGranted() { readContacts(); } });

Caso 1: la aplicación no tiene permiso y no se le ha pedido permiso al usuario antes. En este caso, shouldShowRequestPermissionRationale () devolverá false porque es la primera vez que le preguntamos al usuario.

Caso 2: el usuario ha denegado el permiso y ha seleccionado "No volver a preguntar", en este caso también shouldShowRequestPermissionRationale () devolverá false.

Me gustaría enviar al usuario a la página de configuración de la aplicación en el Caso 2. ¿Cómo hago para diferenciar estos dos casos?

Recibirá devolución de llamada en onPermissionAsk para el caso 1 y onPermissionDisabled para el caso 2.

Feliz codificación :)


Verifica esta implementación. Funciona bastante bien para mí. básicamente verifica los permisos en el método checkPermissions () pasando una lista de permisos. Comprueba el resultado de la solicitud de permiso en onRequestPermissionsResult (). La implementación le permite abordar ambos casos cuando el usuario selecciona "nunca preguntar de nuevo" o no. En esta implementación, en caso de que seleccione "nunca preguntar de nuevo", el cuadro de diálogo tiene una opción para llevarlo a la Actividad de configuración de la aplicación.

Todo este código está dentro de mi fragmento. Estaba pensando que sería mejor crear una clase especializada para hacer esto, como un PermissionManager, pero no estoy seguro de eso.

/** * responsible for checking if permissions are granted. In case permissions are not granted, the user will be requested and the method returns false. In case we have all permissions, the method return true. * The response of the request for the permissions is going to be handled in the onRequestPermissionsResult() method * @param permissions list of permissions to be checked if are granted onRequestPermissionsResult(). * @param requestCode request code to identify this request in * @return true case we already have all permissions. false in case we had to prompt the user for it. */ private boolean checkPermissions(List<String> permissions, int requestCode) { List<String> permissionsNotGranted = new ArrayList<>(); for (String permission : permissions) { if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) permissionsNotGranted.add(permission); } //If there is any permission we don''t have (it''s going to be in permissionsNotGranted List) , we need to request. if (!permissionsNotGranted.isEmpty()) { requestPermissions(permissionsNotGranted.toArray(new String[permissionsNotGranted.size()]), requestCode); return false; } return true; } /** * called after permissions are requested to the user. This is called always, either * has granted or not the permissions. * @param requestCode int code used to identify the request made. Was passed as parameter in the * requestPermissions() call. * @param permissions Array containing the permissions asked to the user. * @param grantResults Array containing the results of the permissions requested to the user. */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case YOUR_REQUEST_CODE: { boolean anyPermissionDenied = false; boolean neverAskAgainSelected = false; // Check if any permission asked has been denied for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { anyPermissionDenied = true; //check if user select "never ask again" when denying any permission if (!shouldShowRequestPermissionRationale(permissions[i])) { neverAskAgainSelected = true; } } } if (!anyPermissionDenied) { // All Permissions asked were granted! Yey! // DO YOUR STUFF } else { // the user has just denied one or all of the permissions // use this message to explain why he needs to grant these permissions in order to proceed String message = ""; DialogInterface.OnClickListener listener = null; if (neverAskAgainSelected) { //This message is displayed after the user has checked never ask again checkbox. message = getString(R.string.permission_denied_never_ask_again_dialog_message); listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //this will be executed if User clicks OK button. This is gonna take the user to the App Settings startAppSettingsConfigActivity(); } }; } else { //This message is displayed while the user hasn''t checked never ask again checkbox. message = getString(R.string.permission_denied_dialog_message); } new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme) .setMessage(message) .setPositiveButton(getString(R.string.label_Ok), listener) .setNegativeButton(getString(R.string.label_cancel), null) .create() .show(); } } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } /** * start the App Settings Activity so that the user can change * settings related to the application such as permissions. */ private void startAppSettingsConfigActivity() { final Intent i = new Intent(); i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); i.addCategory(Intent.CATEGORY_DEFAULT); i.setData(Uri.parse("package:" + getActivity().getPackageName())); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); getActivity().startActivity(i); }


shouldShowRequestPermissionRationale para permisos ESPECIALES siempre devuelve VERDADERO SOLAMENTE después de que el usuario lo haya denegado sin casilla de verificación

Estamos interesados ​​en el valor FALSO

Entonces hay 3 casos perdidos con valor falso :

1. no hubo tal acción anteriormente y ahora el usuario decide aceptar o negar.

Simplemente defina una preferencia ASKED_PERMISSION_* que no existe ahora y que sería verdadera en onRequestPermissionsResult en su inicio en caso de aceptar o rechazar

Entonces, aunque esta preferencia no existe, no hay razón para verificar shouldShowRequestPermissionRationale

2. el usuario hizo clic en aceptar.

Simplemente haz:

checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

Lo que devolverá verdadero y no hay razón para verificar shouldShowRequestPermissionRationale

3. el usuario hizo clic en Denegar con casilla de verificación (segundo o más tiempo solicitado)

Es EL MOMENTO de trabajar con shouldShowRequestPermissionRationale que devolverá FALSE

(existe preferencia y no tenemos permiso)