diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt index ab5902326f..7d6f9cfdf8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt @@ -88,7 +88,7 @@ class LinkDeviceFragment : ComposeFragment() { Scaffolds.Settings( title = stringResource(id = R.string.preferences__linked_devices), - onNavigationClick = { navController.popBackStack() }, + onNavigationClick = { findNavController().popOrFinish() }, navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close) ) { contentPadding: PaddingValues -> @@ -103,6 +103,12 @@ class LinkDeviceFragment : ComposeFragment() { ) } } + + private fun NavController.popOrFinish() { + if (!popBackStack()) { + requireActivity().finishAfterTransition() + } + } } @Composable @@ -117,7 +123,7 @@ fun DeviceDescriptionScreen( ) { if (state.progressDialogMessage != -1) { if (navController?.currentDestination?.id == R.id.linkDeviceFinishedSheet) { - navController?.popBackStack() + navController.popBackStack() } Dialogs.IndeterminateProgressDialog(stringResource(id = state.progressDialogMessage)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java index 5c67fad673..35dbf740df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/CameraXFragment.java @@ -166,7 +166,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment { this.controlsContainer = view.findViewById(R.id.camerax_controls_container); this.cameraXModePolicy = CameraXModePolicy.acquire(requireContext(), controller.getMediaConstraints(), - requireArguments().getBoolean(IS_VIDEO_ENABLED, true)); + requireArguments().getBoolean(IS_VIDEO_ENABLED, true), + requireArguments().getBoolean(IS_QR_SCAN_ENABLED, false)); this.missingPermissionsContainer = view.findViewById(R.id.missing_permissions_container); this.missingPermissionsText = view.findViewById(R.id.missing_permissions_text); this.allowAccessButton = view.findViewById(R.id.allow_access_button); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/camerax/CameraXModePolicy.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/camerax/CameraXModePolicy.kt index 23a71f8d80..42c1e1ebdb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/camerax/CameraXModePolicy.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/camerax/CameraXModePolicy.kt @@ -15,8 +15,18 @@ sealed class CameraXModePolicy { abstract val isVideoSupported: Boolean + abstract val isQrScanEnabled: Boolean + abstract fun initialize(cameraController: CameraXController) + open fun initialize(cameraController: CameraXController, useCaseFlags: Int) { + if (isQrScanEnabled) { + cameraController.setEnabledUseCases(useCaseFlags or CameraController.IMAGE_ANALYSIS) + } else { + cameraController.setEnabledUseCases(useCaseFlags) + } + } + open fun setToImage(cameraController: CameraXController) = Unit open fun setToVideo(cameraController: CameraXController) = Unit @@ -24,19 +34,19 @@ sealed class CameraXModePolicy { /** * The device supports having Image and Video enabled at the same time */ - object Mixed : CameraXModePolicy() { + data class Mixed(override val isQrScanEnabled: Boolean) : CameraXModePolicy() { override val isVideoSupported: Boolean = true override fun initialize(cameraController: CameraXController) { - cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE or CameraController.VIDEO_CAPTURE) + super.initialize(cameraController, CameraController.IMAGE_CAPTURE or CameraController.VIDEO_CAPTURE) } } /** * The device supports image and video, but only one mode at a time. */ - object Single : CameraXModePolicy() { + data class Single(override val isQrScanEnabled: Boolean) : CameraXModePolicy() { override val isVideoSupported: Boolean = true @@ -45,29 +55,29 @@ sealed class CameraXModePolicy { } override fun setToImage(cameraController: CameraXController) { - cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE) + super.initialize(cameraController, CameraController.IMAGE_CAPTURE) } override fun setToVideo(cameraController: CameraXController) { - cameraController.setEnabledUseCases(CameraController.VIDEO_CAPTURE) + super.initialize(cameraController, CameraController.VIDEO_CAPTURE) } } /** * The device supports taking images only. */ - object ImageOnly : CameraXModePolicy() { + data class ImageOnly(override val isQrScanEnabled: Boolean) : CameraXModePolicy() { override val isVideoSupported: Boolean = false override fun initialize(cameraController: CameraXController) { - cameraController.setEnabledUseCases(CameraController.IMAGE_CAPTURE) + super.initialize(cameraController, CameraController.IMAGE_CAPTURE) } } companion object { @JvmStatic - fun acquire(context: Context, mediaConstraints: MediaConstraints, isVideoEnabled: Boolean): CameraXModePolicy { + fun acquire(context: Context, mediaConstraints: MediaConstraints, isVideoEnabled: Boolean, isQrScanEnabled: Boolean): CameraXModePolicy { val isVideoSupported = Build.VERSION.SDK_INT >= 26 && isVideoEnabled && MediaConstraints.isVideoTranscodeAvailable() && @@ -79,9 +89,9 @@ sealed class CameraXModePolicy { !FeatureFlags.cameraXMixedModelBlocklist().asListContains(Build.MODEL) return when { - isMixedModeSupported -> Mixed - isVideoSupported -> Single - else -> ImageOnly + isMixedModeSupported -> Mixed(isQrScanEnabled) + isVideoSupported -> Single(isQrScanEnabled) + else -> ImageOnly(isQrScanEnabled) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt index 3aa87c2bea..ddf6c8b5fb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/capture/MediaCaptureFragment.kt @@ -14,6 +14,7 @@ import org.signal.core.util.concurrent.LifecycleDisposable import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.DeviceActivity import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity import org.thoughtcrime.securesms.mediasend.CameraFragment import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.v2.HudCommand @@ -23,6 +24,7 @@ import org.thoughtcrime.securesms.mms.MediaConstraints import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.CommunicationActions +import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.navigation.safeNavigate import java.io.FileDescriptor import java.util.Optional @@ -92,7 +94,11 @@ class MediaCaptureFragment : Fragment(R.layout.fragment_container), CameraFragme .setTitle(R.string.MediaCaptureFragment_device_link_dialog_title) .setMessage(R.string.MediaCaptureFragment_device_link_dialog_body) .setPositiveButton(R.string.MediaCaptureFragment_device_link_dialog_continue) { d, _ -> - startActivity(DeviceActivity.getIntentForScanner(requireContext())) + if (FeatureFlags.linkedDevicesV2()) { + startActivity(AppSettingsActivity.linkedDevices(requireContext())) + } else { + startActivity(DeviceActivity.getIntentForScanner(requireContext())) + } requireActivity().finish() } .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml index ec211644c2..953c96fafe 100644 --- a/app/src/main/res/navigation/app_settings.xml +++ b/app/src/main/res/navigation/app_settings.xml @@ -591,7 +591,7 @@