diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4a62a24bd..c03ec47b6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,6 +16,7 @@
+
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 9c1530a47..b4c595e89 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -6,4 +6,6 @@
#ff282828
@color/reaction_pill_border
@color/reaction_pill_text_color
+
+ @color/gray95
diff --git a/res/values/themes.xml b/res/values/themes.xml
index d1be60280..39b60ca92 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -198,7 +198,7 @@
- @style/TextSecure.DarkActionBar
- @style/TextSecure.DarkActionBar.TabBar
- @style/ThemeOverlay.AppCompat.Dark
- - @color/gray50
+ - @color/gray78
- @color/text_color_dark_theme
- @color/text_color_secondary_dark_theme
diff --git a/src/org/thoughtcrime/securesms/ConversationListAdapter.java b/src/org/thoughtcrime/securesms/ConversationListAdapter.java
index 8eb5156c1..4b502a301 100644
--- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java
+++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java
@@ -52,7 +52,7 @@ class ConversationListAdapter extends RecyclerView.Adapter {
private static final int MESSAGE_TYPE_INBOX_ZERO = 3;
private final WeakReference context;
- private final @NonNull DcContext dcContext;
+ private @NonNull DcContext dcContext;
private @NonNull DcChatlist dcChatlist;
private final @NonNull GlideRequests glideRequests;
private final @NonNull Locale locale;
@@ -195,7 +195,16 @@ class ConversationListAdapter extends RecyclerView.Adapter {
}
void changeData(@Nullable DcChatlist chatlist) {
- dcChatlist = chatlist == null ? new DcChatlist(0, 0) : chatlist;
+ Context context = this.context.get();
+ if (context == null) {
+ return;
+ }
+ if (chatlist == null) {
+ dcChatlist = new DcChatlist(0, 0);
+ } else {
+ dcChatlist = chatlist;
+ dcContext = DcHelper.getContext(context);
+ }
notifyDataSetChanged();
}
}
diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java
index 20e96ef28..9fdb7e443 100644
--- a/src/org/thoughtcrime/securesms/ConversationListFragment.java
+++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java
@@ -254,6 +254,8 @@ public class ConversationListFragment extends Fragment
@SuppressLint({"StaticFieldLeak", "NewApi"})
private void updateReminders() {
+ // by the time onPostExecute() is asynchronously run, getActivity() might return null, so get the activity here:
+ Activity activity = getActivity();
new AsyncTask() {
@Override
protected Void doInBackground(Context... params) {
@@ -270,7 +272,6 @@ public class ConversationListFragment extends Fragment
@Override
protected void onPostExecute(Void result) {
- Activity activity = ConversationListFragment.this.getActivity();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!Prefs.getBooleanPreference(activity, Prefs.ASKED_FOR_NOTIFICATION_PERMISSION, false)) {
Prefs.setBooleanPreference(activity, Prefs.ASKED_FOR_NOTIFICATION_PERMISSION, true);
@@ -278,7 +279,7 @@ public class ConversationListFragment extends Fragment
.request(Manifest.permission.POST_NOTIFICATIONS)
.ifNecessary()
.onAllGranted(() -> {
- DozeReminder.maybeAskDirectly(getActivity());
+ DozeReminder.maybeAskDirectly(activity);
})
.onAnyDenied(() -> {
final DcContext dcContext = DcHelper.getContext(activity);
@@ -290,10 +291,10 @@ public class ConversationListFragment extends Fragment
.execute();
}
} else {
- DozeReminder.maybeAskDirectly(getActivity());
+ DozeReminder.maybeAskDirectly(activity);
}
}
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, activity);
}
private void handlePinAllSelected() {
diff --git a/src/org/thoughtcrime/securesms/LogViewActivity.java b/src/org/thoughtcrime/securesms/LogViewActivity.java
index 315390b59..db725e87a 100644
--- a/src/org/thoughtcrime/securesms/LogViewActivity.java
+++ b/src/org/thoughtcrime/securesms/LogViewActivity.java
@@ -56,6 +56,7 @@ public class LogViewActivity extends BaseActionBarActivity {
case R.id.save_log:
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.onAllGranted(() -> {
boolean success = logViewFragment.saveLogFile();
diff --git a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java
index 26acf07b6..664f878e8 100644
--- a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java
+++ b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java
@@ -305,6 +305,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
diff --git a/src/org/thoughtcrime/securesms/MessageSelectorFragment.java b/src/org/thoughtcrime/securesms/MessageSelectorFragment.java
index 3451ceb05..c7a95a1cf 100644
--- a/src/org/thoughtcrime/securesms/MessageSelectorFragment.java
+++ b/src/org/thoughtcrime/securesms/MessageSelectorFragment.java
@@ -86,6 +86,7 @@ public abstract class MessageSelectorFragment
Permissions.with(getActivity())
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> performSave(messageRecords))
diff --git a/src/org/thoughtcrime/securesms/ShareActivity.java b/src/org/thoughtcrime/securesms/ShareActivity.java
index 68e5bd7bc..f798f78ea 100644
--- a/src/org/thoughtcrime/securesms/ShareActivity.java
+++ b/src/org/thoughtcrime/securesms/ShareActivity.java
@@ -151,6 +151,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity implement
private void requestPermissionForFiles(List streamExtras) {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk33()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> resolveUris(streamExtras))
diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java
index 8f8505caf..2f0f2344a 100644
--- a/src/org/thoughtcrime/securesms/WelcomeActivity.java
+++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java
@@ -170,6 +170,7 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
private void startImportBackup() {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
index f7897d489..135d67823 100644
--- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
+++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java
@@ -446,6 +446,10 @@ public class AttachmentManager {
}
public static void selectGallery(Activity activity, int requestCode) {
+ // to enable camera roll,
+ // we're asking for "gallery permissions" also on newer systems that do not strictly require that.
+ // (asking directly after tapping "attachment" would be not-so-good as the user may want to attach sth. else
+ // and asking for permissions is better done on-point)
Permissions.with(activity)
.request(Permissions.galleryPermissions())
.ifNecessary()
@@ -466,6 +470,7 @@ public class AttachmentManager {
public static void selectAudio(Activity activity, int requestCode) {
Permissions.with(activity)
.request(Manifest.permission.READ_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> selectMediaType(activity, "audio/*", null, requestCode))
diff --git a/src/org/thoughtcrime/securesms/permissions/Permissions.java b/src/org/thoughtcrime/securesms/permissions/Permissions.java
index caee223ac..c009ad693 100644
--- a/src/org/thoughtcrime/securesms/permissions/Permissions.java
+++ b/src/org/thoughtcrime/securesms/permissions/Permissions.java
@@ -80,6 +80,8 @@ public class Permissions {
private boolean condition = true;
+ private boolean alwaysGranted = false;
+
PermissionsBuilder(PermissionObject permissionObject) {
this.permissionObject = permissionObject;
}
@@ -100,6 +102,20 @@ public class Permissions {
return this;
}
+ public PermissionsBuilder alwaysGrantOnSdk30() {
+ if (Build.VERSION.SDK_INT >= 30) {
+ alwaysGranted = true;
+ }
+ return this;
+ }
+
+ public PermissionsBuilder alwaysGrantOnSdk33() {
+ if (Build.VERSION.SDK_INT >= 33) {
+ alwaysGranted = true;
+ }
+ return this;
+ }
+
public PermissionsBuilder withRationaleDialog(@NonNull String message, @NonNull @DrawableRes int... headers) {
this.rationalDialogHeader = headers;
this.rationaleDialogMessage = message;
@@ -147,16 +163,9 @@ public class Permissions {
}
public void execute() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- // READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE does not exist on modern androids
- // as file access is done by pickers
- String[] r = requestedPermissions;
- Arrays.sort(r);
- if ( (r.length == 1 && (r[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE) || r[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)))
- || (r.length == 2 && r[0].equals(Manifest.permission.READ_EXTERNAL_STORAGE) && r[1].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) ) {
- allGrantedListener.run();
- return;
- }
+ if (alwaysGranted) {
+ allGrantedListener.run();
+ return;
}
PermissionsRequest request = new PermissionsRequest(allGrantedListener, anyDeniedListener, anyPermanentlyDeniedListener, anyResultListener,
diff --git a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 6297ab2c6..d3bc12f86 100644
--- a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -177,7 +177,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) return;
if (requestCode == REQUEST_CODE_CONFIRM_CREDENTIALS_KEYS) {
- exportKeys();
+ manageKeys();
} else if (requestCode == PICK_SELF_KEYS) {
Uri uri = (data != null ? data.getData() : null);
if (uri == null) {
@@ -330,15 +330,16 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
public boolean onPreferenceClick(Preference preference) {
boolean result = ScreenLockUtil.applyScreenLock(getActivity(), getString(R.string.pref_manage_keys), getString(R.string.enter_system_secret_to_continue), REQUEST_CODE_CONFIRM_CREDENTIALS_KEYS);
if (!result) {
- exportKeys();
+ manageKeys();
}
return true;
}
}
- private void exportKeys() {
+ private void manageKeys() {
Permissions.with(getActivity())
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
@@ -359,7 +360,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
else {
if (Build.VERSION.SDK_INT >= 30) {
- AttachmentManager.selectMediaType(getActivity(), "application/pgp-keys", new String[]{"text/plain"}, PICK_SELF_KEYS, StorageUtil.getDownloadUri());
+ AttachmentManager.selectMediaType(getActivity(), "*/*", null, PICK_SELF_KEYS, StorageUtil.getDownloadUri());
} else {
String path = DcHelper.getImexDir().getAbsolutePath();
showImportKeysDialog(path, path);
diff --git a/src/org/thoughtcrime/securesms/preferences/ChatBackgroundActivity.java b/src/org/thoughtcrime/securesms/preferences/ChatBackgroundActivity.java
index dea68ce2d..a120f65a7 100644
--- a/src/org/thoughtcrime/securesms/preferences/ChatBackgroundActivity.java
+++ b/src/org/thoughtcrime/securesms/preferences/ChatBackgroundActivity.java
@@ -38,7 +38,6 @@ public class ChatBackgroundActivity extends PassphraseRequiredActionBarActivity
Button galleryButton;
Button defaultButton;
- MenuItem acceptMenuItem;
ImageView preview;
String tempDestinationPath;
@@ -80,7 +79,6 @@ public class ChatBackgroundActivity extends PassphraseRequiredActionBarActivity
MenuInflater inflater = this.getMenuInflater();
menu.clear();
inflater.inflate(R.menu.chat_background, menu);
- acceptMenuItem = menu.findItem(R.id.apply_background);
super.onPrepareOptionsMenu(menu);
return true;
}
@@ -173,7 +171,6 @@ public class ChatBackgroundActivity extends PassphraseRequiredActionBarActivity
if (data != null && context != null && resultCode == RESULT_OK && requestCode == ApplicationPreferencesActivity.REQUEST_CODE_SET_BACKGROUND) {
imageUri = data.getData();
if (imageUri != null) {
- acceptMenuItem.setEnabled(true);
Thread thread = new Thread(){
@Override
public void run() {
diff --git a/src/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
index 967b937a2..e823f41e9 100644
--- a/src/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java
@@ -266,7 +266,8 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
private void performBackup() {
Permissions.with(getActivity())
- .request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
+ .request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE) // READ_EXTERNAL_STORAGE required to read folder contents and to generate backup names
+ .alwaysGrantOnSdk30()
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
.onAllGranted(() -> {
diff --git a/src/org/thoughtcrime/securesms/search/SearchListAdapter.java b/src/org/thoughtcrime/securesms/search/SearchListAdapter.java
index 6b3d1429d..7923822a3 100644
--- a/src/org/thoughtcrime/securesms/search/SearchListAdapter.java
+++ b/src/org/thoughtcrime/securesms/search/SearchListAdapter.java
@@ -40,7 +40,7 @@ class SearchListAdapter extends RecyclerView.Adapter