Move biometrics check when linking a device.
This commit is contained in:
parent
976f80ff7e
commit
e08c2966c3
10 changed files with 67 additions and 135 deletions
|
@ -2,12 +2,7 @@ package org.thoughtcrime.securesms.linkdevice
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.biometric.BiometricManager
|
|
||||||
import androidx.biometric.BiometricPrompt
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
@ -30,9 +25,6 @@ import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import org.signal.core.ui.Previews
|
import org.signal.core.ui.Previews
|
||||||
import org.signal.core.ui.Scaffolds
|
import org.signal.core.ui.Scaffolds
|
||||||
import org.signal.core.ui.SignalPreview
|
import org.signal.core.ui.SignalPreview
|
||||||
import org.signal.core.util.logging.Log
|
|
||||||
import org.thoughtcrime.securesms.BiometricDeviceAuthentication
|
|
||||||
import org.thoughtcrime.securesms.BiometricDeviceLockContract
|
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
|
@ -43,42 +35,7 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||||
*/
|
*/
|
||||||
class AddLinkDeviceFragment : ComposeFragment() {
|
class AddLinkDeviceFragment : ComposeFragment() {
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val TAG = Log.tag(AddLinkDeviceFragment::class)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val viewModel: LinkDeviceViewModel by activityViewModels()
|
private val viewModel: LinkDeviceViewModel by activityViewModels()
|
||||||
private lateinit var biometricAuth: BiometricDeviceAuthentication
|
|
||||||
private lateinit var biometricDeviceLockLauncher: ActivityResultLauncher<String>
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
|
|
||||||
biometricDeviceLockLauncher = registerForActivityResult(BiometricDeviceLockContract()) { result: Int ->
|
|
||||||
if (result == BiometricDeviceAuthentication.AUTHENTICATED) {
|
|
||||||
viewModel.addDevice()
|
|
||||||
} else {
|
|
||||||
viewModel.clearBiometrics()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
|
||||||
.setAllowedAuthenticators(BiometricDeviceAuthentication.ALLOWED_AUTHENTICATORS)
|
|
||||||
.setTitle(requireContext().getString(R.string.BiometricDeviceAuthentication__signal))
|
|
||||||
.setConfirmationRequired(true)
|
|
||||||
.build()
|
|
||||||
biometricAuth = BiometricDeviceAuthentication(
|
|
||||||
BiometricManager.from(requireActivity()),
|
|
||||||
BiometricPrompt(requireActivity(), BiometricAuthenticationListener()),
|
|
||||||
promptInfo
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
viewModel.clearBiometrics()
|
|
||||||
biometricAuth.cancelAuthentication()
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalPermissionsApi::class)
|
@OptIn(ExperimentalPermissionsApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -103,14 +60,7 @@ class AddLinkDeviceFragment : ComposeFragment() {
|
||||||
onRequestPermissions = { askPermissions() },
|
onRequestPermissions = { askPermissions() },
|
||||||
onShowFrontCamera = { viewModel.showFrontCamera() },
|
onShowFrontCamera = { viewModel.showFrontCamera() },
|
||||||
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
|
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
|
||||||
onQrCodeApproved = {
|
onQrCodeApproved = { viewModel.addDevice() },
|
||||||
viewModel.onQrCodeApproved()
|
|
||||||
if (biometricAuth.canAuthenticate()) {
|
|
||||||
biometricAuth.authenticate(requireContext(), true) { biometricDeviceLockLauncher.launch(getString(R.string.BiometricDeviceAuthentication__signal)) }
|
|
||||||
} else {
|
|
||||||
viewModel.addDevice()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onQrCodeDismissed = { viewModel.onQrCodeDismissed() },
|
onQrCodeDismissed = { viewModel.onQrCodeDismissed() },
|
||||||
onQrCodeRetry = { viewModel.onQrCodeScanned(state.url) },
|
onQrCodeRetry = { viewModel.onQrCodeScanned(state.url) },
|
||||||
onLinkDeviceSuccess = {
|
onLinkDeviceSuccess = {
|
||||||
|
@ -134,23 +84,6 @@ class AddLinkDeviceFragment : ComposeFragment() {
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults)
|
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class BiometricAuthenticationListener : BiometricPrompt.AuthenticationCallback() {
|
|
||||||
override fun onAuthenticationError(errorCode: Int, errorString: CharSequence) {
|
|
||||||
Log.w(TAG, "Linked device authentication error: $errorCode")
|
|
||||||
viewModel.clearBiometrics()
|
|
||||||
onAuthenticationFailed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
|
||||||
Log.i(TAG, "Linked device authentication succeeded")
|
|
||||||
viewModel.addDevice()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
|
||||||
Log.w(TAG, "Linked device unable to authenticate")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -188,7 +121,6 @@ private fun MainScreen(
|
||||||
onQrCodeAccepted = onQrCodeApproved,
|
onQrCodeAccepted = onQrCodeApproved,
|
||||||
onQrCodeDismissed = onQrCodeDismissed,
|
onQrCodeDismissed = onQrCodeDismissed,
|
||||||
onQrCodeRetry = onQrCodeRetry,
|
onQrCodeRetry = onQrCodeRetry,
|
||||||
pendingBiometrics = state.pendingBiometrics,
|
|
||||||
linkDeviceResult = state.linkDeviceResult,
|
linkDeviceResult = state.linkDeviceResult,
|
||||||
onLinkDeviceSuccess = onLinkDeviceSuccess,
|
onLinkDeviceSuccess = onLinkDeviceSuccess,
|
||||||
onLinkDeviceFailure = onLinkDeviceFailure,
|
onLinkDeviceFailure = onLinkDeviceFailure,
|
||||||
|
|
|
@ -3,6 +3,9 @@ package org.thoughtcrime.securesms.linkdevice
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.biometric.BiometricManager
|
||||||
|
import androidx.biometric.BiometricPrompt
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
@ -59,6 +62,9 @@ import org.signal.core.ui.Dividers
|
||||||
import org.signal.core.ui.Previews
|
import org.signal.core.ui.Previews
|
||||||
import org.signal.core.ui.Scaffolds
|
import org.signal.core.ui.Scaffolds
|
||||||
import org.signal.core.ui.SignalPreview
|
import org.signal.core.ui.SignalPreview
|
||||||
|
import org.signal.core.util.logging.Log
|
||||||
|
import org.thoughtcrime.securesms.BiometricDeviceAuthentication
|
||||||
|
import org.thoughtcrime.securesms.BiometricDeviceLockContract
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
|
@ -72,12 +78,40 @@ private const val PLACEHOLDER = "__ICON_PLACEHOLDER__"
|
||||||
*/
|
*/
|
||||||
class LinkDeviceFragment : ComposeFragment() {
|
class LinkDeviceFragment : ComposeFragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = Log.tag(LinkDeviceFragment::class)
|
||||||
|
}
|
||||||
|
|
||||||
private val viewModel: LinkDeviceViewModel by activityViewModels()
|
private val viewModel: LinkDeviceViewModel by activityViewModels()
|
||||||
|
private lateinit var biometricAuth: BiometricDeviceAuthentication
|
||||||
|
private lateinit var biometricDeviceLockLauncher: ActivityResultLauncher<String>
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
viewModel.initialize(requireContext())
|
viewModel.initialize(requireContext())
|
||||||
|
|
||||||
|
biometricDeviceLockLauncher = registerForActivityResult(BiometricDeviceLockContract()) { result: Int ->
|
||||||
|
if (result == BiometricDeviceAuthentication.AUTHENTICATED) {
|
||||||
|
findNavController().safeNavigate(R.id.action_linkDeviceFragment_to_addLinkDeviceFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
|
.setAllowedAuthenticators(BiometricDeviceAuthentication.ALLOWED_AUTHENTICATORS)
|
||||||
|
.setTitle(requireContext().getString(R.string.LinkDeviceFragment__unlock_to_link))
|
||||||
|
.setConfirmationRequired(true)
|
||||||
|
.build()
|
||||||
|
biometricAuth = BiometricDeviceAuthentication(
|
||||||
|
BiometricManager.from(requireActivity()),
|
||||||
|
BiometricPrompt(requireActivity(), BiometricAuthenticationListener()),
|
||||||
|
promptInfo
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
biometricAuth.cancelAuthentication()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -110,7 +144,13 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||||
navController = navController,
|
navController = navController,
|
||||||
modifier = Modifier.padding(contentPadding),
|
modifier = Modifier.padding(contentPadding),
|
||||||
onLearnMore = { navController.safeNavigate(R.id.action_linkDeviceFragment_to_linkDeviceLearnMoreBottomSheet) },
|
onLearnMore = { navController.safeNavigate(R.id.action_linkDeviceFragment_to_linkDeviceLearnMoreBottomSheet) },
|
||||||
onLinkDevice = { navController.safeNavigate(R.id.action_linkDeviceFragment_to_addLinkDeviceFragment) },
|
onLinkDevice = {
|
||||||
|
if (biometricAuth.canAuthenticate()) {
|
||||||
|
biometricAuth.authenticate(requireContext(), true) { biometricDeviceLockLauncher.launch(getString(R.string.LinkDeviceFragment__unlock_to_link)) }
|
||||||
|
} else {
|
||||||
|
navController.safeNavigate(R.id.action_linkDeviceFragment_to_addLinkDeviceFragment)
|
||||||
|
}
|
||||||
|
},
|
||||||
setDeviceToRemove = { device -> viewModel.setDeviceToRemove(device) },
|
setDeviceToRemove = { device -> viewModel.setDeviceToRemove(device) },
|
||||||
onRemoveDevice = { device -> viewModel.removeDevice(requireContext(), device) }
|
onRemoveDevice = { device -> viewModel.removeDevice(requireContext(), device) }
|
||||||
)
|
)
|
||||||
|
@ -122,6 +162,22 @@ class LinkDeviceFragment : ComposeFragment() {
|
||||||
requireActivity().finishAfterTransition()
|
requireActivity().finishAfterTransition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inner class BiometricAuthenticationListener : BiometricPrompt.AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errorString: CharSequence) {
|
||||||
|
Log.w(TAG, "Authentication error: $errorCode")
|
||||||
|
onAuthenticationFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
|
Log.i(TAG, "Authentication succeeded")
|
||||||
|
findNavController().safeNavigate(R.id.action_linkDeviceFragment_to_addLinkDeviceFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
Log.w(TAG, "Unable to authenticate")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
@ -33,7 +33,6 @@ fun LinkDeviceQrScanScreen(
|
||||||
onQrCodeAccepted: () -> Unit,
|
onQrCodeAccepted: () -> Unit,
|
||||||
onQrCodeDismissed: () -> Unit,
|
onQrCodeDismissed: () -> Unit,
|
||||||
onQrCodeRetry: () -> Unit,
|
onQrCodeRetry: () -> Unit,
|
||||||
pendingBiometrics: Boolean,
|
|
||||||
linkDeviceResult: LinkDeviceRepository.LinkDeviceResult,
|
linkDeviceResult: LinkDeviceRepository.LinkDeviceResult,
|
||||||
onLinkDeviceSuccess: () -> Unit,
|
onLinkDeviceSuccess: () -> Unit,
|
||||||
onLinkDeviceFailure: () -> Unit,
|
onLinkDeviceFailure: () -> Unit,
|
||||||
|
@ -95,13 +94,9 @@ fun LinkDeviceQrScanScreen(
|
||||||
view
|
view
|
||||||
},
|
},
|
||||||
update = { view: QrScannerView ->
|
update = { view: QrScannerView ->
|
||||||
if (pendingBiometrics) {
|
view.start(lifecycleOwner = lifecycleOwner, forceLegacy = CameraXModelBlocklist.isBlocklisted())
|
||||||
view.destroy()
|
if (showFrontCamera != null) {
|
||||||
} else {
|
view.toggleCamera()
|
||||||
view.start(lifecycleOwner = lifecycleOwner, forceLegacy = CameraXModelBlocklist.isBlocklisted())
|
|
||||||
if (showFrontCamera != null) {
|
|
||||||
view.toggleCamera()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hasPermission = hasPermission,
|
hasPermission = hasPermission,
|
||||||
|
|
|
@ -17,6 +17,5 @@ data class LinkDeviceSettingsState(
|
||||||
val linkDeviceResult: LinkDeviceRepository.LinkDeviceResult = LinkDeviceRepository.LinkDeviceResult.UNKNOWN,
|
val linkDeviceResult: LinkDeviceRepository.LinkDeviceResult = LinkDeviceRepository.LinkDeviceResult.UNKNOWN,
|
||||||
val showFinishedSheet: Boolean = false,
|
val showFinishedSheet: Boolean = false,
|
||||||
val seenIntroSheet: Boolean = false,
|
val seenIntroSheet: Boolean = false,
|
||||||
val pendingBiometrics: Boolean = false,
|
|
||||||
val pendingNewDevice: Boolean = false
|
val pendingNewDevice: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
|
@ -98,8 +98,7 @@ class LinkDeviceViewModel : ViewModel() {
|
||||||
_state.update {
|
_state.update {
|
||||||
val frontCamera = it.showFrontCamera
|
val frontCamera = it.showFrontCamera
|
||||||
it.copy(
|
it.copy(
|
||||||
showFrontCamera = if (frontCamera == null) true else !frontCamera,
|
showFrontCamera = if (frontCamera == null) true else !frontCamera
|
||||||
pendingBiometrics = false
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,16 +139,6 @@ class LinkDeviceViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onQrCodeApproved() {
|
|
||||||
_state.update {
|
|
||||||
it.copy(
|
|
||||||
qrCodeFound = false,
|
|
||||||
qrCodeInvalid = false,
|
|
||||||
pendingBiometrics = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onQrCodeDismissed() {
|
fun onQrCodeDismissed() {
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
@ -159,21 +148,14 @@ class LinkDeviceViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearBiometrics() {
|
|
||||||
_state.update {
|
|
||||||
it.copy(
|
|
||||||
pendingBiometrics = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addDevice() {
|
fun addDevice() {
|
||||||
val uri = Uri.parse(_state.value.url)
|
val uri = Uri.parse(_state.value.url)
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val result = LinkDeviceRepository.addDevice(uri)
|
val result = LinkDeviceRepository.addDevice(uri)
|
||||||
_state.update {
|
_state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
pendingBiometrics = false,
|
qrCodeFound = false,
|
||||||
|
qrCodeInvalid = false,
|
||||||
linkDeviceResult = result,
|
linkDeviceResult = result,
|
||||||
url = ""
|
url = ""
|
||||||
)
|
)
|
||||||
|
|
|
@ -869,7 +869,7 @@
|
||||||
<!-- Text explaining that on linked devices, messages will be encrypted where %s will be replaced with an image-->
|
<!-- Text explaining that on linked devices, messages will be encrypted where %s will be replaced with an image-->
|
||||||
<string name="LinkDeviceFragment__messages_and_chat_info_are_protected">%1$s Messages and chat info are protected by end-to-end encryption on all devices</string>
|
<string name="LinkDeviceFragment__messages_and_chat_info_are_protected">%1$s Messages and chat info are protected by end-to-end encryption on all devices</string>
|
||||||
<!-- Bottom sheet title explaining how Signal works on a linked device -->
|
<!-- Bottom sheet title explaining how Signal works on a linked device -->
|
||||||
<string name="LinkDeviceFragment__signal_on_desktop_ipad">Signal on Desktop or iPad</string>
|
<string name="LinkDeviceFragment__signal_on_desktop_ipad">Signal on desktop or iPad</string>
|
||||||
<!-- Bottom sheet description explaining that messages on linked devices are private -->
|
<!-- Bottom sheet description explaining that messages on linked devices are private -->
|
||||||
<string name="LinkDeviceFragment__all_messaging_is_private">All messaging on linked devices is private</string>
|
<string name="LinkDeviceFragment__all_messaging_is_private">All messaging on linked devices is private</string>
|
||||||
<!-- Bottom sheet description explaining that future messages on linked devices will be in sync with your phone but previous messages will not appear -->
|
<!-- Bottom sheet description explaining that future messages on linked devices will be in sync with your phone but previous messages will not appear -->
|
||||||
|
@ -891,6 +891,8 @@
|
||||||
<string name="LinkDeviceFragment__loading">Loading…</string>
|
<string name="LinkDeviceFragment__loading">Loading…</string>
|
||||||
<!-- Text message shown when the user has no linked devices -->
|
<!-- Text message shown when the user has no linked devices -->
|
||||||
<string name="LinkDeviceFragment__no_linked_devices">No linked devices</string>
|
<string name="LinkDeviceFragment__no_linked_devices">No linked devices</string>
|
||||||
|
<!-- Title on biometrics prompt explaining what biometrics are being used for -->
|
||||||
|
<string name="LinkDeviceFragment__unlock_to_link">Unlock to link a device</string>
|
||||||
|
|
||||||
<!-- AddLinkDeviceFragment -->
|
<!-- AddLinkDeviceFragment -->
|
||||||
<!-- Description text shown on the QR code scanner when linking a device -->
|
<!-- Description text shown on the QR code scanner when linking a device -->
|
||||||
|
|
|
@ -23,7 +23,6 @@ class QrScannerView @JvmOverloads constructor(
|
||||||
|
|
||||||
private var scannerView: ScannerView? = null
|
private var scannerView: ScannerView? = null
|
||||||
private val qrDataPublish: PublishSubject<String> = PublishSubject.create()
|
private val qrDataPublish: PublishSubject<String> = PublishSubject.create()
|
||||||
private var forceLegacy: Boolean = false
|
|
||||||
|
|
||||||
val qrData: Observable<String> = qrDataPublish
|
val qrData: Observable<String> = qrDataPublish
|
||||||
|
|
||||||
|
@ -38,14 +37,12 @@ class QrScannerView @JvmOverloads constructor(
|
||||||
addView(scannerView)
|
addView(scannerView)
|
||||||
|
|
||||||
this.scannerView = (scannerView as ScannerView)
|
this.scannerView = (scannerView as ScannerView)
|
||||||
this.forceLegacy = forceLegacy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun start(lifecycleOwner: LifecycleOwner, forceLegacy: Boolean = false) {
|
fun start(lifecycleOwner: LifecycleOwner, forceLegacy: Boolean = false) {
|
||||||
if (scannerView != null) {
|
if (scannerView != null) {
|
||||||
Log.w(TAG, "Attempt to start scanning that has already started")
|
Log.w(TAG, "Attempt to start scanning that has already started")
|
||||||
scannerView?.resume()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,14 +61,6 @@ class QrScannerView @JvmOverloads constructor(
|
||||||
scannerView?.toggleCamera()
|
scannerView?.toggleCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Biometrics require use of camera so we disable when needed
|
|
||||||
fun destroy() {
|
|
||||||
scannerView?.destroy()
|
|
||||||
if (!forceLegacy) {
|
|
||||||
scannerView = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = Log.tag(QrScannerView::class.java)
|
private val TAG = Log.tag(QrScannerView::class.java)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,4 @@ import androidx.lifecycle.LifecycleOwner
|
||||||
interface ScannerView {
|
interface ScannerView {
|
||||||
fun start(lifecycleOwner: LifecycleOwner)
|
fun start(lifecycleOwner: LifecycleOwner)
|
||||||
fun toggleCamera()
|
fun toggleCamera()
|
||||||
fun resume()
|
|
||||||
fun destroy()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,16 +59,4 @@ internal class ScannerView19 constructor(
|
||||||
lifecycleObserver.onResume(it)
|
lifecycleObserver.onResume(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resume() {
|
|
||||||
lifecycleOwner?.let {
|
|
||||||
lifecycleObserver.onResume(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun destroy() {
|
|
||||||
lifecycleOwner?.let {
|
|
||||||
lifecycleObserver.onPause(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ internal class ScannerView21 constructor(
|
||||||
|
|
||||||
private val lifecycleObserver: DefaultLifecycleObserver = object : DefaultLifecycleObserver {
|
private val lifecycleObserver: DefaultLifecycleObserver = object : DefaultLifecycleObserver {
|
||||||
override fun onDestroy(owner: LifecycleOwner) {
|
override fun onDestroy(owner: LifecycleOwner) {
|
||||||
cameraProvider?.unbindAll()
|
|
||||||
cameraProvider = null
|
cameraProvider = null
|
||||||
camera = null
|
camera = null
|
||||||
analyzerExecutor.shutdown()
|
analyzerExecutor.shutdown()
|
||||||
|
@ -79,14 +78,6 @@ internal class ScannerView21 constructor(
|
||||||
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
|
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resume() = Unit
|
|
||||||
|
|
||||||
override fun destroy() {
|
|
||||||
lifecyleOwner?.let {
|
|
||||||
lifecycleObserver.onDestroy(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onCameraProvider(lifecycle: LifecycleOwner, cameraProvider: ProcessCameraProvider?) {
|
private fun onCameraProvider(lifecycle: LifecycleOwner, cameraProvider: ProcessCameraProvider?) {
|
||||||
if (cameraProvider == null) {
|
if (cameraProvider == null) {
|
||||||
Log.w(TAG, "Camera provider is null")
|
Log.w(TAG, "Camera provider is null")
|
||||||
|
|
Loading…
Add table
Reference in a new issue