From f9403782a2c1d080c554e014b86afff4658a0460 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 18 Apr 2022 14:02:03 +0100 Subject: [PATCH] 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(); + } + } + } }