Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c76c7ac6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Adding FingerprintEnrollConfirmation" into main

parents 2f20a6ec 0fe0f4d9
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -7,3 +7,10 @@ flag {
  description: "This flag enables or disables the BiometricSettingsProvider"
  bug: "303595205"
}

flag {
  name: "fingerprint_v2_enrollment"
  namespace: "biometrics_framework"
  description: "This flag enables or disables the Fingerprint v2 enrollment"
  bug: "295206723"
}
+24 −1
Original line number Diff line number Diff line
@@ -37,13 +37,13 @@ import com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.GatekeeperPasswordProvider
import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintSensorRepositoryImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.AccessibilityInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintManagerInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.PressToAuthInteractorImpl
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.SetupWizard
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollConfirmationV2Fragment
@@ -54,6 +54,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enroll
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollEnrollingViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollFindSensorViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
@@ -70,6 +71,7 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Fing
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.flags.Flags
import com.android.settings.password.ChooseLockGeneric
import com.android.settings.password.ChooseLockSettingsHelper
import com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE
@@ -96,6 +98,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
  private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
  private lateinit var backgroundViewModel: BackgroundViewModel
  private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
  private lateinit var fingerprintEnrollConfirmationViewModel:
    FingerprintEnrollConfirmationViewModel
  private val coroutineDispatcher = Dispatchers.Default

  /** Result listener for ChooseLock activity flow. */
@@ -155,6 +159,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
    // TODO(b/299573056): Show split screen dialog when it's in multi window mode.
    setContentView(R.layout.fingerprint_v2_enroll_main)

    if (!Flags.fingerprintV2Enrollment()) {
      check(false) {
        "fingerprint enrollment v2 is not enabled, " +
          "please run adb shell device_config put " +
          "biometrics_framework com.android.settings.flags.fingerprint_v2_enrollment true"
      }
      finish()
    }

    setTheme(SetupWizardUtils.getTheme(applicationContext, intent))
    ThemeHelper.trySetDynamicColor(applicationContext)

