= rotationViewModel.liveData
- lastRotation = rotationLiveData.value!!
- if (!errorDialogViewModel.isDialogShown) {
- animation?.let {
- Log.d(TAG, "onResume(), start animation")
- it.startAnimation()
- }
- }
- super.onResume()
- }
-
- override fun onPause() {
- animation?.let {
- if (DEBUG) {
- Log.d(TAG, "onPause(), pause animation")
- }
- it.pauseAnimation()
- }
- super.onPause()
- }
-
- override fun onStop() {
- super.onStop()
- removeEnrollmentObservers()
- val isEnrolling = progressViewModel.isEnrolling
- val isConfigChange = requireActivity().isChangingConfigurations
- Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
- if (isEnrolling && !isConfigChange) {
- cancelEnrollment(false)
- }
- }
-
- private fun removeEnrollmentObservers() {
- progressViewModel.progressLiveData.removeObserver(progressObserver)
- progressViewModel.helpMessageLiveData.removeObserver(errorMessageObserver)
- }
-
- private fun startEnrollment() {
- enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_FIND_SENSOR)
- if (enrollingCancelSignal == null) {
- Log.e(TAG, "startEnrollment(), failed to start enrollment")
- } else {
- Log.d(TAG, "startEnrollment(), success")
- }
- progressViewModel.progressLiveData.observe(this, progressObserver)
- progressViewModel.errorMessageLiveData.observe(this, errorMessageObserver)
- }
-
- private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
- if (!progressViewModel.isEnrolling) {
- Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
- return
- }
- removeEnrollmentObservers()
- if (waitForLastCancelErrMsg) {
- progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
- } else {
- enrollingCancelSignal = null
- }
- val cancelResult: Boolean = progressViewModel.cancelEnrollment()
- if (!cancelResult) {
- Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
- }
- }
-
- private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
- cancelEnrollment(false)
- lifecycleScope.launch {
- Log.d(TAG, "newDialogFlow as $errorMessage")
- errorDialogViewModel.newDialog(errorMessage.msgId)
- }
- }
-
- private fun onEnrollmentCanceled(canceledSignal: Any) {
- Log.d(
- TAG,
- "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
- )
- if (enrollingCancelSignal === canceledSignal) {
- val progress: EnrollmentProgress? = progressViewModel.progressLiveData.value
- progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
- progressViewModel.clearProgressLiveData()
- if (progress != null && !progress.isInitialStep) {
- viewModel.onStartButtonClick()
- }
- }
- }
-
- override fun onDestroy() {
- animation?.let {
- if (DEBUG) {
- Log.d(TAG, "onDestroy(), stop animation")
- }
- it.stopAnimation()
- }
- super.onDestroy()
- }
-
- override fun onAttach(context: Context) {
- ViewModelProvider(requireActivity()).let { provider ->
- _viewModel = provider[FingerprintEnrollFindSensorViewModel::class.java]
- _progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
- _rotationViewModel = provider[DeviceRotationViewModel::class.java]
- _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
- }
- super.onAttach(context)
- }
-
- companion object {
- private const val DEBUG = false
- private const val TAG = "FingerprintEnrollFindRfpsFragment"
- }
-}
-
-fun FragmentActivity.bindFingerprintEnrollFindRfpsView(
- view: GlifLayout,
- onSkipClickListener: View.OnClickListener,
-) {
- GlifLayoutHelper(this, view).let {
- it.setHeaderText(
- R.string.security_settings_fingerprint_enroll_find_sensor_title
- )
- it.setDescriptionText(
- getText(R.string.security_settings_fingerprint_enroll_find_sensor_message)
- )
- }
-
- view.getMixin(FooterBarMixin::class.java).secondaryButton =
- FooterButton.Builder(this)
- .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
- .setButtonType(FooterButton.ButtonType.SKIP)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
- .build()
- .also {
- it.setOnClickListener(onSkipClickListener)
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt
deleted file mode 100644
index 7455be1deda..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindSfpsFragment.kt
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.content.Context
-import android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR
-import android.os.Bundle
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.Surface
-import android.view.View
-import android.view.ViewGroup
-import androidx.annotation.RawRes
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.airbnb.lottie.LottieAnimationView
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.model.EnrollmentProgress
-import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage
-import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
-import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
-import com.android.settingslib.widget.LottieColorUtils
-import com.google.android.setupcompat.template.FooterBarMixin
-import com.google.android.setupcompat.template.FooterButton
-import com.google.android.setupdesign.GlifLayout
-import kotlinx.coroutines.launch
-
-/**
- * Fragment explaining the side fingerprint sensor location for fingerprint enrollment.
- * It interacts with ProgressViewModel, FoldCallback (for different lottie), and
- * LottieAnimationView.
- *
- * | Has | UDFPS | SFPS | Other (Rear FPS) |
- * |---------------------|-------|------|------------------|
- * | Primary button | Yes | No | No |
- * | Illustration Lottie | Yes | Yes | No |
- * | Animation | No | No | Depend on layout |
- * | Progress ViewModel | No | Yes | Yes |
- * | Orientation detect | No | Yes | No |
- * | Foldable detect | No | Yes | No |
- *
- */
-class FingerprintEnrollFindSfpsFragment : Fragment() {
-
- private var _viewModel: FingerprintEnrollFindSensorViewModel? = null
- private val viewModel: FingerprintEnrollFindSensorViewModel
- get() = _viewModel!!
-
- private var _progressViewModel: FingerprintEnrollProgressViewModel? = null
- private val progressViewModel: FingerprintEnrollProgressViewModel
- get() = _progressViewModel!!
-
- private var _rotationViewModel: DeviceRotationViewModel? = null
- private val rotationViewModel: DeviceRotationViewModel
- get() = _rotationViewModel!!
-
- private var _foldedViewModel: DeviceFoldedViewModel? = null
- private val foldedViewModel: DeviceFoldedViewModel
- get() = _foldedViewModel!!
-
- private var _errorDialogViewModel: FingerprintEnrollErrorDialogViewModel? = null
- private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel
- get() = _errorDialogViewModel!!
-
- private var findSfpsView: GlifLayout? = null
-
- private val onSkipClickListener =
- View.OnClickListener { _: View? -> viewModel.onSkipButtonClick() }
-
- private val illustrationLottie: LottieAnimationView
- get() = findSfpsView!!.findViewById(R.id.illustration_lottie)!!
-
- private var enrollingCancelSignal: Any? = null
-
- @Surface.Rotation
- private var animationRotation = -1
-
- private val rotationObserver = Observer { rotation: Int? ->
- rotation?.let { onRotationChanged(it) }
- }
-
- private val progressObserver = Observer { progress: EnrollmentProgress? ->
- if (progress != null && !progress.isInitialStep) {
- cancelEnrollment(true)
- }
- }
-
- private val errorMessageObserver = Observer{ errorMessage: EnrollmentStatusMessage? ->
- Log.d(TAG, "errorMessageObserver($errorMessage)")
- errorMessage?.let { onEnrollmentError(it) }
- }
-
- private val canceledSignalObserver = Observer { canceledSignal: Any? ->
- canceledSignal?.let { onEnrollmentCanceled(it) }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View = (inflater.inflate(
- R.layout.sfps_enroll_find_sensor_layout,
- container,
- false
- ) as GlifLayout).also {
- findSfpsView = it
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- requireActivity().bindFingerprintEnrollFindSfpsView(
- view = findSfpsView!!,
- onSkipClickListener = onSkipClickListener
- )
-
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- errorDialogViewModel.triggerRetryFlow.collect { startEnrollment() }
- }
- }
- }
-
- override fun onStart() {
- super.onStart()
- val isErrorDialogShown = errorDialogViewModel.isDialogShown
- Log.d(TAG, "onStart(), isEnrolling:${progressViewModel.isEnrolling}"
- + ", isErrorDialog:$isErrorDialogShown")
- if (!isErrorDialogShown) {
- startEnrollment()
- }
- }
-
- override fun onResume() {
- super.onResume()
- val rotationLiveData: LiveData = rotationViewModel.liveData
- playLottieAnimation(rotationLiveData.value!!)
- rotationLiveData.observe(this, rotationObserver)
- }
-
- override fun onPause() {
- rotationViewModel.liveData.removeObserver(rotationObserver)
- super.onPause()
- }
-
- override fun onStop() {
- super.onStop()
- val isEnrolling = progressViewModel.isEnrolling
- val isConfigChange = requireActivity().isChangingConfigurations
- Log.d(TAG, "onStop(), enrolling:$isEnrolling isConfigChange:$isConfigChange")
- if (isEnrolling && !isConfigChange) {
- cancelEnrollment(false)
- }
- }
-
- private fun removeEnrollmentObservers() {
- progressViewModel.errorMessageLiveData.removeObserver(errorMessageObserver)
- progressViewModel.progressLiveData.removeObserver(progressObserver)
- }
-
- private fun startEnrollment() {
- enrollingCancelSignal = progressViewModel.startEnrollment(ENROLL_FIND_SENSOR)
- if (enrollingCancelSignal == null) {
- Log.e(TAG, "startEnrollment(), failed to start enrollment")
- } else {
- Log.d(TAG, "startEnrollment(), success")
- }
- progressViewModel.progressLiveData.observe(this, progressObserver)
- progressViewModel.errorMessageLiveData.observe(this, errorMessageObserver)
- }
-
- private fun cancelEnrollment(waitForLastCancelErrMsg: Boolean) {
- if (!progressViewModel.isEnrolling) {
- Log.d(TAG, "cancelEnrollment(), failed because isEnrolling is false")
- return
- }
- removeEnrollmentObservers()
- if (waitForLastCancelErrMsg) {
- progressViewModel.canceledSignalLiveData.observe(this, canceledSignalObserver)
- } else {
- enrollingCancelSignal = null
- }
- val cancelResult: Boolean = progressViewModel.cancelEnrollment()
- if (!cancelResult) {
- Log.e(TAG, "cancelEnrollment(), failed to cancel enrollment")
- }
- }
-
- private fun onRotationChanged(@Surface.Rotation newRotation: Int) {
- if (DEBUG) {
- Log.d(TAG, "onRotationChanged() from $animationRotation to $newRotation")
- }
- if ((newRotation + 2) % 4 == animationRotation) {
- // Fragment not changed, we just need to play correct rotation animation
- playLottieAnimation(newRotation)
- }
- }
-
- private fun onEnrollmentError(errorMessage: EnrollmentStatusMessage) {
- progressViewModel.cancelEnrollment()
- lifecycleScope.launch {
- Log.d(TAG, "newDialogFlow as $errorMessage")
- errorDialogViewModel.newDialog(errorMessage.msgId)
- }
- }
-
- private fun onEnrollmentCanceled(canceledSignal: Any) {
- Log.d(
- TAG,
- "onEnrollmentCanceled enrolling:$enrollingCancelSignal, canceled:$canceledSignal"
- )
- if (enrollingCancelSignal === canceledSignal) {
- val progress: EnrollmentProgress? = progressViewModel.progressLiveData.value
- progressViewModel.canceledSignalLiveData.removeObserver(canceledSignalObserver)
- progressViewModel.clearProgressLiveData()
- if (progress != null && !progress.isInitialStep) {
- viewModel.onStartButtonClick()
- }
- }
- }
-
- private fun playLottieAnimation(@Surface.Rotation rotation: Int) {
- @RawRes val animationRawRes = getSfpsLottieAnimationRawRes(rotation)
- Log.d(
- TAG,
- "play lottie animation $animationRawRes, previous rotation:$animationRotation"
- + ", new rotation:" + rotation
- )
- animationRotation = rotation
- illustrationLottie.setAnimation(animationRawRes)
- LottieColorUtils.applyDynamicColors(activity, illustrationLottie)
- illustrationLottie.visibility = View.VISIBLE
- illustrationLottie.playAnimation()
- }
-
- @RawRes
- private fun getSfpsLottieAnimationRawRes(@Surface.Rotation rotation: Int): Int {
- val isFolded = java.lang.Boolean.FALSE != foldedViewModel.liveData.value
- return when (rotation) {
- Surface.ROTATION_90 ->
- if (isFolded)
- R.raw.fingerprint_edu_lottie_folded_top_left
- else
- R.raw.fingerprint_edu_lottie_portrait_top_left
- Surface.ROTATION_180 ->
- if (isFolded)
- R.raw.fingerprint_edu_lottie_folded_bottom_left
- else
- R.raw.fingerprint_edu_lottie_landscape_bottom_left
- Surface.ROTATION_270 ->
- if (isFolded)
- R.raw.fingerprint_edu_lottie_folded_bottom_right
- else
- R.raw.fingerprint_edu_lottie_portrait_bottom_right
- else ->
- if (isFolded)
- R.raw.fingerprint_edu_lottie_folded_top_right
- else
- R.raw.fingerprint_edu_lottie_landscape_top_right
- }
- }
-
- override fun onAttach(context: Context) {
- ViewModelProvider(requireActivity()).let { provider ->
- _viewModel = provider[FingerprintEnrollFindSensorViewModel::class.java]
- _progressViewModel = provider[FingerprintEnrollProgressViewModel::class.java]
- _rotationViewModel = provider[DeviceRotationViewModel::class.java]
- _foldedViewModel = provider[DeviceFoldedViewModel::class.java]
- _errorDialogViewModel = provider[FingerprintEnrollErrorDialogViewModel::class.java]
- }
- super.onAttach(context)
- }
-
- companion object {
- private const val DEBUG = false
- private const val TAG = "FingerprintEnrollFindSfpsFragment"
- }
-}
-
-fun FragmentActivity.bindFingerprintEnrollFindSfpsView(
- view: GlifLayout,
- onSkipClickListener: View.OnClickListener
-) {
- view.getMixin(FooterBarMixin::class.java).let {
- it.secondaryButton = FooterButton.Builder(this)
- .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
- .setButtonType(FooterButton.ButtonType.SKIP)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
- .build()
- it.secondaryButton.setOnClickListener(onSkipClickListener)
- }
-
- GlifLayoutHelper(this, view).let {
- it.setHeaderText(R.string.security_settings_sfps_enroll_find_sensor_title)
- it.setDescriptionText(
- getText(R.string.security_settings_sfps_enroll_find_sensor_message)
- )
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindUdfpsFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindUdfpsFragment.kt
deleted file mode 100644
index 3dce99c5380..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFindUdfpsFragment.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.content.Context
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.ViewModelProvider
-import com.airbnb.lottie.LottieAnimationView
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
-import com.google.android.setupcompat.template.FooterBarMixin
-import com.google.android.setupcompat.template.FooterButton
-import com.google.android.setupdesign.GlifLayout
-
-/**
- * Fragment explaining the under-display fingerprint sensor location for fingerprint enrollment.
- * It interacts with Primary button, and LottieAnimationView.
- *
- * | Has | UDFPS | SFPS | Other (Rear FPS) |
- * |---------------------|-------|------|------------------|
- * | Primary button | Yes | No | No |
- * | Illustration Lottie | Yes | Yes | No |
- * | Animation | No | No | Depend on layout |
- * | Progress ViewModel | No | Yes | Yes |
- * | Orientation detect | No | Yes | No |
- * | Foldable detect | No | Yes | No |
- *
- */
-class FingerprintEnrollFindUdfpsFragment : Fragment() {
-
- private var _viewModel: FingerprintEnrollFindSensorViewModel? = null
- private val mViewModel: FingerprintEnrollFindSensorViewModel
- get() = _viewModel!!
-
- private var findUdfpsView: GlifLayout? = null
-
- private val mOnSkipClickListener =
- View.OnClickListener { _: View? -> mViewModel.onSkipButtonClick() }
-
- private val mOnStartClickListener =
- View.OnClickListener { _: View? -> mViewModel.onStartButtonClick() }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View = (inflater.inflate(
- R.layout.udfps_enroll_find_sensor_layout,
- container,
- false
- ) as GlifLayout).also {
- findUdfpsView = it
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- requireActivity().bindFingerprintEnrollFindUdfpsView(
- view = findUdfpsView!!,
- isAccessibilityEnabled = mViewModel.isAccessibilityEnabled,
- onSkipClickListener = mOnSkipClickListener,
- onStartClickListener = mOnStartClickListener
- )
- }
-
- override fun onAttach(context: Context) {
- _viewModel = ViewModelProvider(requireActivity())[
- FingerprintEnrollFindSensorViewModel::class.java
- ]
- super.onAttach(context)
- }
-}
-
-fun FragmentActivity.bindFingerprintEnrollFindUdfpsView(
- view: GlifLayout,
- isAccessibilityEnabled: Boolean,
- onSkipClickListener: View.OnClickListener,
- onStartClickListener: View.OnClickListener,
-) {
- GlifLayoutHelper(this, view).let { helper ->
- helper.setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title)
- helper.setDescriptionText(
- getText(R.string.security_settings_udfps_enroll_find_sensor_message)
- )
- }
-
- view.getMixin(FooterBarMixin::class.java)!!.let {
- it.secondaryButton = FooterButton.Builder(this)
- .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
- .setButtonType(FooterButton.ButtonType.SKIP)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
- .build()
- it.secondaryButton.setOnClickListener(onSkipClickListener)
-
- it.primaryButton = FooterButton.Builder(this)
- .setText(R.string.security_settings_udfps_enroll_find_sensor_start_button)
- .setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
- .build()
- it.primaryButton.setOnClickListener(onStartClickListener)
- }
-
- view.findViewById(R.id.illustration_lottie)!!.let {
- it.setOnClickListener(onStartClickListener)
- if (isAccessibilityEnabled) {
- it.setAnimation(R.raw.udfps_edu_a11y_lottie)
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFinishFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFinishFragment.kt
deleted file mode 100644
index 2af2deeebce..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollFinishFragment.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.content.Context
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.ViewModelProvider
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel
-import com.google.android.setupcompat.template.FooterBarMixin
-import com.google.android.setupcompat.template.FooterButton
-import com.google.android.setupdesign.GlifLayout
-
-/**
- * Fragment which concludes fingerprint enrollment.
- */
-class FingerprintEnrollFinishFragment : Fragment() {
-
- private var _viewModel: FingerprintEnrollFinishViewModel? = null
- private val viewModel: FingerprintEnrollFinishViewModel
- get() = _viewModel!!
-
- private val addButtonClickListener =
- View.OnClickListener { _: View? -> viewModel.onAddButtonClick() }
-
- private val nextButtonClickListener =
- View.OnClickListener { _: View? -> viewModel.onNextButtonClick() }
- override fun onAttach(context: Context) {
- super.onAttach(context)
- _viewModel = ViewModelProvider(requireActivity())[
- FingerprintEnrollFinishViewModel::class.java
- ]
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ) : View = (inflater.inflate(
- if (viewModel.canAssumeSfps())
- R.layout.sfps_enroll_finish
- else
- R.layout.fingerprint_enroll_finish,
- container,
- false
- ) as GlifLayout).also {
- requireActivity().bindFingerprintEnrollFinishFragment(
- view = it,
- isSuw = viewModel.request.isSuw,
- canAssumeSfps = viewModel.canAssumeSfps(),
- isAnotherFingerprintEnrollable = viewModel.isAnotherFingerprintEnrollable,
- nextButtonClickListener = nextButtonClickListener,
- addButtonClickListener = addButtonClickListener
- )
- }
-}
-
-fun FragmentActivity.bindFingerprintEnrollFinishFragment(
- view: GlifLayout,
- isSuw: Boolean,
- canAssumeSfps: Boolean,
- isAnotherFingerprintEnrollable: Boolean,
- nextButtonClickListener: View.OnClickListener,
- addButtonClickListener: View.OnClickListener
-) {
- GlifLayoutHelper(this, view).apply {
- setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title)
- setDescriptionText(
- getString(
- if (canAssumeSfps && isAnotherFingerprintEnrollable)
- R.string.security_settings_fingerprint_enroll_finish_v2_add_fingerprint_message
- else
- R.string.security_settings_fingerprint_enroll_finish_v2_message
- )
- )
- }
-
- view.getMixin(FooterBarMixin::class.java).also { footer ->
- footer.primaryButton = FooterButton.Builder(this)
- .setText(
- if (isSuw)
- R.string.next_label
- else
- R.string.security_settings_fingerprint_enroll_done
- )
- .setListener(nextButtonClickListener)
- .setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
- .build()
- if (isAnotherFingerprintEnrollable) {
- footer.secondaryButton = FooterButton.Builder(this)
- .setText(R.string.fingerprint_enroll_button_add)
- .setListener(addButtonClickListener)
- .setButtonType(FooterButton.ButtonType.SKIP)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
- .build()
- }
- }
-
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt
deleted file mode 100644
index d1b37994679..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollIntroFragment.kt
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.app.admin.DevicePolicyManager
-import android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED
-import android.content.Context
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffColorFilter
-import android.os.Bundle
-import android.text.Html
-import android.text.method.LinkMovementMethod
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.ScrollView
-import android.widget.TextView
-import androidx.annotation.StringRes
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_UNKNOWN
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel
-import com.google.android.setupcompat.template.FooterBarMixin
-import com.google.android.setupcompat.template.FooterButton
-import com.google.android.setupdesign.GlifLayout
-import com.google.android.setupdesign.template.RequireScrollMixin
-import com.google.android.setupdesign.util.DeviceHelper
-import com.google.android.setupdesign.util.DynamicColorPalette
-import com.google.android.setupdesign.util.DynamicColorPalette.ColorType.ACCENT
-import java.util.function.Supplier
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.launch
-
-/**
- * Fingerprint intro onboarding page fragment implementation
- */
-class FingerprintEnrollIntroFragment : Fragment() {
-
- private val viewModelProvider: ViewModelProvider
- get() = ViewModelProvider(requireActivity())
-
- private var _viewModel: FingerprintEnrollIntroViewModel? = null
- private val viewModel: FingerprintEnrollIntroViewModel
- get() = _viewModel!!
-
- private var introView: GlifLayout? = null
-
- private var primaryFooterButton: FooterButton? = null
-
- private var secondaryFooterButton: FooterButton? = null
-
- private val onNextClickListener =
- View.OnClickListener { _: View? ->
- activity?.lifecycleScope?.let {
- viewModel.onNextButtonClick(it)
- }
- }
-
- private val onSkipOrCancelClickListener =
- View.OnClickListener { _: View? ->
- activity?.lifecycleScope?.let {
- viewModel.onSkipOrCancelButtonClick(it)
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View {
- introView = inflater.inflate(
- R.layout.fingerprint_enroll_introduction,
- container,
- false
- ) as GlifLayout
- return introView!!
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- requireActivity().bindFingerprintEnrollIntroView(
- view = introView!!,
- canAssumeUdfps = viewModel.canAssumeUdfps,
- isBiometricUnlockDisabledByAdmin = viewModel.isBiometricUnlockDisabledByAdmin,
- isParentalConsentRequired = viewModel.isParentalConsentRequired,
- descriptionDisabledByAdminSupplier = { getDescriptionDisabledByAdmin(view.context) }
- )
- }
-
- override fun onStart() {
- val context: Context = requireContext()
- val footerBarMixin: FooterBarMixin = footerBarMixin
- viewModel.updateEnrollableStatus(lifecycleScope)
- initPrimaryFooterButton(context, footerBarMixin)
- initSecondaryFooterButton(context, footerBarMixin)
- collectPageStatusFlowIfNeed()
- super.onStart()
- }
-
- private fun initPrimaryFooterButton(
- context: Context,
- footerBarMixin: FooterBarMixin
- ) {
- if (footerBarMixin.primaryButton != null) {
- return
- }
- primaryFooterButton = FooterButton.Builder(context)
- .setText(R.string.security_settings_fingerprint_enroll_introduction_agree)
- .setButtonType(FooterButton.ButtonType.OPT_IN)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
- .build()
- .also {
- it.setOnClickListener(onNextClickListener)
- footerBarMixin.primaryButton = it
- }
- }
-
- private fun initSecondaryFooterButton(
- context: Context,
- footerBarMixin: FooterBarMixin
- ) {
- if (footerBarMixin.secondaryButton != null) {
- return
- }
- secondaryFooterButton = FooterButton.Builder(context)
- .setText(
- if (viewModel.request.isAfterSuwOrSuwSuggestedAction)
- R.string.security_settings_fingerprint_enroll_introduction_cancel
- else
- R.string.security_settings_fingerprint_enroll_introduction_no_thanks
- )
- .setButtonType(FooterButton.ButtonType.NEXT)
- .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
- .build()
- .also {
- it.setOnClickListener(onSkipOrCancelClickListener)
- footerBarMixin.setSecondaryButton(it, true /* usePrimaryStyle */)
- }
- }
-
- private fun collectPageStatusFlowIfNeed() {
- lifecycleScope.launch {
- val status = viewModel.pageStatusFlow.first()
- Log.d(TAG, "collectPageStatusFlowIfNeed status:$status")
- if (status.hasScrollToBottom()
- || status.enrollableStatus === FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
- ) {
- // Update once and do not requireScrollWithButton() again when page has
- // scrolled to bottom or User has enrolled at least a fingerprint, because if
- // we requireScrollWithButton() again, primary button will become "More" after
- // scrolling.
- updateFooterButtons(status)
- } else {
- introView!!.getMixin(RequireScrollMixin::class.java).let {
- it.requireScrollWithButton(
- requireActivity(),
- primaryFooterButton!!,
- moreButtonTextRes,
- onNextClickListener
- )
- it.setOnRequireScrollStateChangedListener { scrollNeeded: Boolean ->
- viewModel.setHasScrolledToBottom(!scrollNeeded, lifecycleScope)
- }
- }
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- viewModel.pageStatusFlow.collect(
- this@FingerprintEnrollIntroFragment::updateFooterButtons
- )
- }
- }
- }
- }
-
- override fun onAttach(context: Context) {
- _viewModel = viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
- super.onAttach(context)
- }
-
- private val footerBarMixin: FooterBarMixin
- get() = introView!!.getMixin(FooterBarMixin::class.java)
-
- private fun getDescriptionDisabledByAdmin(context: Context): String? {
- val defaultStrId: Int =
- R.string.security_settings_fingerprint_enroll_introduction_message_unlock_disabled
- val devicePolicyManager: DevicePolicyManager =
- checkNotNull(requireActivity().getSystemService(DevicePolicyManager::class.java))
-
- return devicePolicyManager.resources.getString(FINGERPRINT_UNLOCK_DISABLED) {
- context.getString(defaultStrId)
- }
- }
-
- private fun updateFooterButtons(status: FingerprintEnrollIntroStatus) {
- if (DEBUG) {
- Log.d(TAG, "updateFooterButtons($status)")
- }
- primaryFooterButton!!.setText(
- context,
- if (status.enrollableStatus === FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
- R.string.done
- else if (status.hasScrollToBottom())
- R.string.security_settings_fingerprint_enroll_introduction_agree
- else
- moreButtonTextRes
- )
- secondaryFooterButton!!.visibility =
- if (status.hasScrollToBottom()
- && status.enrollableStatus !== FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
- )
- View.VISIBLE
- else
- View.INVISIBLE
-
- view!!.requireViewById(R.id.error_text).let {
- when (status.enrollableStatus) {
- FINGERPRINT_ENROLLABLE_OK -> {
- it.text = null
- it.visibility = View.GONE
- }
-
- FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX -> {
- it.setText(R.string.fingerprint_intro_error_max)
- it.visibility = View.VISIBLE
- }
-
- FINGERPRINT_ENROLLABLE_UNKNOWN -> {}
- }
- }
- }
-
- @get:StringRes
- private val moreButtonTextRes: Int
- get() = R.string.security_settings_face_enroll_introduction_more
-
- companion object {
- private const val TAG = "FingerprintEnrollIntroFragment"
- private const val DEBUG = false
- }
-}
-
-fun FragmentActivity.bindFingerprintEnrollIntroView(
- view: GlifLayout,
- canAssumeUdfps: Boolean,
- isBiometricUnlockDisabledByAdmin: Boolean,
- isParentalConsentRequired: Boolean,
- descriptionDisabledByAdminSupplier: Supplier
-) {
- val context = view.context
-
- val iconFingerprint = view.findViewById(R.id.icon_fingerprint)!!
- val iconDeviceLocked = view.findViewById(R.id.icon_device_locked)!!
- val iconTrashCan = view.findViewById(R.id.icon_trash_can)!!
- val iconInfo = view.findViewById(R.id.icon_info)!!
- val iconShield = view.findViewById(R.id.icon_shield)!!
- val iconLink = view.findViewById(R.id.icon_link)!!
- val footerMessage6 = view.findViewById(R.id.footer_message_6)!!
-
- PorterDuffColorFilter(
- DynamicColorPalette.getColor(context, ACCENT),
- PorterDuff.Mode.SRC_IN
- ).let { colorFilter ->
- iconFingerprint.drawable.colorFilter = colorFilter
- iconDeviceLocked.drawable.colorFilter = colorFilter
- iconTrashCan.drawable.colorFilter = colorFilter
- iconInfo.drawable.colorFilter = colorFilter
- iconShield.drawable.colorFilter = colorFilter
- iconLink.drawable.colorFilter = colorFilter
- }
-
- view.findViewById(R.id.footer_learn_more)!!.let { learnMore ->
- learnMore.movementMethod = LinkMovementMethod.getInstance()
- val footerLinkStr: String = context.getString(
- R.string.security_settings_fingerprint_v2_enroll_introduction_message_learn_more,
- Html.FROM_HTML_MODE_LEGACY
- )
- learnMore.text = Html.fromHtml(footerLinkStr)
- }
-
- if (canAssumeUdfps) {
- footerMessage6.visibility = View.VISIBLE
- iconShield.visibility = View.VISIBLE
- } else {
- footerMessage6.visibility = View.GONE
- iconShield.visibility = View.GONE
- }
- val glifLayoutHelper = GlifLayoutHelper(this, view)
- if (isBiometricUnlockDisabledByAdmin && !isParentalConsentRequired) {
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_fingerprint_enroll_introduction_title_unlock_disabled
- )
- glifLayoutHelper.setDescriptionText(descriptionDisabledByAdminSupplier.get())
- } else {
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_fingerprint_enroll_introduction_title
- )
- glifLayoutHelper.setDescriptionText(
- getString(
- R.string.security_settings_fingerprint_enroll_introduction_v3_message,
- DeviceHelper.getDeviceName(context)
- )
- )
- }
-
- view.findViewById(com.google.android.setupdesign.R.id.sud_scroll_view)
- ?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
deleted file mode 100644
index ec965970699..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollmentActivity.kt
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.annotation.StyleRes
-import android.content.Intent
-import android.content.res.ColorStateList
-import android.content.res.Configuration
-import android.content.res.Resources.Theme
-import android.graphics.Color
-import android.os.Bundle
-import android.os.SystemClock
-import android.util.Log
-import androidx.activity.result.ActivityResult
-import androidx.activity.result.ActivityResultCallback
-import androidx.activity.result.ActivityResultLauncher
-import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
-import androidx.annotation.ColorInt
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import androidx.lifecycle.viewmodel.CreationExtras
-import androidx.lifecycle.viewmodel.MutableCreationExtras
-import com.android.settings.R
-import com.android.settings.Utils
-import com.android.settings.biometrics.BiometricEnrollBase
-import com.android.settings.biometrics2.factory.BiometricsViewModelFactory
-import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY
-import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CREDENTIAL_MODEL_KEY
-import com.android.settings.biometrics2.factory.BiometricsViewModelFactory.ENROLLMENT_REQUEST_KEY
-import com.android.settings.biometrics2.ui.model.CredentialModel
-import com.android.settings.biometrics2.ui.model.EnrollmentRequest
-import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel
-import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator
-import com.android.settings.biometrics2.ui.viewmodel.CredentialAction
-import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollErrorDialogViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FingerprintEnrollFinishAction
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintErrorDialogSetResultAction.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
-import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
-import com.google.android.setupdesign.util.ThemeHelper
-import kotlinx.coroutines.launch
-
-/**
- * Fingerprint enrollment activity implementation
- */
-open class FingerprintEnrollmentActivity : FragmentActivity() {
- /** SetupWizard activity*/
- class SetupActivity : FingerprintEnrollmentActivity()
-
- /** Internal activity for FingerprintSettings */
- class InternalActivity : FingerprintEnrollmentActivity()
-
- private val viewModelProvider: ViewModelProvider by lazy {
- ViewModelProvider(this)
- }
-
- private val viewModel: FingerprintEnrollmentViewModel by lazy {
- viewModelProvider[FingerprintEnrollmentViewModel::class.java]
- }
-
- private val autoCredentialViewModel: AutoCredentialViewModel by lazy {
- viewModelProvider[AutoCredentialViewModel::class.java]
- }
-
- private val introViewModel: FingerprintEnrollIntroViewModel by lazy {
- viewModelProvider[FingerprintEnrollIntroViewModel::class.java]
- }
-
- private val findSensorViewModel: FingerprintEnrollFindSensorViewModel by lazy {
- viewModelProvider[FingerprintEnrollFindSensorViewModel::class.java]
- }
-
- private val progressViewModel: FingerprintEnrollProgressViewModel by lazy {
- viewModelProvider[FingerprintEnrollProgressViewModel::class.java]
- }
-
- private val enrollingViewModel: FingerprintEnrollEnrollingViewModel by lazy {
- viewModelProvider[FingerprintEnrollEnrollingViewModel::class.java]
- }
-
- private val finishViewModel: FingerprintEnrollFinishViewModel by lazy {
- viewModelProvider[FingerprintEnrollFinishViewModel::class.java]
- }
-
- private val errorDialogViewModel: FingerprintEnrollErrorDialogViewModel by lazy {
- viewModelProvider[FingerprintEnrollErrorDialogViewModel::class.java]
- }
-
- private var isFirstFragmentAdded = false
-
- private val findSensorActionObserver = Observer { action ->
- if (DEBUG) {
- Log.d(TAG, "findSensorActionObserver($action)")
- }
- action?.let { onFindSensorAction(it) }
- }
-
- private val enrollingActionObserver = Observer { action ->
- if (DEBUG) {
- Log.d(TAG, "enrollingActionObserver($action)")
- }
- action?.let { onEnrollingAction(it) }
- }
-
- private val finishActionObserver = Observer { action ->
- if (DEBUG) {
- Log.d(TAG, "finishActionObserver($action)")
- }
- action?.let { onFinishAction(it) }
- }
-
- private val chooseLockResultCallback: ActivityResultCallback =
- ActivityResultCallback { result ->
- onChooseOrConfirmLockResult(true /* isChooseLock */, result)
- }
-
- private val chooseLockLauncher: ActivityResultLauncher =
- registerForActivityResult(StartActivityForResult(), chooseLockResultCallback)
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // Theme
- setTheme(viewModel.request.theme)
- ThemeHelper.trySetDynamicColor(this)
- window.statusBarColor = Color.TRANSPARENT
-
- // fragment
- setContentView(R.layout.biometric_enrollment_container)
- val fragment: Fragment? = supportFragmentManager.findFragmentById(
- R.id.fragment_container_view
- )
- Log.d(
- TAG,
- "onCreate() has savedInstance:$(savedInstanceState != null), fragment:$fragment"
- )
-
- isFirstFragmentAdded = (savedInstanceState != null)
- if (fragment == null) {
- checkCredential()
- if (viewModel.request.isSkipFindSensor) {
- startEnrollingFragment()
- } else if (viewModel.request.isSkipIntro) {
- startFindSensorFragment()
- } else {
- startIntroFragment()
- }
- } else {
- val tag: String? = fragment.tag
- if (INTRO_TAG == tag) {
- attachIntroViewModel()
- } else if (FIND_SENSOR_TAG == tag) {
- attachFindSensorViewModel()
- attachIntroViewModel()
- } else if (ENROLLING_TAG == tag) {
- attachEnrollingViewModel()
- attachFindSensorViewModel()
- attachIntroViewModel()
- } else if (FINISH_TAG == tag) {
- attachFinishViewModel()
- attachFindSensorViewModel()
- attachIntroViewModel()
- } else {
- Log.e(TAG, "fragment tag $tag not found")
- finish()
- return
- }
- }
-
- collectFlows()
- }
-
- private fun collectFlows() {
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- viewModel.setResultFlow.collect {
- Log.d(TAG, "setResultLiveData($it)")
- onSetActivityResult(it)
- }
- }
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- autoCredentialViewModel.generateChallengeFailedFlow.collect {
- Log.d(TAG, "generateChallengeFailedFlow($it)")
- onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
- }
- }
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- errorDialogViewModel.newDialogFlow.collect {
- Log.d(TAG, "newErrorDialogFlow($it)")
- FingerprintEnrollErrorDialog.newInstance(it).show(
- supportFragmentManager,
- ERROR_DIALOG_TAG
- )
- }
- }
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- errorDialogViewModel.setResultFlow.collect {
- Log.d(TAG, "errorDialogSetResultFlow($it)")
- when (it) {
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH -> onSetActivityResult(
- ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null)
- )
-
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT -> onSetActivityResult(
- ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null)
- )
- }
- }
- }
- }
- }
-
- private fun startFragment(fragmentClass: Class, tag: String) {
- if (!isFirstFragmentAdded) {
- supportFragmentManager.beginTransaction()
- .setReorderingAllowed(true)
- .replace(R.id.fragment_container_view, fragmentClass, null, tag)
- .commit()
- isFirstFragmentAdded = true
- } else {
- supportFragmentManager.beginTransaction()
- .setReorderingAllowed(true)
- .setCustomAnimations(
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
- )
- .replace(R.id.fragment_container_view, fragmentClass, null, tag)
- .addToBackStack(tag)
- .commit()
- }
- }
-
- private fun startIntroFragment() {
- attachIntroViewModel()
- startFragment(FingerprintEnrollIntroFragment::class.java, INTRO_TAG)
- }
-
- private fun attachIntroViewModel() {
- val request: EnrollmentRequest = viewModel.request
- if (request.isSkipIntro || request.isSkipFindSensor) {
- return
- }
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- introViewModel.actionFlow.collect(this@FingerprintEnrollmentActivity::onIntroAction)
- }
- }
- }
-
- // We need to make sure token is valid before entering find sensor page
- private fun startFindSensorFragment() {
- // Always setToken into progressViewModel even it is not necessary action for UDFPS
- progressViewModel.setToken(autoCredentialViewModel.token)
- attachFindSensorViewModel()
- val fragmentClass: Class = if (viewModel.canAssumeUdfps) {
- FingerprintEnrollFindUdfpsFragment::class.java
- } else if (viewModel.canAssumeSfps) {
- FingerprintEnrollFindSfpsFragment::class.java
- } else {
- FingerprintEnrollFindRfpsFragment::class.java
- }
- startFragment(fragmentClass, FIND_SENSOR_TAG)
- }
-
- private fun attachFindSensorViewModel() {
- if (viewModel.request.isSkipFindSensor) {
- return
- }
- findSensorViewModel.let {
- // Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
- // recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling
- // activity.
- it.clearActionLiveData()
- it.actionLiveData.observe(this, findSensorActionObserver)
- }
- }
-
- private fun startEnrollingFragment() {
- // Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
- progressViewModel.setToken(autoCredentialViewModel.token)
- attachEnrollingViewModel()
- val fragmentClass: Class = if (viewModel.canAssumeUdfps) {
- FingerprintEnrollEnrollingUdfpsFragment::class.java
- } else if (viewModel.canAssumeSfps) {
- FingerprintEnrollEnrollingSfpsFragment::class.java
- } else {
- FingerprintEnrollEnrollingRfpsFragment::class.java
- }
- startFragment(fragmentClass, ENROLLING_TAG)
- }
-
- private fun attachEnrollingViewModel() {
- enrollingViewModel.let {
- it.clearActionLiveData()
- it.actionLiveData.observe(this, enrollingActionObserver)
- }
- }
-
- private fun startFinishFragment() {
- viewModel.isNewFingerprintAdded = true
- attachFinishViewModel()
- if (viewModel.request.isSkipFindSensor) {
- // Set page to Finish
- supportFragmentManager.beginTransaction()
- .setReorderingAllowed(true)
- .setCustomAnimations(
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
- )
- .replace(
- R.id.fragment_container_view,
- FingerprintEnrollFinishFragment::class.java,
- null,
- FINISH_TAG
- )
- .commit()
- } else {
- // Remove Enrolling page
- supportFragmentManager.popBackStack()
-
- // Remove old Finish page if any
- if (supportFragmentManager.findFragmentByTag(FINISH_TAG) != null) {
- supportFragmentManager.popBackStack(FINISH_TAG, POP_BACK_STACK_INCLUSIVE)
- }
-
- // Remove FindSensor page if maxEnrolled
- if (viewModel.isMaxEnrolledReached(autoCredentialViewModel.userId)
- && supportFragmentManager.findFragmentByTag(FIND_SENSOR_TAG) != null
- ) {
- supportFragmentManager.popBackStack(FIND_SENSOR_TAG, POP_BACK_STACK_INCLUSIVE)
- }
-
- // Add Finish page
- supportFragmentManager.beginTransaction()
- .setReorderingAllowed(true)
- .setCustomAnimations(
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_open_exit,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_enter_dynamic_color,
- com.google.android.setupdesign.R.anim.shared_x_axis_activity_close_exit
- )
- .replace(
- R.id.fragment_container_view,
- FingerprintEnrollFinishFragment::class.java,
- null,
- FINISH_TAG
- )
- .addToBackStack(FINISH_TAG)
- .commit()
- }
- }
-
- private fun attachFinishViewModel() {
- finishViewModel.let {
- it.clearActionLiveData()
- it.actionLiveData.observe(this, finishActionObserver)
- }
- }
-
- private fun onSetActivityResult(result: ActivityResult) {
- val challengeExtras: Bundle? = autoCredentialViewModel.createGeneratingChallengeExtras()
- val overrideResult: ActivityResult = viewModel.getOverrideActivityResult(
- result, challengeExtras
- )
- if (DEBUG) {
- Log.d(
- TAG, "onSetActivityResult(" + result + "), override:" + overrideResult
- + ") challengeExtras:" + challengeExtras
- )
- }
- setResult(overrideResult.resultCode, overrideResult.data)
- finish()
- }
-
- private fun checkCredential() {
- when (autoCredentialViewModel.checkCredential(lifecycleScope)) {
- CredentialAction.FAIL_NEED_TO_CHOOSE_LOCK -> {
- val intent: Intent = autoCredentialViewModel.createChooseLockIntent(
- this,
- viewModel.request.isSuw,
- viewModel.request.suwExtras
- )
- if (!viewModel.isWaitingActivityResult.compareAndSet(false, true)) {
- Log.w(TAG, "chooseLock, fail to set isWaiting flag to true")
- }
- chooseLockLauncher.launch(intent)
- return
- }
-
- CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK -> {
- val launched: Boolean = autoCredentialViewModel.createConfirmLockLauncher(
- this,
- LAUNCH_CONFIRM_LOCK_ACTIVITY,
- getString(R.string.security_settings_fingerprint_preference_title)
- ).launch()
- if (!launched) {
- // This shouldn't happen, as we should only end up at this step if a lock thingy
- // is already set.
- Log.e(TAG, "confirmLock, launched is true")
- finish()
- } else if (!viewModel.isWaitingActivityResult.compareAndSet(false, true)) {
- Log.w(TAG, "confirmLock, fail to set isWaiting flag to true")
- }
- return
- }
-
- CredentialAction.CREDENTIAL_VALID,
- CredentialAction.IS_GENERATING_CHALLENGE -> {}
- }
- }
-
- private fun onChooseOrConfirmLockResult(
- isChooseLock: Boolean,
- activityResult: ActivityResult
- ) {
- if (!viewModel.isWaitingActivityResult.compareAndSet(true, false)) {
- Log.w(TAG, "isChooseLock:$isChooseLock, fail to unset waiting flag")
- }
- if (!autoCredentialViewModel.generateChallengeAsCredentialActivityResult(
- isChooseLock,
- activityResult,
- lifecycleScope
- )
- ) {
- onSetActivityResult(activityResult)
- }
- }
-
- private fun onIntroAction(action: FingerprintEnrollIntroAction) {
- Log.d(TAG, "onIntroAction($action)")
- when (action) {
- FingerprintEnrollIntroAction.DONE_AND_FINISH -> {
- onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null))
- return
- }
-
- FingerprintEnrollIntroAction.SKIP_OR_CANCEL -> {
- onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
- return
- }
-
- FingerprintEnrollIntroAction.CONTINUE_ENROLL -> {
- startFindSensorFragment()
- }
- }
- }
-
- private fun onFindSensorAction(@FingerprintEnrollFindSensorAction action: Int) {
- when (action) {
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP -> {
- onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
- return
- }
-
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG -> {
- SkipSetupFindFpsDialog().show(
- supportFragmentManager,
- SKIP_SETUP_FIND_FPS_DIALOG_TAG
- )
- return
- }
-
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START -> {
- startEnrollingFragment()
- }
- }
- }
-
- private fun onEnrollingAction(@FingerprintEnrollEnrollingAction action: Int) {
- when (action) {
- FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE -> {
- startFinishFragment()
- }
-
- FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP -> {
- onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_SKIP, null))
- }
-
- FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG -> {
- FingerprintEnrollEnrollingIconTouchDialog().show(
- supportFragmentManager,
- SKIP_SETUP_FIND_FPS_DIALOG_TAG
- )
- }
-
- FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED -> {
- if (supportFragmentManager.backStackEntryCount > 0) {
- supportFragmentManager.popBackStack()
- } else {
- onSetActivityResult(ActivityResult(RESULT_CANCELED, null))
- }
- }
- }
- }
-
- private fun onFinishAction(@FingerprintEnrollFinishAction action: Int) {
- when (action) {
- FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK -> {
- startEnrollingFragment()
- }
-
- FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK -> {
- val data: Intent? = if (viewModel.request.isSuw) {
- Intent().also {
- it.putExtras(
- viewModel.getSuwFingerprintCountExtra(
- autoCredentialViewModel.userId
- )
- )
- }
- } else {
- null
- }
- onSetActivityResult(ActivityResult(BiometricEnrollBase.RESULT_FINISHED, data))
- }
- }
- }
-
- override fun onPause() {
- super.onPause()
- viewModel.checkFinishActivityDuringOnPause(
- isFinishing,
- isChangingConfigurations,
- lifecycleScope
- )
- }
-
- override fun onDestroy() {
- viewModel.updateFingerprintSuggestionEnableState(autoCredentialViewModel.userId)
- super.onDestroy()
- }
-
- override fun onApplyThemeResource(theme: Theme, @StyleRes resid: Int, first: Boolean) {
- theme.applyStyle(R.style.SetupWizardPartnerResource, true)
- super.onApplyThemeResource(theme, resid, first)
- }
-
- @Deprecated("Deprecated in Java")
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {
- onChooseOrConfirmLockResult(false, ActivityResult(resultCode, data))
- return
- }
- super.onActivityResult(requestCode, resultCode, data)
- }
-
- override val defaultViewModelCreationExtras: CreationExtras
- get() = MutableCreationExtras(super.defaultViewModelCreationExtras).also {
- it[CHALLENGE_GENERATOR_KEY] = FingerprintChallengeGenerator(
- featureFactory.biometricsRepositoryProvider.getFingerprintRepository(application)!!
- )
- it[ENROLLMENT_REQUEST_KEY] =
- EnrollmentRequest(intent, applicationContext, this is SetupActivity)
- it[CREDENTIAL_MODEL_KEY] =
- CredentialModel(intent.extras, SystemClock.elapsedRealtimeClock())
- }
-
- override val defaultViewModelProviderFactory: ViewModelProvider.Factory
- get() = BiometricsViewModelFactory()
-
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- window.statusBarColor = backgroundColor
- }
-
- @get:ColorInt
- private val backgroundColor: Int
- get() {
- val stateList: ColorStateList? =
- Utils.getColorAttr(this, android.R.attr.windowBackground)
- return stateList?.defaultColor ?: Color.TRANSPARENT
- }
-
- override fun onConfigurationChanged(newConfig: Configuration) {
- viewModelProvider[DeviceFoldedViewModel::class.java].onConfigurationChanged(newConfig)
- super.onConfigurationChanged(newConfig)
- }
-
- companion object {
- private const val DEBUG = false
- private const val TAG = "FingerprintEnrollmentActivity"
- protected const val LAUNCH_CONFIRM_LOCK_ACTIVITY = 1
-
- private const val INTRO_TAG = "intro"
- private const val FIND_SENSOR_TAG = "find-sensor"
- private const val ENROLLING_TAG = "enrolling"
- private const val FINISH_TAG = "finish"
- private const val SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog"
- private const val ERROR_DIALOG_TAG = "error-dialog"
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/GlifLayoutHelper.kt b/src/com/android/settings/biometrics2/ui/view/GlifLayoutHelper.kt
deleted file mode 100644
index 756f309cf56..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/GlifLayoutHelper.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.app.Activity
-import android.text.TextUtils
-import android.view.View
-import androidx.annotation.StringRes
-import com.google.android.setupdesign.GlifLayout
-
-/**
- * Utils class for GlifLayout
- */
-class GlifLayoutHelper(val activity: Activity, val glifLayout: GlifLayout) {
-
- /**
- * Sets header text to GlifLayout
- */
- fun setHeaderText(@StringRes textResId: Int) {
- val layoutTitle = glifLayout.headerTextView
- val previousTitle = layoutTitle.text
- val title = activity.getText(textResId)
- if (previousTitle !== title) {
- if (!TextUtils.isEmpty(previousTitle)) {
- layoutTitle.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE
- }
- glifLayout.headerText = title
- glifLayout.headerTextView.contentDescription = title
- activity.title = title
- }
- }
-
- /**
- * Sets description text to GlifLayout
- */
- fun setDescriptionText(description: CharSequence?) {
- val previousDescription = glifLayout.descriptionText
- // Prevent a11y for re-reading the same string
- if (!TextUtils.equals(previousDescription, description)) {
- glifLayout.descriptionText = description
- }
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/view/SkipSetupFindFpsDialog.kt b/src/com/android/settings/biometrics2/ui/view/SkipSetupFindFpsDialog.kt
deleted file mode 100644
index bb74e360778..00000000000
--- a/src/com/android/settings/biometrics2/ui/view/SkipSetupFindFpsDialog.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.view
-
-import android.app.Dialog
-import android.content.Context
-import android.content.DialogInterface
-import android.os.Bundle
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import androidx.lifecycle.ViewModelProvider
-import com.android.settings.R
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel
-
-/**
- * Skip dialog which shows when user clicks "Do it later" button in FingerprintFindSensor page.
- */
-class SkipSetupFindFpsDialog : DialogFragment() {
-
- private var mViewModel: FingerprintEnrollFindSensorViewModel? = null
-
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
- requireActivity().bindSkipSetupFindFpsDialog {
- _: DialogInterface?, _: Int -> mViewModel?.onSkipDialogButtonClick()
- }
-
- override fun onAttach(context: Context) {
- mViewModel = ViewModelProvider(requireActivity())[
- FingerprintEnrollFindSensorViewModel::class.java
- ]
- super.onAttach(context)
- }
-}
-
-fun Context.bindSkipSetupFindFpsDialog(
- positiveButtonClickListener: DialogInterface.OnClickListener
-): AlertDialog =
- AlertDialog.Builder(this, R.style.Theme_AlertDialog)
- .setTitle(R.string.setup_fingerprint_enroll_skip_title)
- .setPositiveButton(R.string.skip_anyway_button_label, positiveButtonClickListener)
- .setNegativeButton(R.string.go_back_button_label, null)
- .setMessage(R.string.setup_fingerprint_enroll_skip_after_adding_lock_text)
- .create()
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.kt b/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.kt
deleted file mode 100644
index 95aee4bacfc..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/AutoCredentialViewModel.kt
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.viewmodel
-
-import android.app.Activity
-import android.app.Application
-import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
-import android.content.Context
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import androidx.activity.result.ActivityResult
-import androidx.lifecycle.AndroidViewModel
-import com.android.internal.widget.LockPatternUtils
-import com.android.settings.biometrics.BiometricEnrollBase
-import com.android.settings.biometrics.BiometricUtils
-import com.android.settings.biometrics.BiometricUtils.GatekeeperCredentialNotMatchException
-import com.android.settings.biometrics2.data.repository.FingerprintRepository
-import com.android.settings.biometrics2.ui.model.CredentialModel
-import com.android.settings.password.ChooseLockGeneric
-import com.android.settings.password.ChooseLockPattern
-import com.android.settings.password.ChooseLockSettingsHelper
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.asSharedFlow
-import kotlinx.coroutines.launch
-
-/**
- * AutoCredentialViewModel which uses CredentialModel to determine next actions for activity, like
- * start ChooseLockActivity, start ConfirmLockActivity, GenerateCredential, or do nothing.
- */
-class AutoCredentialViewModel(
- application: Application,
- private val lockPatternUtils: LockPatternUtils,
- private val challengeGenerator: ChallengeGenerator,
- private val credentialModel: CredentialModel
-) : AndroidViewModel(application) {
-
- /**
- * Generic callback for FingerprintManager#generateChallenge or FaceManager#generateChallenge
- */
- interface GenerateChallengeCallback {
- /** Generic generateChallenge method for FingerprintManager or FaceManager */
- fun onChallengeGenerated(sensorId: Int, userId: Int, challenge: Long)
- }
-
- /**
- * A generic interface class for calling different generateChallenge from FingerprintManager or
- * FaceManager
- */
- interface ChallengeGenerator {
-
- /** Callback that will be called later after challenge generated */
- var callback: GenerateChallengeCallback?
-
- /** Method for generating challenge from FingerprintManager or FaceManager */
- fun generateChallenge(userId: Int)
- }
-
- /** Used to generate challenge through FingerprintRepository */
- class FingerprintChallengeGenerator(
- private val fingerprintRepository: FingerprintRepository
- ) : ChallengeGenerator {
-
- override var callback: GenerateChallengeCallback? = null
-
- override fun generateChallenge(userId: Int) {
- callback?.let {
- fingerprintRepository.generateChallenge(userId) {
- sensorId: Int, uid: Int, challenge: Long ->
- it.onChallengeGenerated(sensorId, uid, challenge)
- }
- } ?:run {
- Log.e(TAG, "generateChallenge, null callback")
- }
- }
-
- companion object {
- private const val TAG = "FingerprintChallengeGenerator"
- }
- }
-
- private val _generateChallengeFailedFlow = MutableSharedFlow()
- val generateChallengeFailedFlow: SharedFlow
- get() = _generateChallengeFailedFlow.asSharedFlow()
-
-
- // flag if token is generating through checkCredential()'s generateChallenge()
- private var isGeneratingChallengeDuringCheckingCredential = false
-
- /** Get bundle which passing back to FingerprintSettings for late generateChallenge() */
- fun createGeneratingChallengeExtras(): Bundle? {
- if (!isGeneratingChallengeDuringCheckingCredential
- || !credentialModel.isValidToken
- || !credentialModel.isValidChallenge
- ) {
- return null
- }
- val bundle = Bundle()
- bundle.putByteArray(
- ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
- credentialModel.token
- )
- bundle.putLong(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, credentialModel.challenge)
- return bundle
- }
-
- /** Check credential status for biometric enrollment. */
- fun checkCredential(scope: CoroutineScope): CredentialAction {
- return if (isValidCredential) {
- CredentialAction.CREDENTIAL_VALID
- } else if (isUnspecifiedPassword) {
- CredentialAction.FAIL_NEED_TO_CHOOSE_LOCK
- } else if (credentialModel.isValidGkPwHandle) {
- val gkPwHandle = credentialModel.gkPwHandle
- credentialModel.clearGkPwHandle()
- // GkPwHandle is got through caller activity, we shall not revoke it after
- // generateChallenge(). Let caller activity to make decision.
- generateChallenge(gkPwHandle, false, scope)
- isGeneratingChallengeDuringCheckingCredential = true
- CredentialAction.IS_GENERATING_CHALLENGE
- } else {
- CredentialAction.FAIL_NEED_TO_CONFIRM_LOCK
- }
- }
-
- private fun generateChallenge(
- gkPwHandle: Long,
- revokeGkPwHandle: Boolean,
- scope: CoroutineScope
- ) {
- challengeGenerator.callback = object : GenerateChallengeCallback {
- override fun onChallengeGenerated(sensorId: Int, userId: Int, challenge: Long) {
- var illegalStateExceptionCaught = false
- try {
- val newToken = requestGatekeeperHat(gkPwHandle, challenge, userId)
- credentialModel.challenge = challenge
- credentialModel.token = newToken
- } catch (e: IllegalStateException) {
- Log.e(TAG, "generateChallenge, IllegalStateException", e)
- illegalStateExceptionCaught = true
- } finally {
- if (revokeGkPwHandle) {
- lockPatternUtils.removeGatekeeperPasswordHandle(gkPwHandle)
- }
- Log.d(
- TAG,
- "generateChallenge(), model:$credentialModel"
- + ", revokeGkPwHandle:$revokeGkPwHandle"
- )
- // Check credential again
- if (!isValidCredential || illegalStateExceptionCaught) {
- Log.w(TAG, "generateChallenge, invalid Credential or IllegalStateException")
- scope.launch {
- _generateChallengeFailedFlow.emit(true)
- }
- }
- }
- }
- }
- challengeGenerator.generateChallenge(userId)
- }
-
- private val isValidCredential: Boolean
- get() = !isUnspecifiedPassword && credentialModel.isValidToken
-
- private val isUnspecifiedPassword: Boolean
- get() = lockPatternUtils.getActivePasswordQuality(userId) == PASSWORD_QUALITY_UNSPECIFIED
-
- /**
- * Handle activity result from ChooseLockGeneric, ConfirmLockPassword, or ConfirmLockPattern
- * @param isChooseLock true if result is coming from ChooseLockGeneric. False if result is
- * coming from ConfirmLockPassword or ConfirmLockPattern
- * @param result activity result
- * @return if it is a valid result and viewModel is generating challenge
- */
- fun generateChallengeAsCredentialActivityResult(
- isChooseLock: Boolean,
- result: ActivityResult,
- scope: CoroutineScope
- ): Boolean {
- if ((isChooseLock && result.resultCode == ChooseLockPattern.RESULT_FINISHED) ||
- (!isChooseLock && result.resultCode == Activity.RESULT_OK)) {
- result.data?.let {
- val gkPwHandle = it.getLongExtra(
- ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
- CredentialModel.INVALID_GK_PW_HANDLE
- )
- // Revoke self requested GkPwHandle because it shall only used once inside this
- // activity lifecycle.
- generateChallenge(gkPwHandle, true, scope)
- return true
- }
- }
- return false
- }
-
- val userId: Int
- get() = credentialModel.userId
-
- val token: ByteArray?
- get() = credentialModel.token
-
- @Throws(IllegalStateException::class)
- private fun requestGatekeeperHat(gkPwHandle: Long, challenge: Long, userId: Int): ByteArray? {
- val response = lockPatternUtils
- .verifyGatekeeperPasswordHandle(gkPwHandle, challenge, userId)
- if (!response.isMatched) {
- throw GatekeeperCredentialNotMatchException("Unable to request Gatekeeper HAT")
- }
- return response.gatekeeperHAT
- }
-
- /** Create Intent for choosing lock */
- fun createChooseLockIntent(
- context: Context, isSuw: Boolean,
- suwExtras: Bundle
- ): Intent {
- val intent = BiometricUtils.getChooseLockIntent(
- context, isSuw,
- suwExtras
- )
- intent.putExtra(
- ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
- true
- )
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true)
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true)
- if (credentialModel.isValidUserId) {
- intent.putExtra(Intent.EXTRA_USER_ID, credentialModel.userId)
- }
- return intent
- }
-
- /** Create ConfirmLockLauncher */
- fun createConfirmLockLauncher(
- activity: Activity,
- requestCode: Int, title: String
- ): ChooseLockSettingsHelper {
- val builder = ChooseLockSettingsHelper.Builder(activity)
- builder.setRequestCode(requestCode)
- .setTitle(title)
- .setRequestGatekeeperPasswordHandle(true)
- .setForegroundOnly(true)
- .setReturnCredentials(true)
- if (credentialModel.isValidUserId) {
- builder.setUserId(credentialModel.userId)
- }
- return builder.build()
- }
-
- companion object {
- private const val TAG = "AutoCredentialViewModel"
- }
-}
-
-enum class CredentialAction {
-
- CREDENTIAL_VALID,
-
- /** Valid credential, activity does nothing. */
- IS_GENERATING_CHALLENGE,
-
- /** This credential looks good, but still need to run generateChallenge(). */
- FAIL_NEED_TO_CHOOSE_LOCK,
-
- /** Need activity to run confirm lock */
- FAIL_NEED_TO_CONFIRM_LOCK
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceFoldedViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/DeviceFoldedViewModel.java
deleted file mode 100644
index 7dc13282d1d..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceFoldedViewModel.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import android.content.res.Configuration;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-import com.android.systemui.unfold.compat.ScreenSizeFoldProvider;
-import com.android.systemui.unfold.updates.FoldProvider;
-
-import java.util.concurrent.Executor;
-
-/**
- * ViewModel explaining the fingerprint sensor location for fingerprint enrollment.
- */
-public class DeviceFoldedViewModel extends ViewModel {
-
- private static final String TAG = "DeviceFoldedViewModel";
-
- @NonNull private final MutableLiveData mLiveData =
- new MutableLiveData<>(null);
-
- private final ScreenSizeFoldProvider mScreenSizeFoldProvider;
- private final FoldProvider.FoldCallback mIsFoldedCallback = isFolded -> {
- Log.d(TAG, "onFoldUpdated= " + isFolded);
- mLiveData.postValue(isFolded);
- };
-
- public DeviceFoldedViewModel(@NonNull ScreenSizeFoldProvider screenSizeFoldProvider,
- @NonNull Executor executor) {
- super();
- mScreenSizeFoldProvider = screenSizeFoldProvider;
- mScreenSizeFoldProvider.registerCallback(mIsFoldedCallback, executor);
- }
-
- /**
- * Calls this method when activity gets configuration change
- */
- public void onConfigurationChanged(@NonNull Configuration newConfig) {
- mScreenSizeFoldProvider.onConfigurationChange(newConfig);
- }
-
- /**
- * Returns FoldedLiveData
- */
- public LiveData getLiveData() {
- return mLiveData;
- }
-
- @Override
- protected void onCleared() {
- mScreenSizeFoldProvider.unregisterCallback(mIsFoldedCallback);
- super.onCleared();
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java
deleted file mode 100644
index 07fe2759491..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/DeviceRotationViewModel.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import static android.hardware.display.DisplayManager.DisplayListener;
-
-import android.app.Application;
-import android.hardware.display.DisplayManager;
-import android.util.Log;
-import android.view.DisplayInfo;
-import android.view.Surface;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * ViewModel explaining the fingerprint sensor location for fingerprint enrollment.
- */
-public class DeviceRotationViewModel extends AndroidViewModel {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "DeviceRotationViewModel";
-
- private final DisplayManager mDisplayManager;
- private final boolean mIsReverseDefaultRotation;
- @NonNull private final DisplayInfo mDisplayInfo = new DisplayInfo();
-
- /** {@link android.hardware.display.DisplayManager} is a final class, set this member visibility
- * to 'protected' for testing
- */
- @VisibleForTesting
- protected final DisplayListener mDisplayListener = new DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- final int rotation = getRotation();
- Log.d(TAG, "onDisplayChanged(" + displayId + "), rotation:" + rotation);
- mLiveData.postValue(rotation);
- }
- };
-
- @NonNull private final MutableLiveData mLiveData = new MutableLiveData<>();
-
- public DeviceRotationViewModel(@NonNull Application application) {
- super(application);
- mDisplayManager = application.getSystemService(DisplayManager.class);
- mDisplayManager.registerDisplayListener(mDisplayListener,
- application.getMainThreadHandler());
- mIsReverseDefaultRotation = application.getResources().getBoolean(
- com.android.internal.R.bool.config_reverseDefaultRotation);
- }
-
- /**
- * Returns current rotation.
- *
- * {@link android.view.Display} is a final class, set this method visibility to "protected" for
- * inheriting it in test
- */
- @VisibleForTesting
- @Surface.Rotation
- protected int getRotation() {
- getApplication().getDisplay().getDisplayInfo(mDisplayInfo);
- if (mIsReverseDefaultRotation) {
- return (mDisplayInfo.rotation + 1) % 4;
- } else {
- return mDisplayInfo.rotation;
- }
- }
-
- /**
- * Returns RotationLiveData
- */
- public LiveData getLiveData() {
- final Integer lastRotation = mLiveData.getValue();
- @Surface.Rotation int newRotation = getRotation();
- if (lastRotation == null || lastRotation != newRotation) {
- Log.d(TAG, "getLiveData, update rotation from " + lastRotation + " to " + newRotation);
- mLiveData.setValue(newRotation);
- }
- return mLiveData;
- }
-
- @Override
- protected void onCleared() {
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
- super.onCleared();
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
deleted file mode 100644
index eba6a15ebe3..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollEnrollingViewModel.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import android.annotation.IntDef;
-import android.app.Application;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
-import android.os.Vibrator;
-import android.util.Log;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * ViewModel explaining the fingerprint enrolling page
- */
-public class FingerprintEnrollEnrollingViewModel extends AndroidViewModel {
-
- private static final String TAG = FingerprintEnrollEnrollingViewModel.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- private static final VibrationEffect VIBRATE_EFFECT_ERROR =
- VibrationEffect.createWaveform(new long[]{0, 5, 55, 60}, -1);
- private static final VibrationAttributes FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES =
- VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);
-
- /**
- * Enrolling finished
- */
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE = 0;
-
- /**
- * Icon touch dialog show
- */
- public static final int FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG = 1;
-
- /**
- * Has got latest cancelled event due to user skip
- */
- public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP = 2;
-
- /**
- * Has got latest cancelled event due to back key
- */
- public static final int FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED = 3;
-
- @IntDef(prefix = { "FINGERPRINT_ENROLL_ENROLLING_ACTION_" }, value = {
- FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE,
- FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG,
- FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FingerprintEnrollEnrollingAction {}
-
- private final int mUserId;
- private boolean mOnBackPressed;
- private boolean mOnSkipPressed;
- @NonNull private final FingerprintRepository mFingerprintRepository;
- private final AccessibilityManager mAccessibilityManager;
- private final Vibrator mVibrator;
-
- private final MutableLiveData mActionLiveData = new MutableLiveData<>();
-
- public FingerprintEnrollEnrollingViewModel(
- @NonNull Application application,
- int userId,
- @NonNull FingerprintRepository fingerprintRepository
- ) {
- super(application);
- mUserId = userId;
- mFingerprintRepository = fingerprintRepository;
- mAccessibilityManager = application.getSystemService(AccessibilityManager.class);
- mVibrator = application.getSystemService(Vibrator.class);
- }
-
- public LiveData getActionLiveData() {
- return mActionLiveData;
- }
-
- /**
- * Clears action live data
- */
- public void clearActionLiveData() {
- mActionLiveData.setValue(null);
- }
-
- public boolean getOnSkipPressed() {
- return mOnSkipPressed;
- }
-
- /**
- * User clicks skip button
- */
- public void setOnSkipPressed() {
- mOnSkipPressed = true;
- }
-
- /**
- * Enrolling is cancelled because user clicks skip
- */
- public void onCancelledDueToOnSkipPressed() {
- final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
- if (DEBUG) {
- Log.d(TAG, "onSkipButtonClick, post action " + action);
- }
- mOnSkipPressed = false;
- mActionLiveData.postValue(action);
- }
-
- /**
- * Is enrolling finished
- */
- public void onEnrollingDone() {
- final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
- if (DEBUG) {
- Log.d(TAG, "onEnrollingDone, post action " + action);
- }
- mActionLiveData.postValue(action);
- }
-
- public boolean getOnBackPressed() {
- return mOnBackPressed;
- }
-
- /**
- * Back key is pressed.
- */
- public void setOnBackPressed() {
- mOnBackPressed = true;
- }
-
- /**
- * Enrollment is cancelled because back key is pressed.
- */
- public void onCancelledDueToOnBackPressed() {
- final int action = FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
- if (DEBUG) {
- Log.d(TAG, "onCancelledEventReceivedAfterOnBackPressed, post action " + action);
- }
- mOnBackPressed = false;
- mActionLiveData.postValue(action);
- }
-
- /**
- * Icon touch dialog show
- */
- public void showIconTouchDialog() {
- final int action = FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
- if (DEBUG) {
- Log.d(TAG, "onIconTouchDialogShow, post action " + action);
- }
- mActionLiveData.postValue(action);
- }
-
- /**
- * get enroll stage threshold
- */
- public float getEnrollStageThreshold(int index) {
- return mFingerprintRepository.getEnrollStageThreshold(index);
- }
-
- /**
- * Get enroll stage count
- */
- public int getEnrollStageCount() {
- return mFingerprintRepository.getEnrollStageCount();
- }
-
- /**
- * Requests interruption of the accessibility feedback from all accessibility services.
- */
- public void clearTalkback() {
- mAccessibilityManager.interrupt();
- }
-
- /**
- * Returns if the {@link AccessibilityManager} is enabled.
- *
- * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
- */
- public boolean isAccessibilityEnabled() {
- return mAccessibilityManager.isEnabled();
- }
-
- /**
- * Sends an {@link AccessibilityEvent}.
- */
- public void sendAccessibilityEvent(CharSequence announcement) {
- AccessibilityEvent e = AccessibilityEvent.obtain();
- e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- e.setClassName(getClass().getName());
- e.setPackageName(getApplication().getPackageName());
- e.getText().add(announcement);
- mAccessibilityManager.sendAccessibilityEvent(e);
- }
-
- /**
- * Returns if the touch exploration in the system is enabled.
- *
- * @return True if touch exploration is enabled, false otherwise.
- */
- public boolean isTouchExplorationEnabled() {
- return mAccessibilityManager.isTouchExplorationEnabled();
- }
-
- /**
- * Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
- * caller to specify the vibration is owned by someone else and set a reason for vibration.
- */
- public void vibrateError(String reason) {
- mVibrator.vibrate(mUserId, getApplication().getOpPackageName(),
- VIBRATE_EFFECT_ERROR, reason, FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
- }
-
- /**
- * Gets the first FingerprintSensorPropertiesInternal from FingerprintManager
- */
- @Nullable
- public FingerprintSensorPropertiesInternal getFirstFingerprintSensorPropertiesInternal() {
- return mFingerprintRepository.getFirstFingerprintSensorPropertiesInternal();
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt
deleted file mode 100644
index b154fe78ece..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollErrorDialogViewModel.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.android.settings.biometrics2.ui.viewmodel
-
-import android.app.Application
-import androidx.lifecycle.AndroidViewModel
-import kotlinx.atomicfu.AtomicBoolean
-import kotlinx.atomicfu.atomic
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.asSharedFlow
-
-class FingerprintEnrollErrorDialogViewModel(
- application: Application,
- val isSuw: Boolean
-): AndroidViewModel(application) {
-
- private val _isDialogShown: AtomicBoolean = atomic(false)
- val isDialogShown: Boolean
- get() = _isDialogShown.value
-
- private val _newDialogFlow = MutableSharedFlow()
- val newDialogFlow: SharedFlow
- get() = _newDialogFlow.asSharedFlow()
-
- private val _triggerRetryFlow = MutableSharedFlow()
- val triggerRetryFlow: SharedFlow
- get() = _triggerRetryFlow.asSharedFlow()
-
- private val _setResultFlow = MutableSharedFlow()
- val setResultFlow: SharedFlow
- get() = _setResultFlow.asSharedFlow()
-
- suspend fun newDialog(errorMsgId: Int) {
- _isDialogShown.compareAndSet(expect = false, update = true)
- _newDialogFlow.emit(errorMsgId)
- }
-
- suspend fun triggerRetry() {
- _isDialogShown.compareAndSet(expect = true, update = false)
- _triggerRetryFlow.emit(Any())
- }
-
- suspend fun setResultAndFinish(action: FingerprintErrorDialogSetResultAction) {
- _isDialogShown.compareAndSet(expect = true, update = false)
- _setResultFlow.emit(action)
- }
-}
-
-enum class FingerprintErrorDialogSetResultAction {
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH,
- FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModel.java
deleted file mode 100644
index 00c67c4ca35..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFindSensorViewModel.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import android.annotation.IntDef;
-import android.app.Application;
-import android.util.Log;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * ViewModel explaining the fingerprint sensor location for fingerprint enrollment.
- */
-public class FingerprintEnrollFindSensorViewModel extends AndroidViewModel {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "FingerprintEnrollFindSensorViewModel";
-
- /**
- * User clicks 'Skip' button on this page in Settings
- */
- public static final int FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP = 0;
-
- /**
- * User clicks 'Skip' button on this page in SetupWizard flow
- */
- public static final int FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG = 1;
-
- /**
- * User clicks 'Start' button on this page
- */
- public static final int FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START = 2;
-
- @IntDef(prefix = { "FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_" }, value = {
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP,
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG,
- FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FingerprintEnrollFindSensorAction {}
-
- private final AccessibilityManager mAccessibilityManager;
-
- private final boolean mIsSuw;
- @NonNull private final MutableLiveData mActionLiveData = new MutableLiveData<>();
-
- public FingerprintEnrollFindSensorViewModel(@NonNull Application application, boolean isSuw) {
- super(application);
- mAccessibilityManager = application.getSystemService(AccessibilityManager.class);
- mIsSuw = isSuw;
- }
-
- /**
- * Returns action live data that user chooses
- */
- public LiveData getActionLiveData() {
- return mActionLiveData;
- }
-
- /**
- * Clear ActionLiveData to prevent get obsolete data
- */
- public void clearActionLiveData() {
- mActionLiveData.setValue(null);
- }
-
- /**
- * User clicks skip button on dialog
- */
- public void onSkipDialogButtonClick() {
- final int action = FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
- if (DEBUG) {
- Log.d(TAG, "onSkipDialogButtonClick, post " + action);
- }
- mActionLiveData.postValue(action);
- }
-
- /**
- * User clicks skip button
- */
- public void onSkipButtonClick() {
- final int action = mIsSuw
- ? FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG
- : FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
- if (DEBUG) {
- Log.d(TAG, "onSkipButtonClick, post action " + action);
- }
- mActionLiveData.postValue(action);
- }
-
- /**
- * User clicks start button
- */
- public void onStartButtonClick() {
- final int action = FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
- if (DEBUG) {
- Log.d(TAG, "onStartButtonClick, post action " + action);
- }
- mActionLiveData.postValue(action);
- }
-
- /**
- * Returns the info about accessibility is enabled or not
- */
- public boolean isAccessibilityEnabled() {
- return mAccessibilityManager.isEnabled();
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModel.java
deleted file mode 100644
index ae67f74477e..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollFinishViewModel.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import android.annotation.IntDef;
-import android.app.Application;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.android.settings.biometrics2.data.repository.FingerprintRepository;
-import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Finish ViewModel handles the state of the fingerprint renroll final stage
- */
-public class FingerprintEnrollFinishViewModel extends AndroidViewModel {
-
- private static final String TAG = FingerprintEnrollFinishViewModel.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- /**
- * User clicks "Add" button
- */
- public static final int FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK = 0;
-
- /**
- * User clicks "Next" button
- */
- public static final int FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK = 1;
-
- @IntDef(prefix = { "FINGERPRINT_ENROLL_FINISH_ACTION_" }, value = {
- FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK,
- FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FingerprintEnrollFinishAction {}
-
- @NonNull private final FingerprintRepository mFingerprintRepository;
- @NonNull private final EnrollmentRequest mRequest;
- private final int mUserId;
-
- private final MutableLiveData mActionLiveData = new MutableLiveData<>();
-
- public FingerprintEnrollFinishViewModel(@NonNull Application application, int userId,
- @NonNull EnrollmentRequest request,
- @NonNull FingerprintRepository fingerprintRepository) {
- super(application);
- mUserId = userId;
- mRequest = request;
- mFingerprintRepository = fingerprintRepository;
- }
-
- @NonNull
- public EnrollmentRequest getRequest() {
- return mRequest;
- }
-
- /**
- * The first sensor type is Side fps sensor or not
- */
- public boolean canAssumeSfps() {
- return mFingerprintRepository.canAssumeSfps();
- }
-
- /**
- * Device allows user to enroll another fingerprint or not.
- */
- public boolean isAnotherFingerprintEnrollable() {
- return mFingerprintRepository.getNumOfEnrolledFingerprintsSize(mUserId)
- < mFingerprintRepository.getMaxFingerprints();
- }
-
- /**
- * Clear action LiveData
- */
- public void clearActionLiveData() {
- mActionLiveData.setValue(null);
- }
-
- /**
- * Get action LiveData
- */
- public LiveData getActionLiveData() {
- return mActionLiveData;
- }
-
- /**
- * Handle add button Click
- */
- public void onAddButtonClick() {
- final int action = FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
- if (DEBUG) {
- Log.d(TAG, "onAddButtonClick post(" + action + ")");
- }
- mActionLiveData.postValue(action);
- }
-
- /**
- * Handle next button Click
- */
- public void onNextButtonClick() {
- final int action = FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
- if (DEBUG) {
- Log.d(TAG, "onNextButtonClick post(" + action + ")");
- }
- mActionLiveData.postValue(action);
- }
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.kt b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.kt
deleted file mode 100644
index 98137b4ed22..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollIntroViewModel.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.biometrics2.ui.viewmodel
-
-import android.app.Application
-import android.util.Log
-import androidx.lifecycle.AndroidViewModel
-import com.android.settings.biometrics2.data.repository.FingerprintRepository
-import com.android.settings.biometrics2.ui.model.EnrollmentRequest
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus
-import com.android.settings.biometrics2.ui.model.FingerprintEnrollable
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.CONTINUE_ENROLL
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.DONE_AND_FINISH
-import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.SKIP_OR_CANCEL
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharedFlow
-import kotlinx.coroutines.flow.asSharedFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.launch
-
-/** Fingerprint intro onboarding page view model implementation */
-class FingerprintEnrollIntroViewModel(
- application: Application,
- private val fingerprintRepository: FingerprintRepository,
- val request: EnrollmentRequest,
- private val userId: Int
-) : AndroidViewModel(application) {
-
- /** User's action flow (like clicking Agree, Skip, or Done) */
- private val _actionFlow = MutableSharedFlow()
- val actionFlow: SharedFlow
- get() = _actionFlow.asSharedFlow()
-
- private fun getEnrollableStatus(): FingerprintEnrollable {
- val num = fingerprintRepository.getNumOfEnrolledFingerprintsSize(userId)
- val max =
- if (request.isSuw && !request.isAfterSuwOrSuwSuggestedAction)
- fingerprintRepository.getMaxFingerprintsInSuw(
- getApplication().resources
- )
- else
- fingerprintRepository.maxFingerprints
- return if (num >= max)
- FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
- else
- FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK
- }
-
- private val hasScrolledToBottomFlow = MutableStateFlow(HAS_SCROLLED_TO_BOTTOM_DEFAULT)
- private val enrollableStatusFlow = MutableStateFlow(getEnrollableStatus())
-
- /** Enrollable status and hasScrollToBottom live data */
- val pageStatusFlow: Flow =
- hasScrolledToBottomFlow.combine(enrollableStatusFlow) {
- hasScrolledToBottom: Boolean, enrollableStatus: FingerprintEnrollable ->
- FingerprintEnrollIntroStatus(hasScrolledToBottom, enrollableStatus)
- }
-
- fun updateEnrollableStatus(scope: CoroutineScope) {
- scope.launch {
- enrollableStatusFlow.emit(getEnrollableStatus())
- }
- }
-
- /** The first sensor type is UDFPS sensor or not */
- val canAssumeUdfps: Boolean
- get() = fingerprintRepository.canAssumeUdfps()
-
- /** Update onboarding intro page has scrolled to bottom */
- fun setHasScrolledToBottom(value: Boolean, scope: CoroutineScope) {
- scope.launch {
- hasScrolledToBottomFlow.emit(value)
- }
- }
-
- /** Get parental consent required or not during enrollment process */
- val isParentalConsentRequired: Boolean
- get() = fingerprintRepository.isParentalConsentRequired(getApplication())
-
- /** Get fingerprint is disable by admin or not */
- val isBiometricUnlockDisabledByAdmin: Boolean
- get() = fingerprintRepository.isDisabledByAdmin(getApplication(), userId)
-
- /**
- * User clicks next button
- */
- fun onNextButtonClick(scope: CoroutineScope) {
- scope.launch {
- when (val status = enrollableStatusFlow.value) {
- FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX ->
- _actionFlow.emit(DONE_AND_FINISH)
-
- FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK ->
- _actionFlow.emit(CONTINUE_ENROLL)
-
- else -> Log.w(TAG, "fail to click next, enrolled:$status")
- }
- }
- }
-
- /** User clicks skip/cancel button */
- fun onSkipOrCancelButtonClick(scope: CoroutineScope) {
- scope.launch {
- _actionFlow.emit(SKIP_OR_CANCEL)
- }
- }
-
- companion object {
- private const val TAG = "FingerprintEnrollIntroViewModel"
- private const val HAS_SCROLLED_TO_BOTTOM_DEFAULT = false
- private val ENROLLABLE_STATUS_DEFAULT = FingerprintEnrollable.FINGERPRINT_ENROLLABLE_UNKNOWN
- }
-}
-
-enum class FingerprintEnrollIntroAction {
- /** User clicks 'Done' button on this page */
- DONE_AND_FINISH,
- /** User clicks 'Agree' button on this page */
- CONTINUE_ENROLL,
- /** User clicks 'Skip' button on this page */
- SKIP_OR_CANCEL
-}
diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
deleted file mode 100644
index 1cfec52df69..00000000000
--- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.biometrics2.ui.viewmodel;
-
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_CANCELED;
-import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL;
-
-import static com.android.settings.biometrics2.ui.model.EnrollmentProgress.INITIAL_REMAINING;
-import static com.android.settings.biometrics2.ui.model.EnrollmentProgress.INITIAL_STEPS;
-
-import android.app.Application;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.hardware.fingerprint.FingerprintManager.EnrollReason;
-import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
-import android.os.CancellationSignal;
-import android.os.SystemClock;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.lifecycle.AndroidViewModel;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-
-import com.android.settings.R;
-import com.android.settings.biometrics.fingerprint.FingerprintUpdater;
-import com.android.settings.biometrics.fingerprint.MessageDisplayController;
-import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
-import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
-
-import java.util.LinkedList;
-
-/**
- * Progress ViewModel handles the state around biometric enrollment. It manages the state of
- * enrollment throughout the activity lifecycle so the app can continue after an event like
- * rotation.
- */
-public class FingerprintEnrollProgressViewModel extends AndroidViewModel {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "FingerprintEnrollProgressViewModel";
-
- private final MutableLiveData mProgressLiveData = new MutableLiveData<>(
- new EnrollmentProgress(INITIAL_STEPS, INITIAL_REMAINING));
- private final MutableLiveData mHelpMessageLiveData =
- new MutableLiveData<>();
- private final MutableLiveData mErrorMessageLiveData =
- new MutableLiveData<>();
- private final MutableLiveData