From 1adf408ade1f1cf59bf9d5f9ecb25034756a9c85 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 25 Jun 2021 16:56:22 -0300 Subject: [PATCH] Migrate all image file pickers to ActivityResultLauncher startActivityForResult is deprecated and the new API is nicer. Also, we can use the same launcher types in various places. --- .../briar/android/activity/RequestCodes.java | 3 - .../add/nearby/AddNearbyContactActivity.java | 2 +- .../BluetoothConnecterDialogFragment.java | 2 +- .../conversation/ConversationActivity.java | 24 +++-- .../android/conversation/ImageActivity.java | 36 +++----- .../android/conversation/ImageViewModel.java | 7 +- .../removabledrive/ReceiveFragment.java | 21 +---- .../android/removabledrive/SendFragment.java | 13 +-- .../android/settings/SettingsFragment.java | 32 +++---- .../briar/android/util/ActivityLaunchers.java | 88 +++++++++++++++++++ .../util/RequestBluetoothDiscoverable.java | 31 ------- .../briar/android/util/UiUtils.java | 18 ---- .../view/TextAttachmentController.java | 35 ++------ 13 files changed, 149 insertions(+), 163 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java delete mode 100644 briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java index 991aab447..160f054d7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/RequestCodes.java @@ -11,8 +11,5 @@ public interface RequestCodes { int REQUEST_DOZE_WHITELISTING = 9; int REQUEST_UNLOCK = 11; int REQUEST_KEYGUARD_UNLOCK = 12; - int REQUEST_ATTACH_IMAGE = 13; - int REQUEST_SAVE_ATTACHMENT = 14; - int REQUEST_AVATAR_IMAGE = 15; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java index 6dd6ca690..94b381b7f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java @@ -17,7 +17,7 @@ import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; -import org.briarproject.briar.android.util.RequestBluetoothDiscoverable; +import org.briarproject.briar.android.util.ActivityLaunchers.RequestBluetoothDiscoverable; import java.util.logging.Logger; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/BluetoothConnecterDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/BluetoothConnecterDialogFragment.java index 955dc419f..f208d3bcf 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/BluetoothConnecterDialogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/BluetoothConnecterDialogFragment.java @@ -14,7 +14,7 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.BaseActivity; import org.briarproject.briar.android.contact.ContactItem; -import org.briarproject.briar.android.util.RequestBluetoothDiscoverable; +import org.briarproject.briar.android.util.ActivityLaunchers.RequestBluetoothDiscoverable; import javax.inject.Inject; 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 18c08f02a..db2f8fb2a 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 @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.content.DialogInterface; import android.content.Intent; import android.graphics.drawable.Drawable; +import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.transition.Slide; @@ -54,6 +55,8 @@ import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener import org.briarproject.briar.android.introduction.IntroductionActivity; 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.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.ImagePreview; @@ -92,6 +95,7 @@ import java.util.logging.Logger; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.appcompat.app.AlertDialog; @@ -121,6 +125,7 @@ import static android.widget.Toast.LENGTH_SHORT; import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation; import static androidx.lifecycle.Lifecycle.State.STARTED; import static androidx.recyclerview.widget.SortedList.INVALID_POSITION; +import static java.util.Collections.singletonList; import static java.util.Collections.sort; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.INFO; @@ -132,7 +137,6 @@ import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.StringUtils.fromHexString; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.join; -import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_ATTACH_IMAGE; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_INTRODUCTION; import static org.briarproject.briar.android.conversation.ImageActivity.ATTACHMENTS; import static org.briarproject.briar.android.conversation.ImageActivity.ATTACHMENT_POSITION; @@ -192,6 +196,12 @@ public class ConversationActivity extends BriarActivity requireNonNull(name); loadMessages(); }; + private final ActivityResultLauncher launcher = SDK_INT >= 18 ? + registerForActivityResult(new GetMultipleImagesAdvanced(), + this::onImagesChosen) : + registerForActivityResult(new GetImageAdvanced(), uri -> { + if (uri != null) onImagesChosen(singletonList(uri)); + }); private AttachmentRetriever attachmentRetriever; private ConversationViewModel viewModel; @@ -314,9 +324,6 @@ public class ConversationActivity extends BriarActivity .make(list, R.string.introduction_sent, Snackbar.LENGTH_SHORT) .show(); - } else if (request == REQUEST_ATTACH_IMAGE && result == RESULT_OK) { - // TODO: remove cast when removing feature flag - ((TextAttachmentController) sendController).onImageReceived(data); } } @@ -769,8 +776,13 @@ public class ConversationActivity extends BriarActivity } @Override - public void onAttachImage(Intent intent) { - startActivityForResult(intent, REQUEST_ATTACH_IMAGE); + public void onAttachImageClicked() { + launcher.launch("image/*"); + } + + private void onImagesChosen(@Nullable List uris) { + // TODO: remove cast when removing feature flag + ((TextAttachmentController) sendController).onImageReceived(uris); } @Override 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 4bfeedcef..7ee1f0448 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 @@ -2,6 +2,7 @@ package org.briarproject.briar.android.conversation; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.transition.Fade; import android.transition.Transition; @@ -21,6 +22,7 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.attachment.AttachmentItem; +import org.briarproject.briar.android.util.ActivityLaunchers.CreateDocumentAdvanced; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.PullDownLayout; @@ -28,6 +30,7 @@ import java.util.List; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AlertDialog.Builder; @@ -38,9 +41,6 @@ import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.lifecycle.ViewModelProvider; import androidx.viewpager.widget.ViewPager; -import static android.content.Intent.ACTION_CREATE_DOCUMENT; -import static android.content.Intent.CATEGORY_OPENABLE; -import static android.content.Intent.EXTRA_TITLE; import static android.graphics.Color.TRANSPARENT; import static android.os.Build.VERSION.SDK_INT; import static android.view.View.GONE; @@ -51,7 +51,6 @@ import static android.view.View.VISIBLE; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; import static java.util.Objects.requireNonNull; -import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SAVE_ATTACHMENT; import static org.briarproject.briar.android.util.UiUtils.formatDateAbsolute; import static org.briarproject.briar.android.util.UiUtils.getDialogIcon; @@ -80,6 +79,10 @@ public class ImageActivity extends BriarActivity private List attachments; private MessageId conversationMessageId; + private final ActivityResultLauncher launcher = + registerForActivityResult(new CreateDocumentAdvanced(), + this::onImageUriSelected); + @Override public void injectActivity(ActivityComponent component) { component.inject(this); @@ -177,16 +180,6 @@ public class ImageActivity extends BriarActivity layout.getViewTreeObserver().removeOnGlobalLayoutListener(this); } - @Override - protected void onActivityResult(int request, int result, - @Nullable Intent data) { - super.onActivityResult(request, result, data); - if (request == REQUEST_SAVE_ATTACHMENT && result == RESULT_OK && - data != null) { - viewModel.saveImage(getVisibleAttachment(), data.getData()); - } - } - @Override public void onPullStart() { appBarLayout.animate() @@ -270,8 +263,9 @@ public class ImageActivity extends BriarActivity private void showSaveImageDialog() { OnClickListener okListener = (dialog, which) -> { if (SDK_INT >= 19) { - Intent intent = getCreationIntent(); - startActivityForResult(intent, REQUEST_SAVE_ATTACHMENT); + String name = viewModel.getFileName() + "." + + getVisibleAttachment().getExtension(); + launcher.launch(name); } else { viewModel.saveImage(getVisibleAttachment()); } @@ -285,13 +279,9 @@ public class ImageActivity extends BriarActivity builder.show(); } - @RequiresApi(api = 19) - private Intent getCreationIntent() { - Intent intent = new Intent(ACTION_CREATE_DOCUMENT); - intent.addCategory(CATEGORY_OPENABLE); - intent.setType(getVisibleAttachment().getMimeType()); - intent.putExtra(EXTRA_TITLE, viewModel.getFileName()); - return intent; + private void onImageUriSelected(@Nullable Uri uri) { + if (uri == null) return; + viewModel.saveImage(getVisibleAttachment(), uri); } private void onImageSaveStateChanged(@Nullable Boolean error) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java index 80ab00150..84e9af5d8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java @@ -33,7 +33,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -45,6 +44,7 @@ import androidx.annotation.UiThread; import static android.media.MediaScannerConnection.scanFile; import static android.os.Environment.DIRECTORY_PICTURES; import static android.os.Environment.getExternalStoragePublicDirectory; +import static java.util.Locale.US; import static java.util.Objects.requireNonNull; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; @@ -111,7 +111,7 @@ public class ImageViewModel extends DbViewModel implements EventListener { } @UiThread - public void expectAttachments(List attachments) { + void expectAttachments(List attachments) { for (AttachmentItem item : attachments) { // no need to track items that are in a final state already if (item.getState().isFinal()) continue; @@ -226,8 +226,7 @@ public class ImageViewModel extends DbViewModel implements EventListener { } String getFileName() { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", - Locale.getDefault()); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HHmmss", US); return sdf.format(new Date()); } 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 a82818649..26df80ed3 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,7 +1,6 @@ package org.briarproject.briar.android.removabledrive; import android.content.Context; -import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; @@ -15,11 +14,11 @@ 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.util.ActivityLaunchers.GetContentAdvanced; import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts.GetContent; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; @@ -28,7 +27,6 @@ import androidx.lifecycle.ViewModelProvider; 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.putShowAdvancedExtra; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -36,22 +34,9 @@ public class ReceiveFragment extends Fragment { final static String TAG = ReceiveFragment.class.getName(); - private static class GetFile extends GetContent { - @Override - public Intent createIntent(Context context, String input) { - Intent i = super.createIntent(context, input); - putShowAdvancedExtra(i); - return i; - } - } - - // TODO we can pass an extra named DocumentsContract.EXTRA_INITIAL_URI - // to have the file-picker start on the usb-stick -- if get hold of URI - // of the same. USB manager API? - // Overall, passing this extra requires extending the ready-made - // contracts and overriding createIntent. private final ActivityResultLauncher launcher = - registerForActivityResult(new GetFile(), this::onDocumentChosen); + registerForActivityResult(new GetContentAdvanced(), + this::onDocumentChosen); @Inject ViewModelProvider.Factory viewModelFactory; 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 9dc82a5eb..432a9e7d2 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,7 +1,6 @@ package org.briarproject.briar.android.removabledrive; import android.content.Context; -import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; @@ -16,11 +15,11 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.file.RemovableDriveTask; import org.briarproject.briar.R; +import org.briarproject.briar.android.util.ActivityLaunchers.CreateDocumentAdvanced; import javax.inject.Inject; import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts.CreateDocument; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; @@ -30,7 +29,6 @@ import static android.os.Build.VERSION.SDK_INT; 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.putShowAdvancedExtra; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -38,15 +36,6 @@ public class SendFragment extends Fragment { final static String TAG = SendFragment.class.getName(); - private static class CreateDocumentAdvanced extends CreateDocument { - @Override - public Intent createIntent(Context context, String input) { - Intent i = super.createIntent(context, input); - putShowAdvancedExtra(i); - return i; - } - } - private final ActivityResultLauncher launcher = registerForActivityResult(new CreateDocumentAdvanced(), this::onDocumentCreated); 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 e3769e9e2..df8543c1a 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,7 +1,6 @@ package org.briarproject.briar.android.settings; import android.content.Context; -import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; @@ -9,9 +8,11 @@ import android.view.View; 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.GetImageAdvanced; import javax.inject.Inject; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; @@ -20,12 +21,9 @@ import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; -import static android.app.Activity.RESULT_OK; 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.activity.RequestCodes.REQUEST_AVATAR_IMAGE; -import static org.briarproject.briar.android.util.UiUtils.createSelectImageIntent; import static org.briarproject.briar.android.util.UiUtils.triggerFeedback; @MethodsNotNullByDefault @@ -45,6 +43,10 @@ public class SettingsFragment extends PreferenceFragmentCompat { private SettingsViewModel viewModel; private AvatarPreference prefAvatar; + private final ActivityResultLauncher launcher = + registerForActivityResult(new GetImageAdvanced(), + this::onImageSelected); + @Override public void onAttach(@NonNull Context context) { super.onAttach(context); @@ -60,8 +62,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { prefAvatar = requireNonNull(findPreference(PREF_KEY_AVATAR)); if (viewModel.shouldEnableProfilePictures()) { prefAvatar.setOnPreferenceClickListener(preference -> { - Intent intent = createSelectImageIntent(false); - startActivityForResult(intent, REQUEST_AVATAR_IMAGE); + launcher.launch("image/*"); return true; }); } else { @@ -102,20 +103,11 @@ public class SettingsFragment extends PreferenceFragmentCompat { requireActivity().setTitle(R.string.settings_button); } - @Override - public void onActivityResult(int request, int result, - @Nullable Intent data) { - super.onActivityResult(request, result, data); - if (request == REQUEST_AVATAR_IMAGE && result == RESULT_OK) { - if (data == null) return; - Uri uri = data.getData(); - if (uri == null) return; - - DialogFragment dialog = - ConfirmAvatarDialogFragment.newInstance(uri); - dialog.show(getParentFragmentManager(), - ConfirmAvatarDialogFragment.TAG); - } + private void onImageSelected(@Nullable Uri uri) { + if (uri == null) return; + DialogFragment dialog = ConfirmAvatarDialogFragment.newInstance(uri); + dialog.show(getParentFragmentManager(), + ConfirmAvatarDialogFragment.TAG); } } 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 new file mode 100644 index 000000000..cd7456c89 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/ActivityLaunchers.java @@ -0,0 +1,88 @@ +package org.briarproject.briar.android.util; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.Intent; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +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.annotation.Nullable; + +import static android.app.Activity.RESULT_CANCELED; +import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; +import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION; +import static android.content.Intent.EXTRA_MIME_TYPES; +import static android.os.Build.VERSION.SDK_INT; +import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageContentTypes; + +@NotNullByDefault +public class ActivityLaunchers { + + public static class CreateDocumentAdvanced extends CreateDocument { + @Override + public Intent createIntent(Context context, String input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + return i; + } + } + + public static class GetContentAdvanced extends GetContent { + @Override + public Intent createIntent(Context context, String input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + return i; + } + } + + public static class GetImageAdvanced extends GetContent { + @Override + public Intent createIntent(Context context, String input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + i.setType("image/*"); + if (SDK_INT >= 19) + i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes()); + return i; + } + } + + @TargetApi(18) + public static class GetMultipleImagesAdvanced extends GetMultipleContents { + @Override + public Intent createIntent(Context context, String input) { + Intent i = super.createIntent(context, input); + putShowAdvancedExtra(i); + i.setType("image/*"); + if (SDK_INT >= 19) + i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes()); + return i; + } + } + + public static class RequestBluetoothDiscoverable + extends ActivityResultContract { + @Override + public Intent createIntent(Context context, Integer duration) { + Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE); + i.putExtra(EXTRA_DISCOVERABLE_DURATION, duration); + return i; + } + + @Override + public Boolean parseResult(int resultCode, @Nullable Intent intent) { + return resultCode != RESULT_CANCELED; + } + } + + private static void putShowAdvancedExtra(Intent i) { + i.putExtra(SDK_INT <= 28 ? "android.content.extra.SHOW_ADVANCED" : + "android.provider.extra.SHOW_ADVANCED", true); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java b/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java deleted file mode 100644 index 8288aedac..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/RequestBluetoothDiscoverable.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.briarproject.briar.android.util; - - -import android.content.Context; -import android.content.Intent; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import androidx.activity.result.contract.ActivityResultContract; -import androidx.annotation.Nullable; - -import static android.app.Activity.RESULT_CANCELED; -import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; -import static android.bluetooth.BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION; - -@NotNullByDefault -public class RequestBluetoothDiscoverable - extends ActivityResultContract { - - @Override - public Intent createIntent(Context context, Integer duration) { - Intent i = new Intent(ACTION_REQUEST_DISCOVERABLE); - i.putExtra(EXTRA_DISCOVERABLE_DURATION, duration); - return i; - } - - @Override - public Boolean parseResult(int resultCode, @Nullable Intent intent) { - return resultCode != RESULT_CANCELED; - } -} 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 11aff8d03..fd5140407 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 @@ -67,12 +67,7 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import static android.content.Context.KEYGUARD_SERVICE; import static android.content.Context.POWER_SERVICE; -import static android.content.Intent.ACTION_GET_CONTENT; -import static android.content.Intent.ACTION_OPEN_DOCUMENT; import static android.content.Intent.CATEGORY_DEFAULT; -import static android.content.Intent.CATEGORY_OPENABLE; -import static android.content.Intent.EXTRA_ALLOW_MULTIPLE; -import static android.content.Intent.EXTRA_MIME_TYPES; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Build.MANUFACTURER; import static android.os.Build.VERSION.SDK_INT; @@ -107,7 +102,6 @@ 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 org.briarproject.bramble.util.AndroidUtils.getSupportedImageContentTypes; 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; @@ -310,18 +304,6 @@ public class UiUtils { }; } - public static Intent createSelectImageIntent(boolean allowMultiple) { - Intent intent = new Intent(SDK_INT >= 19 ? - ACTION_OPEN_DOCUMENT : ACTION_GET_CONTENT); - intent.setType("image/*"); - intent.addCategory(CATEGORY_OPENABLE); - if (SDK_INT >= 19) - intent.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes()); - if (allowMultiple && SDK_INT >= 18) - intent.putExtra(EXTRA_ALLOW_MULTIPLE, true); - return intent; - } - public static void showOnboardingDialog(Context ctx, String text) { new AlertDialog.Builder(ctx, R.style.OnboardingDialogTheme) .setMessage(text) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java index 9cb3210f3..f6b751412 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextAttachmentController.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.view; import android.app.Activity; -import android.content.ClipData; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -15,13 +14,13 @@ import org.briarproject.briar.R; import org.briarproject.briar.android.attachment.AttachmentItemResult; import org.briarproject.briar.android.attachment.AttachmentManager; import org.briarproject.briar.android.attachment.AttachmentResult; -import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.appcompat.app.AlertDialog.Builder; @@ -31,7 +30,6 @@ import androidx.lifecycle.Observer; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt; -import static android.os.Build.VERSION.SDK_INT; import static android.view.View.GONE; import static android.widget.Toast.LENGTH_LONG; import static androidx.core.content.ContextCompat.getColor; @@ -143,38 +141,23 @@ public class TextAttachmentController extends TextSendController builder.show(); return; } - Intent intent = UiUtils.createSelectImageIntent(true); if (attachmentListener.getLifecycle().getCurrentState() != DESTROYED) { - attachmentListener.onAttachImage(intent); + attachmentListener.onAttachImageClicked(); } } /** - * This is called with the result Intent returned by the Activity started - * with {@link UiUtils#createSelectImageIntent(boolean)}. - *

* This method must be called at most once per call to - * {@link AttachmentListener#onAttachImage(Intent)}. - * Normally, this is true if called from + * {@link AttachmentListener#onAttachImageClicked()}. + * Normally, this is true if called from the launcher equivalent of * {@link Activity#onActivityResult(int, int, Intent)} since this is called - * at most once per call to - * {@link Activity#startActivityForResult(Intent, int)}. + * at most once per call to {@link ActivityResultLauncher#launch(Object)}. */ @SuppressWarnings("JavadocReference") - public void onImageReceived(@Nullable Intent resultData) { - if (resultData == null) return; + public void onImageReceived(@Nullable List newUris) { + if (newUris == null) return; if (loadingUris || !imageUris.isEmpty()) throw new AssertionError(); - List newUris = new ArrayList<>(); - if (resultData.getData() != null) { - newUris.add(resultData.getData()); - onNewUris(false, newUris); - } else if (SDK_INT >= 18 && resultData.getClipData() != null) { - ClipData clipData = resultData.getClipData(); - for (int i = 0; i < clipData.getItemCount(); i++) { - newUris.add(clipData.getItemAt(i).getUri()); - } - onNewUris(false, newUris); - } + onNewUris(false, newUris); } private void onNewUris(boolean restart, List newUris) { @@ -329,7 +312,7 @@ public class TextAttachmentController extends TextSendController @UiThread public interface AttachmentListener extends SendListener { - void onAttachImage(Intent intent); + void onAttachImageClicked(); void onTooManyAttachments(); }