@@ -293,6 +306,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
      ),
    )[RFPSViewModel::class.java]

    fingerprintEnrollConfirmationViewModel =
      ViewModelProvider(
        this,
        FingerprintEnrollConfirmationViewModel.FingerprintEnrollConfirmationViewModelFactory(
          navigationViewModel,
          fingerprintManagerInteractor,
        ),
      )[FingerprintEnrollConfirmationViewModel::class.java]

    lifecycleScope.launch {
      navigationViewModel.currentStep.collect { step ->
        if (step is Init) {
@@ -304,6 +326,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {

    lifecycleScope.launch {
      navigationViewModel.navigateTo.filterNotNull().collect { step ->
        Log.d(TAG, "navigateTo: $step")
        if (step is ConfirmDeviceCredential) {
          launchConfirmOrChooseLock(userId)
          navigationViewModel.update(
+79 −3
Original line number Diff line number Diff line
@@ -17,7 +17,21 @@
package com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
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.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel
import com.google.android.setupcompat.template.FooterBarMixin
import com.google.android.setupcompat.template.FooterButton
import com.google.android.setupdesign.GlifLayout
import kotlinx.coroutines.launch

/**
 * A fragment to indicate that fingerprint enrollment has been completed.
@@ -25,9 +39,71 @@ import androidx.fragment.app.Fragment
 * This page will display basic information about what a fingerprint can be used for and acts as the
 * final step of enrollment.
 */
class FingerprintEnrollConfirmationV2Fragment : Fragment() {
class FingerprintEnrollConfirmationV2Fragment() :
  Fragment(R.layout.fingerprint_enroll_finish_base) {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
  companion object {
    const val TAG = "FingerprintEnrollConfirmationV2Fragment"
  }

  /** Used for testing purposes */
  private var factory: ViewModelProvider.Factory? = null

  @VisibleForTesting
  constructor(theFactory: ViewModelProvider.Factory) : this() {
    factory = theFactory
  }

  private val viewModelProvider: ViewModelProvider by lazy {
    if (factory != null) {
      ViewModelProvider(requireActivity(), factory!!)
    } else {
      ViewModelProvider(requireActivity())
    }
  }

  private val viewModel: FingerprintEnrollConfirmationViewModel by lazy {
    viewModelProvider[FingerprintEnrollConfirmationViewModel::class.java]
  }

  override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View? =
    super.onCreateView(inflater, container, savedInstanceState).also { theView ->
      val mainView = theView!! as GlifLayout

      mainView.setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title)
      mainView.setDescriptionText(R.string.security_settings_fingerprint_enroll_finish_v2_message)

      val mixin = mainView.getMixin(FooterBarMixin::class.java)
      viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.RESUMED) {
          viewModel.isAddAnotherButtonVisible.collect {
            mixin.secondaryButton =
              FooterButton.Builder(requireContext())
                .setText(R.string.fingerprint_enroll_button_add)
                .setListener { viewModel.onAddAnotherButtonClicked() }
                .setButtonType(FooterButton.ButtonType.SKIP)
                .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary)
                .build()
          }
        }
      }

      mixin.setPrimaryButton(
        FooterButton.Builder(requireContext())
          .setText(R.string.security_settings_fingerprint_enroll_done)
          .setListener(this::onNextButtonClick)
          .setButtonType(FooterButton.ButtonType.NEXT)
          .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary)
          .build()
      )
    }

  @Suppress("UNUSED_PARAMETER")
  private fun onNextButtonClick(view: View?) {
    viewModel.onNextButtonClicked()
  }
}
+15 −4
Original line number Diff line number Diff line
@@ -47,10 +47,12 @@ class RFPSViewModel(
  /** Value to indicate if the text view is visible or not */
  val textViewIsVisible: Flow<Boolean> = _textViewIsVisible.asStateFlow()

  private var _shouldAnimateIcon: Flow<Boolean> =
    fingerprintEnrollViewModel.enrollFlowShouldBeRunning
  /** Indicates if the icon should be animating or not */
  val shouldAnimateIcon = fingerprintEnrollViewModel.enrollFlowShouldBeRunning
  val shouldAnimateIcon = _shouldAnimateIcon

  private val enrollFlow: Flow<FingerEnrollState?> = fingerprintEnrollViewModel.enrollFLow
  private var enrollFlow: Flow<FingerEnrollState?> = fingerprintEnrollViewModel.enrollFLow

  /**
   * Enroll progress message with a replay of size 1 allowing for new subscribers to get the most
@@ -59,7 +61,7 @@ class RFPSViewModel(
  val progress: Flow<FingerEnrollState.EnrollProgress?> =
    enrollFlow
      .filterIsInstance<FingerEnrollState.EnrollProgress>()
      .shareIn(viewModelScope, SharingStarted.Eagerly, 1)
      .shareIn(viewModelScope, SharingStarted.Eagerly, 0)

  /** Clear help message on enroll progress */
  val clearHelpMessage: Flow<Boolean> = progress.map { it != null }
@@ -122,6 +124,7 @@ class RFPSViewModel(

  /** Indicates the negative button has been clicked */
  fun negativeButtonClicked() {
    doReset()
    navigationViewModel.update(
      FingerprintAction.NEGATIVE_BUTTON_PRESSED,
      navStep,
@@ -129,11 +132,19 @@ class RFPSViewModel(
    )
  }

  /** Indicates that enrollment has been finished and we can proceed to the next step. */
  /** Indicates that an enrollment was completed */
  fun finishedSuccessfully() {
    doReset()
    navigationViewModel.update(FingerprintAction.NEXT, navStep, "${TAG}#progressFinished")
  }

  private fun doReset() {
    _textViewIsVisible.update { false }
    _shouldAnimateIcon = fingerprintEnrollViewModel.enrollFlowShouldBeRunning
    /** Indicates if the icon should be animating or not */
    enrollFlow = fingerprintEnrollViewModel.enrollFLow
  }

  class RFPSViewModelFactory(
    private val fingerprintEnrollEnrollingViewModel: FingerprintEnrollEnrollingViewModel,
    private val navigationViewModel: FingerprintNavigationViewModel,
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.biometrics.fingerprint2.ui.enrollment.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.android.settings.biometrics.fingerprint2.lib.domain.interactor.FingerprintManagerInteractor
import kotlinx.coroutines.flow.Flow

/**
 * Models the UI state for [FingerprintEnrollConfirmationV2Fragment]
 */
class FingerprintEnrollConfirmationViewModel(
  private val navigationViewModel: FingerprintNavigationViewModel,
  fingerprintInteractor: FingerprintManagerInteractor,
) : ViewModel() {

  /**
   * Indicates if the add another button is possible. This should only be true when the user is able
   * to enroll more fingerprints.
   */
  val isAddAnotherButtonVisible: Flow<Boolean> = fingerprintInteractor.canEnrollFingerprints

  /**
   * Indicates that the user has clicked the next button and is done with fingerprint enrollment.
   */
  fun onNextButtonClicked() {
    navigationViewModel.update(FingerprintAction.NEXT, navStep, "onNextButtonClicked")
  }

  /**
   * Indicates that the user has clicked the add another button and will be sent to the enrollment
   * screen.
   */
  fun onAddAnotherButtonClicked() {
    navigationViewModel.update(FingerprintAction.ADD_ANOTHER, navStep, "onAddAnotherButtonClicked")
  }

  class FingerprintEnrollConfirmationViewModelFactory(
    private val navigationViewModel: FingerprintNavigationViewModel,
    private val fingerprintInteractor: FingerprintManagerInteractor,
  ) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
      return FingerprintEnrollConfirmationViewModel(navigationViewModel, fingerprintInteractor) as T
    }
  }

  companion object {
    private const val TAG = "FingerprintEnrollConfirmationViewModel"
    private val navStep = FingerprintNavigationStep.Confirmation::class
  }
}
Loading