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

Commit f6849078 authored by Joshua McCloskey's avatar Joshua McCloskey
Browse files

UDFPS Enrollment Refactor (5/N)

Adding minor touch ups, such as starting the
FingerprintEnrollConfirmation when enrollment has been completed.

Bug: 297082837
Test: atest
Change-Id: I7b3edebb141bdb3e4648f71527d45dc5a0185b60
parent 0336781b
Loading
Loading
Loading
Loading
+8 −8
Original line number Original line Diff line number Diff line
@@ -14,38 +14,38 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


package com.android.settings.biometrics.fingerprint2.lib.model
package com.android.settings.biometrics.fingerprint2.data.model


/**
/**
 * A view model that describes the various stages of UDFPS Enrollment. This stages typically update
 * A view model that describes the various stages of UDFPS Enrollment. This stages typically update
 * the enrollment UI in a major way, such as changing the lottie animation or changing the location
 * the enrollment UI in a major way, such as changing the lottie animation or changing the location
 * of the where the user should press their fingerprint
 * of the where the user should press their fingerprint
 */
 */
sealed class StageViewModel {
sealed class EnrollStageModel {
  /** Unknown stage */
  /** Unknown stage */
  data object Unknown : StageViewModel()
  data object Unknown : EnrollStageModel()


  /** This is the stage that moves the fingerprint icon around during enrollment. */
  /** This is the stage that moves the fingerprint icon around during enrollment. */
  data object Guided : StageViewModel()
  data object Guided : EnrollStageModel()


  /** The center stage is the initial stage of enrollment. */
  /** The center stage is the initial stage of enrollment. */
  data object Center : StageViewModel()
  data object Center : EnrollStageModel()


  /**
  /**
   * Fingerprint stage of enrollment. Typically there is some sort of indication that a user should
   * Fingerprint stage of enrollment. Typically there is some sort of indication that a user should
   * be using their finger tip to enroll.
   * be using their finger tip to enroll.
   */
   */
  data object Fingertip : StageViewModel()
  data object Fingertip : EnrollStageModel()


  /**
  /**
   * Left edge stage of enrollment. Typically there is an indication that a user should be using the
   * Left edge stage of enrollment. Typically there is an indication that a user should be using the
   * left edge of their fingerprint.
   * left edge of their fingerprint.
   */
   */
  data object LeftEdge : StageViewModel()
  data object LeftEdge : EnrollStageModel()


  /**
  /**
   * Right edge stage of enrollment. Typically there is an indication that a user should be using
   * Right edge stage of enrollment. Typically there is an indication that a user should be using
   * the right edge of their fingerprint.
   * the right edge of their fingerprint.
   */
   */
  data object RightEdge : StageViewModel()
  data object RightEdge : EnrollStageModel()
}
}
+7 −7
Original line number Original line Diff line number Diff line
@@ -16,11 +16,11 @@


package com.android.settings.biometrics.fingerprint2.domain.interactor
package com.android.settings.biometrics.fingerprint2.domain.interactor


import com.android.settings.biometrics.fingerprint2.lib.model.StageViewModel
import com.android.settings.biometrics.fingerprint2.data.model.EnrollStageModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOf


typealias EnrollStageThresholds = Map<Float, StageViewModel>
typealias EnrollStageThresholds = Map<Float, EnrollStageModel>


