I’m facing a problem where I can’t collect the images selected by the user after he accepts the permissions by clicking on SELECT PHOTOS AND VIDEOS.
After accepting the partial access permission, Android automatically shows an image picker. However, unfortunately, I could not identify how I can collect these user-selected images.
My codes:
Permission check:
public boolean checkPermission(String permission) {
int statusCode = ContextCompat.checkSelfPermission(this, permission);
return statusCode == PackageManager.PERMISSION_GRANTED;
}
int sdk = Build.VERSION.SDK_INT;
if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (checkPermission(Manifest.permission.READ_MEDIA_IMAGES) || checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)) {
selectImage();
} else {
permissionLauncher.launch(new String[]{
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
});
}
}
After the permissions, I tried to do the following checks:
-
If the user only gave partial access:
READ_MEDIA_IMAGES would be false and READ_MEDIA_VISUAL_USER_SELECTED would be true, then I would search for the photo he selected -
If the user accepted all permissions:
Both READ_MEDIA_IMAGES and READ_MEDIA_VISUAL_USER_SELECTED would be true, so I would show the image selector to him, since in these cases Android 14 does not show it automatically.
permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
boolean permissionsGranted = false;
int sdk = Build.VERSION.SDK_INT;
if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && (!checkPermission(Manifest.permission.READ_MEDIA_IMAGES) && checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED))) {
permissionsGranted = true;
Uri firstImage = selectFirstImageFromMedia();
if (firstImage != null) {
setImageInView(firstImage);
} else {
Toast.makeText(getApplicationContext(), "Selection canceled", Toast.LENGTH_SHORT).show();
}
} else if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && (checkPermission(Manifest.permission.READ_MEDIA_IMAGES) && checkPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED))) {
permissionsGranted = true;
selectImage();
}
if (!permissionsGranted) {
Toast.makeText(this, "The app needs permission.", Toast.LENGTH_SHORT).show();
}
});
Other logics
// Logic to collect the image selected by the user on Android 14 or higher.
pickMedia = registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), uri -> {
if (uri != null) {
setImageInView(uri);
} else {
Toast.makeText(getApplicationContext(), "Selection canceled", Toast.LENGTH_SHORT).show();
}
});
selectFirstImageFromMedia: (Unfortunately they do not work correctly, it seems that the photo returned is always a random one from the chosen ones.)
Refs: https://developer.android.com/about/versions/14/changes/partial-photo-video-access#query-library
private Uri selectFirstImageFromMedia() {
Uri firstImageUri = null;
// Specify only the necessary columns
String[] projection = { MediaStore.MediaColumns._ID };
try (Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, // Columns to retrieve
null, // No WHERE condition
null, // No arguments for WHERE
MediaStore.MediaColumns.DATE_ADDED + " ASC" // Sort by date added
)) {
if (cursor != null && cursor.moveToFirst()) {
// Get the ID of the first image
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID));
// Build the URI of the image using the ID
firstImageUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
}
} catch (Exception e) {
Log.e("Error retrieving image", " Details: selectFirstImageFromMedia: " + e.getMessage());
}
return firstImageUri;
}
selectImage
public void selectImage() {
int sdk = Build.VERSION.SDK_INT;
if (sdk >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
// Image selection logic for Android versions >= 14
pickMedia.launch(new PickVisualMediaRequest.Builder()
.setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
.build());
} else {
// Image selection logic for Android versions <= 13
Intent picIntent = new Intent(Intent.ACTION_GET_CONTENT, null);
picIntent.setType("image/*");
picIntent.putExtra("return_data", true);
onRequestPermissionsResult.launch(picIntent);
}
}
setImageInView
public void setImageInView(Uri uri) {
try {
// Load the bitmap from the URI
Bitmap fullBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
// Resize the bitmap to fit the ImageView
Bitmap bMapScaled = Bitmap.createScaledBitmap(fullBitmap, ib_tirarfoto_placa.getWidth(), ib_tirarfoto_placa.getHeight(), true);
ib_tirarfoto_placa.setImageBitmap(bMapScaled);
// Save the image and get the path of the saved file
checklist.setVehiclePlatePhotoFilePath(saveImage(fullBitmap));
} catch (Exception e) {
Log.e("Error retrieving image", "Details: setImageInView: " + e.getMessage());
}
}
All the logic for checking permissions and collecting images after the user grants full access is working correctly. My only difficulty is in this issue of collecting the image after the selector is launched automatically. Since when it is programmatically I can collect it correctly.
Any help is very welcome! Thank you in advance!