Reputation: 51
In the Android 14 release, there is a new permission:
This new permission has a new dialog with the following options:
https://developer.android.com/about/versions/14/changes/partial-photo-video-access
Note: If your app already uses the photo picker, you don't need to take any action to support this change. Otherwise, consider using the photo picker instead of adopting this change.
When I try to implement the photo picker and test myapp.
Step 1: Request permission: "READ_MEDIA_IMAGES", "READ_MEDIA_VISUAL_USER_SELECTED"
Step 2: I select "Select photos and videos"
Step 3: Select a few photos -> Allow
Result: The PhotoPicker still displays all media content on the device instead of only displaying media content that has been granted permission.
Am I misunderstanding or is there a problem with my code?
If I don't understand correctly, what is the actual behavior? What should I do with it?
Everyone please let me know. Thanks.
I implemented the photo picker in two cases and got the same results. Here is my code:
Case 1 uses Intent:
public class MainActivity extends AppCompatActivity {
ImageView imageView;
Button takePictureButton;
int RESULT_CODE = 0;
int REQUEST_CODE = 1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.img);
takePictureButton = findViewById(R.id.btn_take_picture);
takePictureButton.setOnClickListener(view -> {
if (android.os.Build.VERSION.SDK_INT == 34) {
int result14 = this.checkSelfPermission(READ_MEDIA_VISUAL_USER_SELECTED);
boolean hasReadMediaPermissionAndroid14 = PackageManager.PERMISSION_GRANTED == result14;
if (hasReadMediaPermissionAndroid14) {
Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES);
intent.setType("image/*");
startActivityForResult(intent, RESULT_CODE);
} else {
requestPermissions(new String[] {READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED}, REQUEST_CODE);
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data != null) {
imageView.setImageURI(data.getData());
}
}
}
Case 2 follows the instructions in the documentation Photo picker:
public class MainActivity extends AppCompatActivity {
ImageView imageView;
Button takePictureButton;
int REQUEST_CODE = 1;
ActivityResultLauncher<PickVisualMediaRequest> pickMedia =
registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), uri -> {
if (uri != null) {
imageView.setImageURI(uri);
Log.d("PhotoPicker", "Selected URI: " + uri);
} else {
Log.d("PhotoPicker", "No media selected");
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.img);
takePictureButton = findViewById(R.id.btn_take_picture);
takePictureButton.setOnClickListener(view -> {
if (android.os.Build.VERSION.SDK_INT == 34) {
int result14 = this.checkSelfPermission(READ_MEDIA_VISUAL_USER_SELECTED);
boolean hasReadMediaPermissionAndroid14 = PackageManager.PERMISSION_GRANTED == result14;
if (hasReadMediaPermissionAndroid14) {
pickMedia.launch(new PickVisualMediaRequest.Builder()
.setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
.build());
} else {
requestPermissions(new String[]{READ_MEDIA_IMAGES, READ_MEDIA_VISUAL_USER_SELECTED}, REQUEST_CODE);
}
}
}
);
}
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/img"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintVertical_bias="0"
android:src="@drawable/img"
tools:ignore="ContentDescription" />
<Button
android:id="@+id/btn_take_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="take picture"
app:layout_constraintTop_toBottomOf="@id/img"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Upvotes: 5
Views: 5343
Reputation: 87
So, I had the same issue, tried to use READ_MEDIA_VISUAL_USER_SELECTED and Photopicker together and it didn't work properly.
Turned out you can use the Photopicker and still omit to use the READ_MEDIA_VISUAL_USER_SELECTED permission: in this case, the Photopicker will still ask grant automatically this permission as you can select only few photos as the photopicker will "hide" all photos informations from the app, and show it to the app only when the photos will be selected.
If you are planning to use a custom photopicker than you will be required to manage manually the READ_MEDIA_VISUAL_USER_SELECTED permission.
Upvotes: 0
Reputation: 11
'READ_MEDIA_VISUAL_USER_SELECTED' need requested alongside READ_MEDIA_IMAGES and/or READ_MEDIA_VIDEO. And if you choose 'select a few photos', the result 'READ_MEDIA_IMAGES' returns denied, and 'READ_MEDIA_VISUAL_USER_SELECTED' granted. Maybe you can check this first.
Upvotes: 1
Reputation: 9292
My five cents:
If your app requests READ_MEDIA_IMAGES and the user confirms then your app can use the classic File class to list files in for instance the DCIM/Camera directory and see all files of the default Camera app.
This is true for Android 14 too.
But if it directly goes for READ_MEDIA_IMAGES and READ_MEDIA_VISUAL_USER_SELECTED and the user selects four files in DCIM/Camera then after that the File.listFiles() function will only list those four files.
In my experience the new permission has nothing to do with PickVisualMedia() or ACTION_GET_CONTENT or ACTION_PICK_IMAGES only with the classic File class.
Well my five cents. I find the documentation pretty obscure too and messed a long while with this.
Upvotes: 0