From 97ba18cfb26d1ecbd7784423dfdcbb961f6c10ec Mon Sep 17 00:00:00 2001 From: akwizgran Date: Sun, 17 Apr 2022 12:12:02 +0100 Subject: [PATCH 1/6] Catch ActivityNotFoundException when choosing files. --- .../android/conversation/ConversationActivity.java | 9 ++++++++- .../android/removabledrive/ReceiveFragment.java | 12 +++++++++--- .../briar/android/removabledrive/SendFragment.java | 12 +++++++++--- .../briar/android/settings/SettingsFragment.java | 10 +++++++++- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index 512342fd0..50bff36c3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -1,6 +1,7 @@ package org.briarproject.briar.android.conversation; import android.annotation.SuppressLint; +import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -121,6 +122,7 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import static android.os.Build.VERSION.SDK_INT; import static android.view.Gravity.RIGHT; +import static android.widget.Toast.LENGTH_LONG; import static android.widget.Toast.LENGTH_SHORT; import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation; import static androidx.lifecycle.Lifecycle.State.STARTED; @@ -774,7 +776,12 @@ public class ConversationActivity extends BriarActivity @Override public void onAttachImageClicked() { - launcher.launch("image/*"); + try { + launcher.launch("image/*"); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.error_start_activity, + LENGTH_LONG).show(); + } } private void onImagesChosen(@Nullable List uris) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java index f56a3184c..13ae078de 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.removabledrive; +import android.content.ActivityNotFoundException; import android.content.Context; import android.net.Uri; import android.os.Bundle; @@ -68,9 +69,14 @@ public class ReceiveFragment extends Fragment { scrollView = (ScrollView) v; progressBar = v.findViewById(R.id.progressBar); button = v.findViewById(R.id.fileButton); - button.setOnClickListener(view -> - launcher.launch("*/*") - ); + button.setOnClickListener(view -> { + try { + launcher.launch("*/*"); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), + R.string.error_start_activity, LENGTH_LONG).show(); + } + }); viewModel.getOldTaskResumedEvent() .observeEvent(getViewLifecycleOwner(), this::onOldTaskResumed); viewModel.getState() diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java index d1235ff17..59614fee1 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.removabledrive; +import android.content.ActivityNotFoundException; import android.content.Context; import android.net.Uri; import android.os.Bundle; @@ -73,9 +74,14 @@ public class SendFragment extends Fragment { introTextView = v.findViewById(R.id.introTextView); progressBar = v.findViewById(R.id.progressBar); button = v.findViewById(R.id.fileButton); - button.setOnClickListener(view -> - launcher.launch(viewModel.getFileName()) - ); + button.setOnClickListener(view -> { + try { + launcher.launch(viewModel.getFileName()); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), + R.string.error_start_activity, LENGTH_LONG).show(); + } + }); viewModel.getOldTaskResumedEvent() .observeEvent(getViewLifecycleOwner(), this::onOldTaskResumed); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index 219c43891..e6ffbfce4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -1,10 +1,12 @@ package org.briarproject.briar.android.settings; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; +import android.widget.Toast; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; @@ -23,6 +25,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; +import static android.widget.Toast.LENGTH_LONG; import static java.util.Objects.requireNonNull; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @@ -65,7 +68,12 @@ public class SettingsFragment extends PreferenceFragmentCompat { prefAvatar = requireNonNull(findPreference(PREF_KEY_AVATAR)); if (viewModel.shouldEnableProfilePictures()) { prefAvatar.setOnPreferenceClickListener(preference -> { - launcher.launch("image/*"); + try { + launcher.launch("image/*"); + } catch (ActivityNotFoundException e) { + Toast.makeText(requireContext(), + R.string.error_start_activity, LENGTH_LONG).show(); + } return true; }); } else { From f9403782a2c1d080c554e014b86afff4658a0460 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 18 Apr 2022 14:02:03 +0100 Subject: [PATCH 2/6] When opening files, try OPEN_DOCUMENT and fall back to GET_CONTENT. --- .../conversation/ConversationActivity.java | 25 ++++++----- .../removabledrive/ReceiveFragment.java | 19 ++++---- .../android/removabledrive/SendFragment.java | 7 +++ .../android/settings/SettingsFragment.java | 18 ++++---- .../briar/android/util/ActivityLaunchers.java | 44 +++++++++++++++++++ .../briar/android/util/UiUtils.java | 23 ++++++++++ 6 files changed, 105 insertions(+), 31 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index 50bff36c3..f11f2cac2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.conversation; import android.annotation.SuppressLint; -import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -59,6 +58,8 @@ import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.removabledrive.RemovableDriveActivity; import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced; import org.briarproject.briar.android.util.ActivityLaunchers.GetMultipleImagesAdvanced; +import org.briarproject.briar.android.util.ActivityLaunchers.OpenImageDocumentAdvanced; +import org.briarproject.briar.android.util.ActivityLaunchers.OpenMultipleImageDocumentsAdvanced; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.ImagePreview; @@ -122,7 +123,6 @@ import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; import static android.os.Build.VERSION.SDK_INT; import static android.view.Gravity.RIGHT; -import static android.widget.Toast.LENGTH_LONG; import static android.widget.Toast.LENGTH_SHORT; import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation; import static androidx.lifecycle.Lifecycle.State.STARTED; @@ -145,6 +145,7 @@ import static org.briarproject.briar.android.conversation.ImageActivity.ATTACHME import static org.briarproject.briar.android.conversation.ImageActivity.DATE; import static org.briarproject.briar.android.conversation.ImageActivity.ITEM_ID; import static org.briarproject.briar.android.conversation.ImageActivity.NAME; +import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile; import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.view.AuthorView.setAvatar; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; @@ -198,12 +199,19 @@ public class ConversationActivity extends BriarActivity requireNonNull(name); loadMessages(); }; - private final ActivityResultLauncher launcher = SDK_INT >= 18 ? - registerForActivityResult(new GetMultipleImagesAdvanced(), + private final ActivityResultLauncher docLauncher = SDK_INT >= 18 ? + registerForActivityResult(new OpenMultipleImageDocumentsAdvanced(), this::onImagesChosen) : - registerForActivityResult(new GetImageAdvanced(), uri -> { + registerForActivityResult(new OpenImageDocumentAdvanced(), uri -> { if (uri != null) onImagesChosen(singletonList(uri)); }); + private final ActivityResultLauncher contentLauncher = + SDK_INT >= 18 ? + registerForActivityResult(new GetMultipleImagesAdvanced(), + this::onImagesChosen) : + registerForActivityResult(new GetImageAdvanced(), uri -> { + if (uri != null) onImagesChosen(singletonList(uri)); + }); private AttachmentRetriever attachmentRetriever; private ConversationViewModel viewModel; @@ -776,12 +784,7 @@ public class ConversationActivity extends BriarActivity @Override public void onAttachImageClicked() { - try { - launcher.launch("image/*"); - } catch (ActivityNotFoundException e) { - Toast.makeText(this, R.string.error_start_activity, - LENGTH_LONG).show(); - } + launchActivityToOpenFile(this, docLauncher, contentLauncher, "image/*"); } private void onImagesChosen(@Nullable List uris) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java index 13ae078de..a8e31fd74 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.removabledrive; -import android.content.ActivityNotFoundException; import android.content.Context; import android.net.Uri; import android.os.Bundle; @@ -16,6 +15,7 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.util.ActivityLaunchers.GetContentAdvanced; +import org.briarproject.briar.android.util.ActivityLaunchers.OpenDocumentAdvanced; import javax.inject.Inject; @@ -29,6 +29,7 @@ import static android.view.View.FOCUS_DOWN; import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.briar.android.AppModule.getAndroidComponent; +import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -36,7 +37,10 @@ public class ReceiveFragment extends Fragment { final static String TAG = ReceiveFragment.class.getName(); - private final ActivityResultLauncher launcher = + private final ActivityResultLauncher docLauncher = + registerForActivityResult(new OpenDocumentAdvanced(), + this::onDocumentChosen); + private final ActivityResultLauncher contentLauncher = registerForActivityResult(new GetContentAdvanced(), this::onDocumentChosen); @@ -69,14 +73,9 @@ public class ReceiveFragment extends Fragment { scrollView = (ScrollView) v; progressBar = v.findViewById(R.id.progressBar); button = v.findViewById(R.id.fileButton); - button.setOnClickListener(view -> { - try { - launcher.launch("*/*"); - } catch (ActivityNotFoundException e) { - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG).show(); - } - }); + button.setOnClickListener(view -> + launchActivityToOpenFile(requireContext(), + docLauncher, contentLauncher, "*/*")); viewModel.getOldTaskResumedEvent() .observeEvent(getViewLifecycleOwner(), this::onOldTaskResumed); viewModel.getState() diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java index 59614fee1..15caf6b54 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java @@ -19,6 +19,8 @@ import org.briarproject.bramble.api.plugin.file.RemovableDriveTask; import org.briarproject.briar.R; import org.briarproject.briar.android.util.ActivityLaunchers.CreateDocumentAdvanced; +import java.util.logging.Logger; + import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; @@ -31,6 +33,9 @@ import static android.os.Build.VERSION.SDK_INT; import static android.view.View.FOCUS_DOWN; import static android.view.View.VISIBLE; import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.AppModule.getAndroidComponent; @MethodsNotNullByDefault @@ -38,6 +43,7 @@ import static org.briarproject.briar.android.AppModule.getAndroidComponent; public class SendFragment extends Fragment { final static String TAG = SendFragment.class.getName(); + private static final Logger LOG = getLogger(TAG); private final ActivityResultLauncher launcher = registerForActivityResult(new CreateDocumentAdvanced(), @@ -78,6 +84,7 @@ public class SendFragment extends Fragment { try { launcher.launch(viewModel.getFileName()); } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); Toast.makeText(requireContext(), R.string.error_start_activity, LENGTH_LONG).show(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index e6ffbfce4..d516b2daf 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -1,18 +1,17 @@ package org.briarproject.briar.android.settings; -import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; -import android.widget.Toast; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.mailbox.MailboxActivity; import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced; +import org.briarproject.briar.android.util.ActivityLaunchers.OpenImageDocumentAdvanced; import javax.inject.Inject; @@ -25,10 +24,10 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; -import static android.widget.Toast.LENGTH_LONG; import static java.util.Objects.requireNonNull; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; +import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile; import static org.briarproject.briar.android.util.UiUtils.triggerFeedback; @MethodsNotNullByDefault @@ -49,7 +48,10 @@ public class SettingsFragment extends PreferenceFragmentCompat { private SettingsViewModel viewModel; private AvatarPreference prefAvatar; - private final ActivityResultLauncher launcher = + private final ActivityResultLauncher docLauncher = + registerForActivityResult(new OpenImageDocumentAdvanced(), + this::onImageSelected); + private final ActivityResultLauncher contentLauncher = registerForActivityResult(new GetImageAdvanced(), this::onImageSelected); @@ -68,12 +70,8 @@ public class SettingsFragment extends PreferenceFragmentCompat { prefAvatar = requireNonNull(findPreference(PREF_KEY_AVATAR)); if (viewModel.shouldEnableProfilePictures()) { prefAvatar.setOnPreferenceClickListener(preference -> { - try { - launcher.launch("image/*"); - } catch (ActivityNotFoundException e) { - Toast.makeText(requireContext(), - R.string.error_start_activity, LENGTH_LONG).show(); - } + launchActivityToOpenFile(requireContext(), + docLauncher, contentLauncher, "image/*"); return true; }); } else { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java b/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java index 7798e6659..24aa5fb9b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java @@ -10,6 +10,8 @@ import androidx.activity.result.contract.ActivityResultContract; import androidx.activity.result.contract.ActivityResultContracts.CreateDocument; import androidx.activity.result.contract.ActivityResultContracts.GetContent; import androidx.activity.result.contract.ActivityResultContracts.GetMultipleContents; +import androidx.activity.result.contract.ActivityResultContracts.OpenDocument; +import androidx.activity.result.contract.ActivityResultContracts.OpenMultipleDocuments; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -45,6 +47,18 @@ public class ActivityLaunchers { } } + public static class OpenDocumentAdvanced extends OpenDocument { + @NonNull + @Override + public Intent createIntent(Context context, String[] input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + i.setType("/*"); + i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + return i; + } + } + public static class GetImageAdvanced extends GetContent { @NonNull @Override @@ -74,6 +88,36 @@ public class ActivityLaunchers { } } + public static class OpenImageDocumentAdvanced extends OpenDocument { + @NonNull + @Override + public Intent createIntent(Context context, String[] input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + i.setType("image/*"); + i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (SDK_INT >= 19) + i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes()); + return i; + } + } + + @TargetApi(18) + public static class OpenMultipleImageDocumentsAdvanced + extends OpenMultipleDocuments { + @NonNull + @Override + public Intent createIntent(Context context, String[] input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + i.setType("image/*"); + i.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (SDK_INT >= 19) + i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes()); + return i; + } + } + public static class RequestBluetoothDiscoverable extends ActivityResultContract { @NonNull diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index ea6272b71..21ad79a1e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -45,6 +45,7 @@ import org.briarproject.briar.android.view.ArticleMovementMethod; import java.util.Locale; import java.util.logging.Logger; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.AnyThread; import androidx.annotation.AttrRes; import androidx.annotation.ColorInt; @@ -108,6 +109,7 @@ import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_RTL; import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.DAYS; import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.BuildConfig.APPLICATION_ID; import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE; @@ -122,6 +124,8 @@ import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA @ParametersNotNullByDefault public class UiUtils { + private static final Logger LOG = getLogger(UiUtils.class.getName()); + public static final long MIN_DATE_RESOLUTION = MINUTE_IN_MILLIS; public static final int TEASER_LENGTH = 320; public static final float GREY_OUT = 0.5f; @@ -601,4 +605,23 @@ public class UiUtils { (dialog, which) -> requestPermissions.run()); builder.show(); } + + public static void launchActivityToOpenFile(Context ctx, + ActivityResultLauncher docLauncher, + ActivityResultLauncher contentLauncher, + String contentType) { + // Try OPEN_DOCUMENT, fall back to GET_CONTENT + try { + docLauncher.launch(new String[] {contentType}); + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + try { + contentLauncher.launch(contentType); + } catch (ActivityNotFoundException e1) { + logException(LOG, WARNING, e); + Toast.makeText(ctx, R.string.error_start_activity, + LENGTH_LONG).show(); + } + } + } } From b36066514b6d02979a5a15a667ac360eb4be325a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 18 Apr 2022 14:02:25 +0100 Subject: [PATCH 3/6] Add SDK_INT check to appease the linter. --- .../briar/android/conversation/ConversationActivity.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index f11f2cac2..12ca3077b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -434,9 +434,11 @@ public class ConversationActivity extends BriarActivity startActivity(intent); return true; } else if (itemId == R.id.action_transfer_data) { - Intent intent = new Intent(this, RemovableDriveActivity.class); - intent.putExtra(CONTACT_ID, contactId.getInt()); - startActivity(intent); + if (SDK_INT >= 19) { + Intent intent = new Intent(this, RemovableDriveActivity.class); + intent.putExtra(CONTACT_ID, contactId.getInt()); + startActivity(intent); + } return true; } else if (itemId == R.id.action_delete_all_messages) { askToDeleteAllMessages(); From 23316f5e9ccb12cd90d6686400effc57f72ab9a4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 18 Apr 2022 15:42:24 +0100 Subject: [PATCH 4/6] Don't use OPEN_DOCUMENT launchers on API < 19. --- .../conversation/ConversationActivity.java | 8 +++---- .../removabledrive/ReceiveFragment.java | 2 ++ .../android/removabledrive/SendFragment.java | 2 ++ .../android/settings/SettingsFragment.java | 7 ++++-- .../briar/android/util/ActivityLaunchers.java | 9 +++++--- .../briar/android/util/UiUtils.java | 23 +++++++++++-------- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index 12ca3077b..80a912178 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -58,7 +58,6 @@ import org.briarproject.briar.android.privategroup.conversation.GroupActivity; import org.briarproject.briar.android.removabledrive.RemovableDriveActivity; import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced; import org.briarproject.briar.android.util.ActivityLaunchers.GetMultipleImagesAdvanced; -import org.briarproject.briar.android.util.ActivityLaunchers.OpenImageDocumentAdvanced; import org.briarproject.briar.android.util.ActivityLaunchers.OpenMultipleImageDocumentsAdvanced; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; @@ -199,12 +198,11 @@ public class ConversationActivity extends BriarActivity requireNonNull(name); loadMessages(); }; - private final ActivityResultLauncher docLauncher = SDK_INT >= 18 ? + @Nullable + private final ActivityResultLauncher docLauncher = SDK_INT >= 19 ? registerForActivityResult(new OpenMultipleImageDocumentsAdvanced(), this::onImagesChosen) : - registerForActivityResult(new OpenImageDocumentAdvanced(), uri -> { - if (uri != null) onImagesChosen(singletonList(uri)); - }); + null; private final ActivityResultLauncher contentLauncher = SDK_INT >= 18 ? registerForActivityResult(new GetMultipleImagesAdvanced(), diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java index a8e31fd74..548382d1c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/ReceiveFragment.java @@ -21,6 +21,7 @@ import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.ViewModelProvider; @@ -31,6 +32,7 @@ import static android.widget.Toast.LENGTH_LONG; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile; +@RequiresApi(19) @MethodsNotNullByDefault @ParametersNotNullByDefault public class ReceiveFragment extends Fragment { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java index 15caf6b54..f42bdcef7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/removabledrive/SendFragment.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.ViewModelProvider; @@ -38,6 +39,7 @@ import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.android.AppModule.getAndroidComponent; +@RequiresApi(19) @MethodsNotNullByDefault @ParametersNotNullByDefault public class SendFragment extends Fragment { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java index d516b2daf..348fcc4ac 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java @@ -24,6 +24,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; +import static android.os.Build.VERSION.SDK_INT; import static java.util.Objects.requireNonNull; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @@ -48,9 +49,11 @@ public class SettingsFragment extends PreferenceFragmentCompat { private SettingsViewModel viewModel; private AvatarPreference prefAvatar; - private final ActivityResultLauncher docLauncher = + @Nullable + private final ActivityResultLauncher docLauncher = SDK_INT >= 19 ? registerForActivityResult(new OpenImageDocumentAdvanced(), - this::onImageSelected); + this::onImageSelected) : + null; private final ActivityResultLauncher contentLauncher = registerForActivityResult(new GetImageAdvanced(), this::onImageSelected); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java b/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java index 24aa5fb9b..f71755596 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.util; -import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; @@ -14,6 +13,7 @@ import androidx.activity.result.contract.ActivityResultContracts.OpenDocument; import androidx.activity.result.contract.ActivityResultContracts.OpenMultipleDocuments; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import static android.app.Activity.RESULT_CANCELED; import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; @@ -26,6 +26,7 @@ import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageConten @NotNullByDefault public class ActivityLaunchers { + @RequiresApi(19) public static class CreateDocumentAdvanced extends CreateDocument { @NonNull @Override @@ -47,6 +48,7 @@ public class ActivityLaunchers { } } + @RequiresApi(19) public static class OpenDocumentAdvanced extends OpenDocument { @NonNull @Override @@ -73,7 +75,7 @@ public class ActivityLaunchers { } } - @TargetApi(18) + @RequiresApi(18) public static class GetMultipleImagesAdvanced extends GetMultipleContents { @NonNull @Override @@ -88,6 +90,7 @@ public class ActivityLaunchers { } } + @RequiresApi(19) public static class OpenImageDocumentAdvanced extends OpenDocument { @NonNull @Override @@ -102,7 +105,7 @@ public class ActivityLaunchers { } } - @TargetApi(18) + @RequiresApi(19) public static class OpenMultipleImageDocumentsAdvanced extends OpenMultipleDocuments { @NonNull diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index 21ad79a1e..9c59633aa 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -607,21 +607,24 @@ public class UiUtils { } public static void launchActivityToOpenFile(Context ctx, - ActivityResultLauncher docLauncher, + @Nullable ActivityResultLauncher docLauncher, ActivityResultLauncher contentLauncher, String contentType) { - // Try OPEN_DOCUMENT, fall back to GET_CONTENT + // Try OPEN_DOCUMENT if available, fall back to GET_CONTENT + if (docLauncher != null) { + try { + docLauncher.launch(new String[] {contentType}); + return; + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + } + } try { - docLauncher.launch(new String[] {contentType}); + contentLauncher.launch(contentType); } catch (ActivityNotFoundException e) { logException(LOG, WARNING, e); - try { - contentLauncher.launch(contentType); - } catch (ActivityNotFoundException e1) { - logException(LOG, WARNING, e); - Toast.makeText(ctx, R.string.error_start_activity, - LENGTH_LONG).show(); - } + Toast.makeText(ctx, R.string.error_start_activity, + LENGTH_LONG).show(); } } } From 383056d37eaaca8e78226d855af00dea2043bd65 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 18 Apr 2022 15:57:18 +0100 Subject: [PATCH 5/6] Fix the lint problems I created for myself. --- .../briar/android/conversation/ImageActivity.java | 14 +++++--------- .../briar/android/hotspot/FallbackFragment.java | 14 ++++++++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java index 3a0b289a0..46bbfabf2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java @@ -32,7 +32,6 @@ import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.Fragment; @@ -64,7 +63,6 @@ public class ImageActivity extends BriarActivity final static String DATE = "date"; final static String ITEM_ID = "itemId"; - @RequiresApi(api = 16) private final static int UI_FLAGS_DEFAULT = SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; @@ -78,9 +76,11 @@ public class ImageActivity extends BriarActivity private List attachments; private MessageId conversationMessageId; - private final ActivityResultLauncher launcher = + @Nullable + private final ActivityResultLauncher launcher = SDK_INT >= 19 ? registerForActivityResult(new CreateDocumentAdvanced(), - this::onImageUriSelected); + this::onImageUriSelected) : + null; @Override public void injectActivity(ActivityComponent component) { @@ -208,14 +208,12 @@ public class ImageActivity extends BriarActivity super.onBackPressed(); } - @RequiresApi(api = 16) private void onImageClicked(@Nullable Boolean clicked) { if (clicked != null && clicked) { toggleSystemUi(); } } - @RequiresApi(api = 16) private void toggleSystemUi() { View decorView = getWindow().getDecorView(); if (appBarLayout.getVisibility() == VISIBLE) { @@ -225,7 +223,6 @@ public class ImageActivity extends BriarActivity } } - @RequiresApi(api = 16) private void hideSystemUi(View decorView) { decorView.setSystemUiVisibility( SYSTEM_UI_FLAG_FULLSCREEN | UI_FLAGS_DEFAULT); @@ -236,7 +233,6 @@ public class ImageActivity extends BriarActivity .start(); } - @RequiresApi(api = 16) private void showSystemUi(View decorView) { decorView.setSystemUiVisibility(UI_FLAGS_DEFAULT); appBarLayout.animate() @@ -263,7 +259,7 @@ public class ImageActivity extends BriarActivity if (SDK_INT >= 19) { String name = viewModel.getFileName() + "." + getVisibleAttachment().getExtension(); - launcher.launch(name); + requireNonNull(launcher).launch(name); } else { viewModel.saveImage(getVisibleAttachment()); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java index 56c88f061..3b8d57bc8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/FallbackFragment.java @@ -34,6 +34,7 @@ import static android.os.Build.VERSION.SDK_INT; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static androidx.transition.TransitionManager.beginDelayedTransition; +import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.briar.android.AppModule.getAndroidComponent; import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName; @@ -47,9 +48,11 @@ public class FallbackFragment extends BaseFragment { ViewModelProvider.Factory viewModelFactory; private HotspotViewModel viewModel; - private final ActivityResultLauncher launcher = + @Nullable + private final ActivityResultLauncher launcher = SDK_INT >= 19 ? registerForActivityResult(new CreateDocumentAdvanced(), - this::onDocumentCreated); + this::onDocumentCreated) : + null; private Button fallbackButton; private ProgressBar progressBar; @@ -87,8 +90,11 @@ public class FallbackFragment extends BaseFragment { fallbackButton.setVisibility(INVISIBLE); progressBar.setVisibility(VISIBLE); - if (SDK_INT >= 19) launcher.launch(getApkFileName()); - else viewModel.exportApk(); + if (SDK_INT >= 19) { + requireNonNull(launcher).launch(getApkFileName()); + } else { + viewModel.exportApk(); + } }); viewModel.getSavedApkToUri().observeEvent(this, this::shareUri); } From eb6a5fe63e0d722bc4c534996561f77036fd0ea0 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 19 Apr 2022 12:57:58 +0100 Subject: [PATCH 6/6] Try GET_CONTENT first, fall back to OPEN_DOCUMENT. --- .../briarproject/briar/android/util/UiUtils.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index 9c59633aa..446d20e8a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -610,7 +610,13 @@ public class UiUtils { @Nullable ActivityResultLauncher docLauncher, ActivityResultLauncher contentLauncher, String contentType) { - // Try OPEN_DOCUMENT if available, fall back to GET_CONTENT + // Try GET_CONTENT, fall back to OPEN_DOCUMENT if available + try { + contentLauncher.launch(contentType); + return; + } catch (ActivityNotFoundException e) { + logException(LOG, WARNING, e); + } if (docLauncher != null) { try { docLauncher.launch(new String[] {contentType}); @@ -619,12 +625,6 @@ public class UiUtils { logException(LOG, WARNING, e); } } - try { - contentLauncher.launch(contentType); - } catch (ActivityNotFoundException e) { - logException(LOG, WARNING, e); - Toast.makeText(ctx, R.string.error_start_activity, - LENGTH_LONG).show(); - } + Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG).show(); } }