I'm trying to set up a way to register permission result handlers after the activity is initialized, by creating a Map<Integer, Runnable>
to hold the handlers, when I request permission I use a randomly generated code and save a runnable to the Map of codes/handlers.
Here's what I have so far in my activity class
private final HashMap<Integer, Runnable> onPermission = new HashMap<>();
//i call this from other classes to ask for a permission and register a handler
public void requestPermission(Runnable onGranted, String...permissions) {
int code = Permissions.permissionRequestCode();
onPermission.put(code, onGranted);
requestPermissions(permissions, code);
}
//overriding this method to check if the Map has a handler for the granted request
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Runnable handler = onPermission.get(requestCode);
if (handler != null && isGranted(grantResults)) {
handler.run();
onPermission.remove(requestCode);
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
//utility method to check if all the requested permissions are granted
private boolean isGranted(int[] results) {
for (int i : results) {
if (i != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
And here is an example of how this can be used, where owner
is an my Activity instance :
private void readImages() {
if (ContextCompat.checkSelfPermission(owner, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
loadImages();
} else {
owner.requestPermission(this::loadImages, Manifest.permission.READ_EXTERNAL_STORAGE);
}
}
Now running this on an actual device (Android 12, API 31), works exactly like I would expect (the request shows, and the handler is executed when the permission is granted), however on the emulator (Android 13, API 33), nothing shows when the permission is requested, and it remains "not granted", the permission doesn't even show in the "App info" even though it's included in the manifest.
Real device :
Emulator :
My manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Mesa"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.Mesa.NoActionBar"
android:usesCleartextTraffic="true">
<activity
android:name=".app.Mesa"
android:configChanges="uiMode|screenSize|colorMode"
android:exported="true"
android:theme="@style/Theme.Mesa.NoActionBar"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
My build.gradle :
android {
compileSdk 33
defaultConfig {
applicationId "org.luke.mesa"
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
proguardFiles 'proguard-rules.pro'
}
buildTypes {
release {
minifyEnabled true
}
debug {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
allprojects {
tasks.withType(JavaCompile){
options.compilerArgs <<"-Xlint:deprecation"
}
}
}
buildFeatures {
viewBinding true
dataBinding true
}
packagingOptions {
resources {
merges += ['META-INF/DEPENDENCIES']
}
}
namespace 'org.luke.mesa'
dependenciesInfo {
includeInApk true
includeInBundle true
}
buildToolsVersion '33.0.0'
}
possible duplicates which didn't solve my problem :
As of Android 13 and above, apps that request READ_EXTERNAL_STORAGE
must instead request one or more of the following more granular permissions:
READ_MEDIA_IMAGES
READ_MEDIA_VIDEO
READ_MEDIA_AUDIO
Reference: https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions