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