/** Interactor that provides enroll stages for enrollment. */
/** Interactor that provides enroll stages for enrollment. */
interface EnrollStageInteractor {
interface EnrollStageInteractor {
@@ -33,11 +33,11 @@ class EnrollStageInteractorImpl() : EnrollStageInteractor {
  override val enrollStageThresholds: Flow<EnrollStageThresholds> =
  override val enrollStageThresholds: Flow<EnrollStageThresholds> =
    flowOf(
    flowOf(
      mapOf(
      mapOf(
        0.0f to StageViewModel.Center,
        0.0f to EnrollStageModel.Center,
        0.25f to StageViewModel.Guided,
        0.25f to EnrollStageModel.Guided,
        0.5f to StageViewModel.Fingertip,
        0.5f to EnrollStageModel.Fingertip,
        0.75f to StageViewModel.LeftEdge,
        0.75f to EnrollStageModel.LeftEdge,
        0.875f to StageViewModel.RightEdge,
        0.875f to EnrollStageModel.RightEdge,
      )
      )
    )
    )
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@ interface OrientationInteractor {
   * A flow that contains the rotation info matched against the def [config_reverseDefaultRotation]
   * A flow that contains the rotation info matched against the def [config_reverseDefaultRotation]
   */
   */
  val rotationFromDefault: Flow<Int>
  val rotationFromDefault: Flow<Int>

  /**
  /**
   * A Helper function that computes rotation if device is in
   * A Helper function that computes rotation if device is in
   * [R.bool.config_reverseDefaultConfigRotation]
   * [R.bool.config_reverseDefaultConfigRotation]
+96 −0
Original line number Original line 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.domain.interactor

import android.graphics.PointF
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update

/**
 * This interactor provides information about the current offset of the sensor for guided enrollment
 * on UDFPS devices.
 */
interface UdfpsEnrollInteractor {
  /** Indicates at which step a UDFPS enrollment is in. */
  fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int)

  /** Indicates if guided enrollment should be enabled or not. */
  fun updateGuidedEnrollment(enabled: Boolean)

  /**
   * A flow indicating how much the sensor image drawable should be offset for guided enrollment. A
   * null point indicates that the icon should be in its default position.
   */
  val guidedEnrollmentOffset: Flow<PointF>
}

/** Keeps track of which guided enrollment point we should be using */
class UdfpsEnrollInteractorImpl(
  pixelsPerMillimeter: Float,
  accessibilityInteractor: AccessibilityInteractor,
) : UdfpsEnrollInteractor {

  private var isGuidedEnrollment = MutableStateFlow(false)
  // Number of pixels per mm
  val px = pixelsPerMillimeter
  private val guidedEnrollmentPoints: MutableList<PointF> =
    mutableListOf(
      PointF(2.00f * px, 0.00f * px),
      PointF(0.87f * px, -2.70f * px),
      PointF(-1.80f * px, -1.31f * px),
      PointF(-1.80f * px, 1.31f * px),
      PointF(0.88f * px, 2.70f * px),
      PointF(3.94f * px, -1.06f * px),
      PointF(2.90f * px, -4.14f * px),
      PointF(-0.52f * px, -5.95f * px),
      PointF(-3.33f * px, -3.33f * px),
      PointF(-3.99f * px, -0.35f * px),
      PointF(-3.62f * px, 2.54f * px),
      PointF(-1.49f * px, 5.57f * px),
      PointF(2.29f * px, 4.92f * px),
      PointF(3.82f * px, 1.78f * px),
    )

  override fun onEnrollmentStep(stepsRemaining: Int, totalStep: Int) {
    val index = (totalStep - stepsRemaining) % guidedEnrollmentPoints.size
    _guidedEnrollment.update { guidedEnrollmentPoints[index] }
  }

  override fun updateGuidedEnrollment(enabled: Boolean) {
    isGuidedEnrollment.update { enabled }
  }

  private val _guidedEnrollment = MutableStateFlow(PointF(0f, 0f))
  override val guidedEnrollmentOffset: Flow<PointF> =
    combine(
      _guidedEnrollment,
      accessibilityInteractor.isAccessibilityEnabled,
      isGuidedEnrollment,
    ) { point, accessibilityEnabled, guidedEnrollmentEnabled ->
      if (accessibilityEnabled || !guidedEnrollmentEnabled) {
        return@combine PointF(0f, 0f)
      } else {
        return@combine PointF(point.x * SCALE, point.y * SCALE)
      }
    }

  companion object {
    private const val SCALE = 0.5f
  }
}
+29 −11
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.hardware.fingerprint.FingerprintManager
import android.os.Bundle
import android.os.Bundle
import android.os.Vibrator
import android.os.Vibrator
import android.util.Log
import android.util.Log
import android.util.TypedValue
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.fragment.app.Fragment
@@ -54,6 +55,8 @@ import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateI
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractorImpl
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.OrientationInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.OrientationInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.UdfpsEnrollInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.VibrationInteractorImpl
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.Default
@@ -89,6 +92,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.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Transition
import com.android.settings.flags.Flags
import com.android.settings.flags.Flags
import com.android.settings.password.ChooseLockGeneric
import com.android.settings.password.ChooseLockGeneric
import com.android.settings.password.ChooseLockSettingsHelper
import com.android.settings.password.ChooseLockSettingsHelper
@@ -116,6 +120,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
  private lateinit var foldStateInteractor: FoldStateInteractor
  private lateinit var foldStateInteractor: FoldStateInteractor
  private lateinit var orientationInteractor: OrientationInteractor
  private lateinit var orientationInteractor: OrientationInteractor
  private lateinit var displayDensityInteractor: DisplayDensityInteractor
  private lateinit var displayDensityInteractor: DisplayDensityInteractor
  private lateinit var udfpsEnrollInteractor: UdfpsEnrollInteractor
  private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
  private lateinit var fingerprintScrollViewModel: FingerprintScrollViewModel
  private lateinit var backgroundViewModel: BackgroundViewModel
  private lateinit var backgroundViewModel: BackgroundViewModel
  private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
  private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
@@ -256,6 +261,15 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
          fingerprintManager,
          fingerprintManager,
          Settings,
          Settings,
        )
        )
    val accessibilityInteractor =
      AccessibilityInteractorImpl(
        getSystemService(AccessibilityManager::class.java)!!,
        lifecycleScope,
      )

