====Demande de permissions==== ===Demande explicites pour permissions multiples=== private ActivityResultLauncher requestPermissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestMultiplePermissions(), isGranted -> { if (!isGranted.containsValue(false)) { // Tous les accès sont bons. } } ); String[] ask_permission = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}; requestPermissionLauncher.launch(ask_permission); [[https://medium.com/@ajinkya.kolkhede1/requesting-runtime-permissions-using-new-activityresult-api-cb6116551f00|Requesting runtime permissions using new ActivityResult API]] {{ :lang:android:permission:requesting_runtime_permissions_using_new_activityresult_api_by_ajinkya_kolkhede_medium_26_09_2022_09_29_20_.html |Archive du 06/07/2020 le 26/09/2022}} ===Demande d'accès sur événements=== Avec quelques spécificités sur l'USB. * Code Kotlin private lateinit var mPermissionIntent: PendingIntent private lateinit var mUsbManager: UsbManager private val ACTION_USB_PERMISSION = "com.class.name.USB_PERMISSION" private val mUsbReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) if (device == null) { return } when (intent.action) { ACTION_USB_PERMISSION -> { synchronized(this) { if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { } else { // Denied } } } UsbManager.ACTION_USB_DEVICE_ATTACHED -> { if (!mUsbManager.hasPermission(device)) { mUsbManager.requestPermission(device, mPermissionIntent) } else { // Denied } } UsbManager.ACTION_USB_DEVICE_DETACHED -> { // Detached } } } } override fun onCreate(savedInstanceState: Bundle?) { mUsbManager = getSystemService(Context.USB_SERVICE) as UsbManager mPermissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0); val filter = IntentFilter() filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED) filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED) filter.addAction(ACTION_USB_PERMISSION) registerReceiver(mUsbReceiver, filter) } * ''app\src\main\AndroidManifest.xml'' Déclarer la liste des droits nécessaires. * Filtrer les devices USB autorisés dans ''app\src\main\res\xml\device_filter.xml'' ===Permission se demandant via une fenêtre dédiée et non une simple popup=== Exemple avec ''MANAGE_EXTERNAL_STORAGE''. * Avant API 30 Il faut ajouter ''android:requestLegacyExternalStorage=%%"true"%%'' à ''AndroidManifest.xml''. * A partir de l'API 30 Cela se fait en ouvrant une fenêtre dédiée à la modification des droits. On commence par vérifier si on a les droits avant. Puis on vérifie si on a les droits à la fermeture de la fenêtre. Ne pas appelé ''registerForActivityResult'' depuis le constructeur mais depuis ''onCreate''. Si la vue est recréée (''onCreate''), l%%'%%''intent'' est ''unregister''. Il faut donc le ''register'' à nouveau. Le composant ''ActivityResultLauncher'' ne doit pas être appelé depuis ''onCreate'' mais après.
Note: You must call registerForActivityResult() before the fragment or activity is created; you cannot launch the ActivityResultLauncher until the fragment or activity's Lifecycle has reached CREATED.[[https://developer.android.com/training/basics/intents/result|Getting a result from an activity]] {{ :lang:android:permission:getting_a_result_from_an_activity_android_developers_17_01_2023_14_24_47_.html |Archive du 20/09/2022 le 17/01/2023}}
private ActivityResultLauncher requestManageAllFilesLauncher; public void onCreate(Bundle savedInstanceState) requestManageAllFilesLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (Environment.isExternalStorageManager()) { // Accès validé. } } ); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); requestManageAllFilesLauncher.launch(intent); } else { // OK } Message d'erreur si le composant a été ''unregister'' dû à un nouveau cycle de vie : ''java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher with contract androidx.activity.result.contract.ActivityResultContracts$StartActivityForResult@27807b and input Intent { act=android.intent.action.OPEN_DOCUMENT_TREE }. You must ensure the ActivityResultLauncher is registered before calling launch().'' [[https://developer.android.com/training/basics/intents/result#custom|Creating a custom contract]] {{ :lang:android:permission:getting_a_result_from_an_activity_android_developers_26_09_2022_14_58_57_.html |Archive du 20/09/2022 le 26/09/2022}} ===Autorisation avec adb=== Pour les tests, il peut être nécessaire d'activer certaines autorisations sans interaction avec l'utilisateur. adb shell appops set --uid com.package MANAGE_EXTERNAL_STORAGE allow Pour avoir la liste des permissions, lancer : adb shell 'pm list permissions | sort' ====Permission des dossiers==== * Carte SD ou ''/storage/emulated'' Ne doit servir que pour stocker des données. Il n'est pas possible d'y stocker des exécutables. Le dossier est monté en ''noexec''. * Dossier home de l'application ou ''/data/data'' Ne doit servir que pour stocker des données spécifiques à chaque application. Il n'est pas possible d'y stocker des exécutables. Pour exécuter des binaires externes, il faut les [[lang:android:packaging#embarquer_un_executable_pour_l_executer_manuellement|embarquer dans l'apk]]. [[https://developer.android.com/about/versions/10/behavior-changes-10#execute-permission|Removed execute permission for app home directory]] {{ :lang:android:permission:behavior_changes_apps_targeting_api_29_android_developers_27_09_2022_12_40_59_.html |Archive du 19/09/2022 le 27/09/2022}}