diff --git a/app/build.gradle b/app/build.gradle
index f75f878c8a..9c01bf04b7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,6 +17,7 @@ if (rootProject.file("local.properties").exists())
android {
compileSdkVersion 33
+ compileSdkExtension 4 // https://developer.android.com/guide/sdk-extensions
namespace 'eu.faircode.email'
// https://apilevels.com/
diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java
index b237c9d327..ab29d288fa 100644
--- a/app/src/main/java/eu/faircode/email/FragmentCompose.java
+++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java
@@ -364,10 +364,7 @@ public class FragmentCompose extends FragmentBase {
setTitle(R.string.page_compose);
setSubtitle(getResources().getQuantityString(R.plurals.page_message, 1));
- int max = (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
- ? Integer.MAX_VALUE
- : MediaStore.getPickImagesMaxLimit());
-
+ int max = Helper.hasPhotoPicker() ? MediaStore.getPickImagesMaxLimit() : 20;
pickImages =
registerForActivityResult(new ActivityResultContracts.PickMultipleVisualMedia(max), uris -> {
if (!uris.isEmpty())
@@ -3458,24 +3455,28 @@ public class FragmentCompose extends FragmentBase {
// https://developer.android.com/training/data-storage/shared/photopicker#device-availability
// https://developer.android.com/reference/android/provider/MediaStore#ACTION_PICK_IMAGES
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- boolean photo_picker = prefs.getBoolean("photo_picker", false);
- if (photo_picker) {
- Log.i("Using photo picker");
- pickImages.launch(new PickVisualMediaRequest.Builder()
- .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
- .build());
- } else {
- Log.i("Using file picker");
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.setType("image/*");
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- if (intent.resolveActivity(pm) == null) // GET_CONTENT whitelisted
- noStorageAccessFramework();
- else
- startActivityForResult(Helper.getChooser(context, intent), REQUEST_IMAGE_FILE);
- }
+ boolean photo_picker = prefs.getBoolean("photo_picker", true);
+ if (photo_picker)
+ try {
+ Log.i("Using photo picker");
+ pickImages.launch(new PickVisualMediaRequest.Builder()
+ .setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE)
+ .build());
+ return;
+ } catch (Throwable ex) {
+ Log.e(ex);
+ }
+
+ Log.i("Using file picker");
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setType("image/*");
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
+ if (intent.resolveActivity(pm) == null) // GET_CONTENT whitelisted
+ noStorageAccessFramework();
+ else
+ startActivityForResult(Helper.getChooser(context, intent), REQUEST_IMAGE_FILE);
}
}
diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsBehavior.java b/app/src/main/java/eu/faircode/email/FragmentOptionsBehavior.java
index ca025b0321..362a77e92a 100644
--- a/app/src/main/java/eu/faircode/email/FragmentOptionsBehavior.java
+++ b/app/src/main/java/eu/faircode/email/FragmentOptionsBehavior.java
@@ -62,7 +62,6 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
private SwitchCompat swConversationActionsReplies;
private SwitchCompat swLanguageDetection;
private EditText etDefaultSnooze;
- private SwitchCompat swPhotoPicker;
private SwitchCompat swPull;
private SwitchCompat swAutoScroll;
private SwitchCompat swQuickFilter;
@@ -94,6 +93,7 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
private SwitchCompat swAutoUnflag;
private SwitchCompat swResetImportance;
private SwitchCompat swThreadSentTrash;
+ private SwitchCompat swPhotoPicker;
private SwitchCompat swFlagSnoozed;
private SwitchCompat swAutoImportant;
private SwitchCompat swResetSnooze;
@@ -142,7 +142,6 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
swConversationActionsReplies = view.findViewById(R.id.swConversationActionsReplies);
swLanguageDetection = view.findViewById(R.id.swLanguageDetection);
etDefaultSnooze = view.findViewById(R.id.etDefaultSnooze);
- swPhotoPicker = view.findViewById(R.id.swPhotoPicker);
swPull = view.findViewById(R.id.swPull);
swAutoScroll = view.findViewById(R.id.swAutoScroll);
swQuickFilter = view.findViewById(R.id.swQuickFilter);
@@ -174,6 +173,7 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
swAutoUnflag = view.findViewById(R.id.swAutoUnflag);
swResetImportance = view.findViewById(R.id.swResetImportance);
swThreadSentTrash = view.findViewById(R.id.swThreadSentTrash);
+ swPhotoPicker = view.findViewById(R.id.swPhotoPicker);
swFlagSnoozed = view.findViewById(R.id.swFlagSnoozed);
swAutoImportant = view.findViewById(R.id.swAutoImportant);
swResetSnooze = view.findViewById(R.id.swResetSnooze);
@@ -270,14 +270,6 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
}
});
- swPhotoPicker.setVisibility(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU ? View.GONE : View.VISIBLE);
- swPhotoPicker.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
- prefs.edit().putBoolean("photo_picker", checked).apply();
- }
- });
-
swPull.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@@ -522,6 +514,14 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
}
});
+ swPhotoPicker.setVisibility(Helper.hasPhotoPicker() ? View.VISIBLE : View.GONE);
+ swPhotoPicker.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ prefs.edit().putBoolean("photo_picker", checked).apply();
+ }
+ });
+
swFlagSnoozed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@@ -657,8 +657,6 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
etDefaultSnooze.setText(default_snooze == 1 ? null : Integer.toString(default_snooze));
etDefaultSnooze.setHint("1");
- swPhotoPicker.setChecked(prefs.getBoolean("photo_picker", false));
-
swPull.setChecked(prefs.getBoolean("pull", true));
swAutoScroll.setChecked(prefs.getBoolean("autoscroll", false));
swQuickFilter.setChecked(prefs.getBoolean("quick_filter", false));
@@ -715,6 +713,7 @@ public class FragmentOptionsBehavior extends FragmentBase implements SharedPrefe
swResetImportance.setChecked(prefs.getBoolean("reset_importance", false));
swThreadSentTrash.setChecked(prefs.getBoolean("thread_sent_trash", true));
+ swPhotoPicker.setChecked(prefs.getBoolean("photo_picker", true));
swFlagSnoozed.setChecked(prefs.getBoolean("flag_snoozed", false));
swAutoImportant.setChecked(prefs.getBoolean("auto_important", false));
swResetSnooze.setChecked(prefs.getBoolean("reset_snooze", true));
diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java
index b1a0ebcd5c..ba5f10ea0d 100644
--- a/app/src/main/java/eu/faircode/email/Helper.java
+++ b/app/src/main/java/eu/faircode/email/Helper.java
@@ -62,6 +62,7 @@ import android.os.Looper;
import android.os.Parcel;
import android.os.PowerManager;
import android.os.StatFs;
+import android.os.ext.SdkExtensions;
import android.os.storage.StorageManager;
import android.provider.Browser;
import android.provider.DocumentsContract;
@@ -876,6 +877,12 @@ public class Helper {
return ContextCompat.getSystemService(context.getApplicationContext(), type);
}
+ static boolean hasPhotoPicker() {
+ return (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU ||
+ (Build.VERSION.SDK_INT > Build.VERSION_CODES.R &&
+ SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R) >= 2));
+ }
+
// View
static Integer actionBarHeight = null;
diff --git a/app/src/main/res/layout/fragment_options_behavior.xml b/app/src/main/res/layout/fragment_options_behavior.xml
index 8d2d9aa37d..1a23b7ecea 100644
--- a/app/src/main/res/layout/fragment_options_behavior.xml
+++ b/app/src/main/res/layout/fragment_options_behavior.xml
@@ -204,18 +204,6 @@
app:layout_constraintBottom_toBottomOf="@+id/etDefaultSnooze"
app:layout_constraintStart_toEndOf="@+id/etDefaultSnooze"
app:layout_constraintTop_toTopOf="@+id/etDefaultSnooze" />
-
-
@@ -750,6 +738,18 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
+
+