====Demande de permissions====
===Demande explicites pour permissions multiples===
private ActivityResultLauncher
[[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}}