Demande de permissions
Demande explicites pour permissions multiples
private ActivityResultLauncher<String[]> 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);
Requesting runtime permissions using new ActivityResult API 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.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.androidusbhost" android:versionCode="1" android:versionName="1.0" > <application <activity <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> </intent-filter> </activity> </application> </manifest>
- Filtrer les devices USB autorisés dans
app\src\main\res\xml\device_filter.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Accept all device VID/PID combinations --> <usb-device /> </resources>
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.Getting a result from an activity Archive du 20/09/2022 le 17/01/2023
private ActivityResultLauncher<Intent> 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().
Creating a custom contract 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 embarquer dans l'apk.
Removed execute permission for app home directory Archive du 19/09/2022 le 27/09/2022