    val pixelsPerMillimeter =
      TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, context.resources.displayMetrics)
    udfpsEnrollInteractor = UdfpsEnrollInteractorImpl(pixelsPerMillimeter, accessibilityInteractor)


    val fingerprintManagerInteractor =
    val fingerprintManagerInteractor =
      FingerprintManagerInteractorImpl(
      FingerprintManagerInteractorImpl(
@@ -273,12 +287,6 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {


    val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo
    val hasConfirmedDeviceCredential = gatekeeperInfo is GatekeeperInfo.GatekeeperPasswordInfo


    val accessibilityInteractor =
      AccessibilityInteractorImpl(
        getSystemService(AccessibilityManager::class.java)!!,
        lifecycleScope,
      )

    navigationViewModel =
    navigationViewModel =
      ViewModelProvider(
      ViewModelProvider(
        this,
        this,
@@ -384,6 +392,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
          orientationInteractor,
          orientationInteractor,
          backgroundViewModel,
          backgroundViewModel,
          fingerprintSensorRepo,
          fingerprintSensorRepo,
          udfpsEnrollInteractor,
        ),
        ),
      )[UdfpsViewModel::class.java]
      )[UdfpsViewModel::class.java]


@@ -435,17 +444,17 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
                  else -> FingerprintEnrollEnrollingV2Fragment()
                  else -> FingerprintEnrollEnrollingV2Fragment()
                }
                }
              }
              }
              Introduction -> FingerprintEnrollIntroV2Fragment()
              is Introduction -> FingerprintEnrollIntroV2Fragment()
              else -> null
              else -> null
            }
            }


          if (theClass != null) {
          if (theClass != null) {
            supportFragmentManager.fragments.onEach { fragment ->
              supportFragmentManager.beginTransaction().remove(fragment).commit()
            }

            supportFragmentManager
            supportFragmentManager
              .beginTransaction()
              .beginTransaction()
              .setCustomAnimations(
                step.enterTransition.toAnimation(),
                step.exitTransition.toAnimation(),
              )
              .setReorderingAllowed(true)
              .setReorderingAllowed(true)
              .add(R.id.fragment_container_view, theClass::class.java, null)
              .add(R.id.fragment_container_view, theClass::class.java, null)
              .commit()
              .commit()
@@ -512,3 +521,12 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
    }
    }
  }
  }
}
}

private fun Transition.toAnimation(): Int {
  return when (this) {
    Transition.EnterFromLeft -> com.google.android.setupdesign.R.anim.sud_slide_back_in
    Transition.EnterFromRight -> com.google.android.setupdesign.R.anim.sud_slide_next_in
    Transition.ExitToLeft -> com.google.android.setupdesign.R.anim.sud_slide_next_out
    Transition.ExitToRight -> com.google.android.setupdesign.R.anim.sud_slide_back_out
  }
}
Loading