Merge "Modernize UDFPS views for maintainability" into udc-qpr-dev
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<com.android.systemui.biometrics.UdfpsKeyguardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/udfps_animation_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<!-- Add fingerprint views here. See udfps_keyguard_view_internal.xml. -->
|
||||||
|
|
||||||
|
</com.android.systemui.biometrics.UdfpsKeyguardView>
|
||||||
@@ -16,8 +16,7 @@
|
|||||||
-->
|
-->
|
||||||
<com.android.systemui.biometrics.UdfpsKeyguardViewLegacy
|
<com.android.systemui.biometrics.UdfpsKeyguardViewLegacy
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
android:id="@+id/udfps_animation_view_legacy"
|
||||||
android:id="@+id/udfps_animation_view"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ import com.android.systemui.flags.FeatureFlags;
|
|||||||
import com.android.systemui.flags.Flags;
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||||
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
|
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
|
||||||
|
import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter;
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
|
||||||
import com.android.systemui.log.SessionTracker;
|
import com.android.systemui.log.SessionTracker;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
@@ -153,6 +155,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
@NonNull private final SystemUIDialogManager mDialogManager;
|
@NonNull private final SystemUIDialogManager mDialogManager;
|
||||||
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||||
@NonNull private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
|
@NonNull private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
|
||||||
|
@NonNull private final Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels;
|
||||||
@NonNull private final VibratorHelper mVibrator;
|
@NonNull private final VibratorHelper mVibrator;
|
||||||
@NonNull private final FeatureFlags mFeatureFlags;
|
@NonNull private final FeatureFlags mFeatureFlags;
|
||||||
@NonNull private final FalsingManager mFalsingManager;
|
@NonNull private final FalsingManager mFalsingManager;
|
||||||
@@ -272,7 +275,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
(view, event, fromUdfpsView) -> onTouch(requestId, event,
|
(view, event, fromUdfpsView) -> onTouch(requestId, event,
|
||||||
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
|
fromUdfpsView), mActivityLaunchAnimator, mFeatureFlags,
|
||||||
mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsUtils,
|
mPrimaryBouncerInteractor, mAlternateBouncerInteractor, mUdfpsUtils,
|
||||||
mUdfpsKeyguardAccessibilityDelegate)));
|
mUdfpsKeyguardAccessibilityDelegate,
|
||||||
|
mUdfpsKeyguardViewModels)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -784,7 +788,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
private boolean shouldTryToDismissKeyguard() {
|
private boolean shouldTryToDismissKeyguard() {
|
||||||
return mOverlay != null
|
return mOverlay != null
|
||||||
&& mOverlay.getAnimationViewController()
|
&& mOverlay.getAnimationViewController()
|
||||||
instanceof UdfpsKeyguardViewControllerLegacy
|
instanceof UdfpsKeyguardViewControllerAdapter
|
||||||
&& mKeyguardStateController.canDismissLockScreen()
|
&& mKeyguardStateController.canDismissLockScreen()
|
||||||
&& !mAttemptedToDismissKeyguard;
|
&& !mAttemptedToDismissKeyguard;
|
||||||
}
|
}
|
||||||
@@ -829,7 +833,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
@NonNull InputManager inputManager,
|
@NonNull InputManager inputManager,
|
||||||
@NonNull UdfpsUtils udfpsUtils,
|
@NonNull UdfpsUtils udfpsUtils,
|
||||||
@NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
|
@NonNull KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
|
||||||
@NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate) {
|
@NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate,
|
||||||
|
@NonNull Provider<UdfpsKeyguardViewModels> udfpsKeyguardViewModelsProvider) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mExecution = execution;
|
mExecution = execution;
|
||||||
mVibrator = vibrator;
|
mVibrator = vibrator;
|
||||||
@@ -895,6 +900,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
|
|||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
|
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
|
||||||
|
mUdfpsKeyguardViewModels = udfpsKeyguardViewModelsProvider;
|
||||||
|
|
||||||
final UdfpsOverlayController mUdfpsOverlayController = new UdfpsOverlayController();
|
final UdfpsOverlayController mUdfpsOverlayController = new UdfpsOverlayController();
|
||||||
mFingerprintManager.setUdfpsOverlayController(mUdfpsOverlayController);
|
mFingerprintManager.setUdfpsOverlayController(mUdfpsOverlayController);
|
||||||
|
|||||||
@@ -46,15 +46,19 @@ import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan
|
|||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor
|
import com.android.keyguard.KeyguardUpdateMonitor
|
||||||
import com.android.settingslib.udfps.UdfpsUtils
|
|
||||||
import com.android.settingslib.udfps.UdfpsOverlayParams
|
import com.android.settingslib.udfps.UdfpsOverlayParams
|
||||||
|
import com.android.settingslib.udfps.UdfpsUtils
|
||||||
import com.android.systemui.R
|
import com.android.systemui.R
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||||
|
import com.android.systemui.biometrics.ui.controller.UdfpsKeyguardViewController
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.flags.Flags
|
import com.android.systemui.flags.Flags
|
||||||
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
import com.android.systemui.flags.Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS
|
||||||
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
|
import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.shade.ShadeExpansionStateManager
|
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
||||||
@@ -64,6 +68,8 @@ import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
|
|||||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import com.android.systemui.util.settings.SecureSettings
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import javax.inject.Provider
|
||||||
|
|
||||||
private const val TAG = "UdfpsControllerOverlay"
|
private const val TAG = "UdfpsControllerOverlay"
|
||||||
|
|
||||||
@@ -75,6 +81,7 @@ const val SETTING_REMOVE_ENROLLMENT_UI = "udfps_overlay_remove_enrollment_ui"
|
|||||||
* request. This state can persist across configuration changes via the [show] and [hide]
|
* request. This state can persist across configuration changes via the [show] and [hide]
|
||||||
* methods.
|
* methods.
|
||||||
*/
|
*/
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
@UiThread
|
@UiThread
|
||||||
class UdfpsControllerOverlay @JvmOverloads constructor(
|
class UdfpsControllerOverlay @JvmOverloads constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
@@ -105,6 +112,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
|||||||
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
|
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
|
||||||
private val udfpsUtils: UdfpsUtils,
|
private val udfpsUtils: UdfpsUtils,
|
||||||
private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
|
private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
|
||||||
|
private val udfpsKeyguardViewModels: Provider<UdfpsKeyguardViewModels>,
|
||||||
) {
|
) {
|
||||||
/** The view, when [isShowing], or null. */
|
/** The view, when [isShowing], or null. */
|
||||||
var overlayView: UdfpsView? = null
|
var overlayView: UdfpsView? = null
|
||||||
@@ -243,27 +251,40 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
REASON_AUTH_KEYGUARD -> {
|
REASON_AUTH_KEYGUARD -> {
|
||||||
UdfpsKeyguardViewControllerLegacy(
|
if (featureFlags.isEnabled(REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
|
||||||
view.addUdfpsView(R.layout.udfps_keyguard_view_legacy) {
|
udfpsKeyguardViewModels.get().setSensorBounds(sensorBounds)
|
||||||
updateSensorLocation(sensorBounds)
|
UdfpsKeyguardViewController(
|
||||||
},
|
view.addUdfpsView(R.layout.udfps_keyguard_view),
|
||||||
statusBarStateController,
|
statusBarStateController,
|
||||||
shadeExpansionStateManager,
|
shadeExpansionStateManager,
|
||||||
statusBarKeyguardViewManager,
|
dialogManager,
|
||||||
keyguardUpdateMonitor,
|
dumpManager,
|
||||||
dumpManager,
|
alternateBouncerInteractor,
|
||||||
transitionController,
|
udfpsKeyguardViewModels.get(),
|
||||||
configurationController,
|
)
|
||||||
keyguardStateController,
|
} else {
|
||||||
unlockedScreenOffAnimationController,
|
UdfpsKeyguardViewControllerLegacy(
|
||||||
dialogManager,
|
view.addUdfpsView(R.layout.udfps_keyguard_view_legacy) {
|
||||||
controller,
|
updateSensorLocation(sensorBounds)
|
||||||
activityLaunchAnimator,
|
},
|
||||||
featureFlags,
|
statusBarStateController,
|
||||||
primaryBouncerInteractor,
|
shadeExpansionStateManager,
|
||||||
alternateBouncerInteractor,
|
statusBarKeyguardViewManager,
|
||||||
udfpsKeyguardAccessibilityDelegate,
|
keyguardUpdateMonitor,
|
||||||
)
|
dumpManager,
|
||||||
|
transitionController,
|
||||||
|
configurationController,
|
||||||
|
keyguardStateController,
|
||||||
|
unlockedScreenOffAnimationController,
|
||||||
|
dialogManager,
|
||||||
|
controller,
|
||||||
|
activityLaunchAnimator,
|
||||||
|
featureFlags,
|
||||||
|
primaryBouncerInteractor,
|
||||||
|
alternateBouncerInteractor,
|
||||||
|
udfpsKeyguardAccessibilityDelegate,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
REASON_AUTH_BP -> {
|
REASON_AUTH_BP -> {
|
||||||
// note: empty controller, currently shows no visual affordance
|
// note: empty controller, currently shows no visual affordance
|
||||||
@@ -415,7 +436,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean {
|
private fun shouldRotate(animation: UdfpsAnimationViewController<*>?): Boolean {
|
||||||
if (animation !is UdfpsKeyguardViewControllerLegacy) {
|
if (animation !is UdfpsKeyguardViewControllerAdapter) {
|
||||||
// always rotate view if we're not on the keyguard
|
// always rotate view if we're not on the keyguard
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.biometrics
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
/** View corresponding with udfps_keyguard_view.xml */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class UdfpsKeyguardView(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet?,
|
||||||
|
) :
|
||||||
|
UdfpsAnimationView(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
) {
|
||||||
|
private val fingerprintDrawablePlaceHolder = UdfpsFpDrawable(context)
|
||||||
|
private var visible = false
|
||||||
|
|
||||||
|
override fun calculateAlpha(): Int {
|
||||||
|
return if (mPauseAuth) {
|
||||||
|
0
|
||||||
|
} else 255 // ViewModels handle animating alpha values
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDrawable(): UdfpsDrawable {
|
||||||
|
return fingerprintDrawablePlaceHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useExpandedOverlay(useExpandedOverlay: Boolean) {
|
||||||
|
mUseExpandedOverlay = useExpandedOverlay
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isVisible(): Boolean {
|
||||||
|
return visible
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setVisible(isVisible: Boolean) {
|
||||||
|
visible = isVisible
|
||||||
|
isPauseAuth = !visible
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
|
|||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.flags.Flags
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter
|
||||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.shade.ShadeExpansionListener
|
import com.android.systemui.shade.ShadeExpansionListener
|
||||||
@@ -80,7 +81,8 @@ constructor(
|
|||||||
shadeExpansionStateManager,
|
shadeExpansionStateManager,
|
||||||
systemUIDialogManager,
|
systemUIDialogManager,
|
||||||
dumpManager,
|
dumpManager,
|
||||||
) {
|
),
|
||||||
|
UdfpsKeyguardViewControllerAdapter {
|
||||||
private val useExpandedOverlay: Boolean =
|
private val useExpandedOverlay: Boolean =
|
||||||
featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
|
featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
|
||||||
private var showingUdfpsBouncer = false
|
private var showingUdfpsBouncer = false
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.biometrics.ui.controller
|
||||||
|
|
||||||
|
import com.android.systemui.biometrics.UdfpsAnimationViewController
|
||||||
|
import com.android.systemui.biometrics.UdfpsKeyguardView
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
||||||
|
import com.android.systemui.dump.DumpManager
|
||||||
|
import com.android.systemui.keyguard.ui.adapter.UdfpsKeyguardViewControllerAdapter
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels
|
||||||
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
|
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||||
|
import com.android.systemui.statusbar.phone.SystemUIDialogManager
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
/** Class that coordinates non-HBM animations during keyguard authentication. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
open class UdfpsKeyguardViewController(
|
||||||
|
val view: UdfpsKeyguardView,
|
||||||
|
statusBarStateController: StatusBarStateController,
|
||||||
|
shadeExpansionStateManager: ShadeExpansionStateManager,
|
||||||
|
systemUIDialogManager: SystemUIDialogManager,
|
||||||
|
dumpManager: DumpManager,
|
||||||
|
private val alternateBouncerInteractor: AlternateBouncerInteractor,
|
||||||
|
udfpsKeyguardViewModels: UdfpsKeyguardViewModels,
|
||||||
|
) :
|
||||||
|
UdfpsAnimationViewController<UdfpsKeyguardView>(
|
||||||
|
view,
|
||||||
|
statusBarStateController,
|
||||||
|
shadeExpansionStateManager,
|
||||||
|
systemUIDialogManager,
|
||||||
|
dumpManager,
|
||||||
|
),
|
||||||
|
UdfpsKeyguardViewControllerAdapter {
|
||||||
|
override val tag: String
|
||||||
|
get() = TAG
|
||||||
|
|
||||||
|
init {
|
||||||
|
udfpsKeyguardViewModels.bindViews(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onViewAttached() {
|
||||||
|
super.onViewAttached()
|
||||||
|
alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onViewDetached() {
|
||||||
|
super.onViewDetached()
|
||||||
|
alternateBouncerInteractor.setAlternateBouncerUIAvailable(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldPauseAuth(): Boolean {
|
||||||
|
return !view.isVisible()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun listenForTouchesOutsideView(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UdfpsKeyguardViewController"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -156,7 +156,12 @@ constructor(
|
|||||||
|
|
||||||
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
|
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
|
||||||
return ValueAnimator().apply {
|
return ValueAnimator().apply {
|
||||||
interpolator = Interpolators.LINEAR
|
interpolator =
|
||||||
|
when (toState) {
|
||||||
|
KeyguardState.ALTERNATE_BOUNCER -> Interpolators.FAST_OUT_SLOW_IN
|
||||||
|
else -> Interpolators.LINEAR
|
||||||
|
}
|
||||||
|
|
||||||
duration =
|
duration =
|
||||||
when (toState) {
|
when (toState) {
|
||||||
KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
|
KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
|
|||||||
import com.android.systemui.dagger.qualifiers.Application
|
import com.android.systemui.dagger.qualifiers.Application
|
||||||
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
|
||||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||||
|
import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER
|
||||||
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
|
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
|
||||||
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
|
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
|
||||||
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
|
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
|
||||||
@@ -61,6 +62,26 @@ constructor(
|
|||||||
val fromDreamingTransition: Flow<TransitionStep> =
|
val fromDreamingTransition: Flow<TransitionStep> =
|
||||||
repository.transitions.filter { step -> step.from == DREAMING }
|
repository.transitions.filter { step -> step.from == DREAMING }
|
||||||
|
|
||||||
|
/** (any)->Lockscreen transition information */
|
||||||
|
val anyStateToLockscreenTransition: Flow<TransitionStep> =
|
||||||
|
repository.transitions.filter { step -> step.to == LOCKSCREEN }
|
||||||
|
|
||||||
|
/** (any)->Occluded transition information */
|
||||||
|
val anyStateToOccludedTransition: Flow<TransitionStep> =
|
||||||
|
repository.transitions.filter { step -> step.to == OCCLUDED }
|
||||||
|
|
||||||
|
/** (any)->PrimaryBouncer transition information */
|
||||||
|
val anyStateToPrimaryBouncerTransition: Flow<TransitionStep> =
|
||||||
|
repository.transitions.filter { step -> step.to == PRIMARY_BOUNCER }
|
||||||
|
|
||||||
|
/** (any)->Dreaming transition information */
|
||||||
|
val anyStateToDreamingTransition: Flow<TransitionStep> =
|
||||||
|
repository.transitions.filter { step -> step.to == DREAMING }
|
||||||
|
|
||||||
|
/** (any)->AlternateBouncer transition information */
|
||||||
|
val anyStateToAlternateBouncerTransition: Flow<TransitionStep> =
|
||||||
|
repository.transitions.filter { step -> step.to == ALTERNATE_BOUNCER }
|
||||||
|
|
||||||
/** AOD->LOCKSCREEN transition information. */
|
/** AOD->LOCKSCREEN transition information. */
|
||||||
val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN)
|
val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN)
|
||||||
|
|
||||||
@@ -68,6 +89,9 @@ constructor(
|
|||||||
val dreamingToLockscreenTransition: Flow<TransitionStep> =
|
val dreamingToLockscreenTransition: Flow<TransitionStep> =
|
||||||
repository.transition(DREAMING, LOCKSCREEN)
|
repository.transition(DREAMING, LOCKSCREEN)
|
||||||
|
|
||||||
|
/** GONE->AOD transition information. */
|
||||||
|
val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD)
|
||||||
|
|
||||||
/** GONE->DREAMING transition information. */
|
/** GONE->DREAMING transition information. */
|
||||||
val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING)
|
val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.domain.interactor
|
||||||
|
|
||||||
|
import android.animation.FloatEvaluator
|
||||||
|
import android.animation.IntEvaluator
|
||||||
|
import com.android.systemui.common.ui.data.repository.ConfigurationRepository
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
||||||
|
/** Encapsulates business logic for transitions between UDFPS states on the keyguard. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SysUISingleton
|
||||||
|
class UdfpsKeyguardInteractor
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
configRepo: ConfigurationRepository,
|
||||||
|
burnInInteractor: BurnInInteractor,
|
||||||
|
keyguardInteractor: KeyguardInteractor,
|
||||||
|
) {
|
||||||
|
private val intEvaluator = IntEvaluator()
|
||||||
|
private val floatEvaluator = FloatEvaluator()
|
||||||
|
|
||||||
|
val dozeAmount = keyguardInteractor.dozeAmount
|
||||||
|
val scaleForResolution = configRepo.scaleForResolution
|
||||||
|
|
||||||
|
/** Burn-in offsets for the UDFPS view to mitigate burn-in on AOD. */
|
||||||
|
val burnInOffsets: Flow<BurnInOffsets> =
|
||||||
|
combine(
|
||||||
|
keyguardInteractor.dozeAmount,
|
||||||
|
burnInInteractor.udfpsBurnInXOffset,
|
||||||
|
burnInInteractor.udfpsBurnInYOffset,
|
||||||
|
burnInInteractor.udfpsBurnInProgress
|
||||||
|
) { dozeAmount, fullyDozingBurnInX, fullyDozingBurnInY, fullyDozingBurnInProgress ->
|
||||||
|
BurnInOffsets(
|
||||||
|
intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInX),
|
||||||
|
intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInY),
|
||||||
|
floatEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInProgress),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class BurnInOffsets(
|
||||||
|
val burnInXOffset: Int, // current x burn in offset based on the aodTransitionAmount
|
||||||
|
val burnInYOffset: Int, // current y burn in offset based on the aodTransitionAmount
|
||||||
|
val burnInProgress: Float, // current progress based on the aodTransitionAmount
|
||||||
|
)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.adapter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary adapter class while
|
||||||
|
* [com.android.systemui.biometrics.ui.controller.UdfpsKeyguardViewController] is being refactored
|
||||||
|
* before [com.android.systemui.biometrics.UdfpsKeyguardViewControllerLegacy] is removed.
|
||||||
|
*
|
||||||
|
* TODO (b/278719514): Delete once udfps keyguard view is fully refactored.
|
||||||
|
*/
|
||||||
|
interface UdfpsKeyguardViewControllerAdapter
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.binder
|
||||||
|
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import com.airbnb.lottie.LottieAnimationView
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsAodViewModel
|
||||||
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
object UdfpsAodFingerprintViewBinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drives UI for the UDFPS aod fingerprint view. See [UdfpsFingerprintViewBinder] and
|
||||||
|
* [UdfpsBackgroundViewBinder].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun bind(
|
||||||
|
view: LottieAnimationView,
|
||||||
|
viewModel: UdfpsAodViewModel,
|
||||||
|
) {
|
||||||
|
view.repeatWhenAttached {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
launch {
|
||||||
|
viewModel.burnInOffsets.collect { burnInOffsets ->
|
||||||
|
view.progress = burnInOffsets.burnInProgress
|
||||||
|
view.translationX = burnInOffsets.burnInXOffset.toFloat()
|
||||||
|
view.translationY = burnInOffsets.burnInYOffset.toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
|
||||||
|
|
||||||
|
launch {
|
||||||
|
viewModel.padding.collect { padding ->
|
||||||
|
view.setPadding(padding, padding, padding, padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.binder
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.BackgroundViewModel
|
||||||
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
object UdfpsBackgroundViewBinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drives UI for the udfps background view. See [UdfpsAodFingerprintViewBinder] and
|
||||||
|
* [UdfpsFingerprintViewBinder].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun bind(
|
||||||
|
view: ImageView,
|
||||||
|
viewModel: BackgroundViewModel,
|
||||||
|
) {
|
||||||
|
view.repeatWhenAttached {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
launch {
|
||||||
|
viewModel.transition.collect {
|
||||||
|
view.alpha = it.alpha
|
||||||
|
view.scaleX = it.scale
|
||||||
|
view.scaleY = it.scale
|
||||||
|
view.imageTintList = ColorStateList.valueOf(it.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.binder
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import com.airbnb.lottie.LottieAnimationView
|
||||||
|
import com.airbnb.lottie.LottieProperty
|
||||||
|
import com.airbnb.lottie.model.KeyPath
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.FingerprintViewModel
|
||||||
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
object UdfpsFingerprintViewBinder {
|
||||||
|
private var udfpsIconColor = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drives UI for the UDFPS fingerprint view when it's NOT on aod. See
|
||||||
|
* [UdfpsAodFingerprintViewBinder] and [UdfpsBackgroundViewBinder].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun bind(
|
||||||
|
view: LottieAnimationView,
|
||||||
|
viewModel: FingerprintViewModel,
|
||||||
|
) {
|
||||||
|
view.repeatWhenAttached {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
launch {
|
||||||
|
viewModel.transition.collect {
|
||||||
|
view.alpha = it.alpha
|
||||||
|
view.scaleX = it.scale
|
||||||
|
view.scaleY = it.scale
|
||||||
|
if (udfpsIconColor != (it.color)) {
|
||||||
|
udfpsIconColor = it.color
|
||||||
|
view.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
viewModel.burnInOffsets.collect { burnInOffsets ->
|
||||||
|
view.translationX = burnInOffsets.burnInXOffset.toFloat()
|
||||||
|
view.translationY = burnInOffsets.burnInYOffset.toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
viewModel.dozeAmount.collect { dozeAmount ->
|
||||||
|
// Lottie progress represents: aod=0 to lockscreen=1
|
||||||
|
view.progress = 1f - dozeAmount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
viewModel.padding.collect { padding ->
|
||||||
|
view.setPadding(padding, padding, padding, padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a callback that updates the color to `udfpsIconColor` whenever invalidate is called
|
||||||
|
view.addValueCallback(KeyPath("**"), LottieProperty.COLOR_FILTER) {
|
||||||
|
PorterDuffColorFilter(udfpsIconColor, PorterDuff.Mode.SRC_ATOP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.biometrics.ui.binder
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.keyguard.ui.binder.UdfpsAodFingerprintViewBinder
|
||||||
|
import com.android.systemui.keyguard.ui.binder.UdfpsBackgroundViewBinder
|
||||||
|
import com.android.systemui.keyguard.ui.binder.UdfpsFingerprintViewBinder
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.BackgroundViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.FingerprintViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsAodViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardInternalViewModel
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
object UdfpsKeyguardInternalViewBinder {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun bind(
|
||||||
|
view: View,
|
||||||
|
viewModel: UdfpsKeyguardInternalViewModel,
|
||||||
|
aodViewModel: UdfpsAodViewModel,
|
||||||
|
fingerprintViewModel: FingerprintViewModel,
|
||||||
|
backgroundViewModel: BackgroundViewModel,
|
||||||
|
) {
|
||||||
|
view.accessibilityDelegate = viewModel.accessibilityDelegate
|
||||||
|
|
||||||
|
// bind child views
|
||||||
|
UdfpsAodFingerprintViewBinder.bind(view.findViewById(R.id.udfps_aod_fp), aodViewModel)
|
||||||
|
UdfpsFingerprintViewBinder.bind(
|
||||||
|
view.findViewById(R.id.udfps_lockscreen_fp),
|
||||||
|
fingerprintViewModel
|
||||||
|
)
|
||||||
|
UdfpsBackgroundViewBinder.bind(
|
||||||
|
view.findViewById(R.id.udfps_keyguard_fp_bg),
|
||||||
|
backgroundViewModel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.binder
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.biometrics.UdfpsKeyguardView
|
||||||
|
import com.android.systemui.biometrics.ui.binder.UdfpsKeyguardInternalViewBinder
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.BackgroundViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.FingerprintViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsAodViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardInternalViewModel
|
||||||
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModel
|
||||||
|
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
object UdfpsKeyguardViewBinder {
|
||||||
|
/**
|
||||||
|
* Drives UI for the keyguard UDFPS view. Inflates child views on a background thread. For view
|
||||||
|
* binders for its child views, see [UdfpsFingerprintViewBinder], [UdfpsBackgroundViewBinder] &
|
||||||
|
* [UdfpsAodFingerprintViewBinder].
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun bind(
|
||||||
|
view: UdfpsKeyguardView,
|
||||||
|
viewModel: UdfpsKeyguardViewModel,
|
||||||
|
udfpsKeyguardInternalViewModel: UdfpsKeyguardInternalViewModel,
|
||||||
|
aodViewModel: UdfpsAodViewModel,
|
||||||
|
fingerprintViewModel: FingerprintViewModel,
|
||||||
|
backgroundViewModel: BackgroundViewModel,
|
||||||
|
) {
|
||||||
|
view.useExpandedOverlay(viewModel.useExpandedOverlay())
|
||||||
|
|
||||||
|
val layoutInflaterFinishListener =
|
||||||
|
AsyncLayoutInflater.OnInflateFinishedListener { inflatedInternalView, _, parent ->
|
||||||
|
UdfpsKeyguardInternalViewBinder.bind(
|
||||||
|
inflatedInternalView,
|
||||||
|
udfpsKeyguardInternalViewModel,
|
||||||
|
aodViewModel,
|
||||||
|
fingerprintViewModel,
|
||||||
|
backgroundViewModel,
|
||||||
|
)
|
||||||
|
if (viewModel.useExpandedOverlay()) {
|
||||||
|
val lp = inflatedInternalView.layoutParams as FrameLayout.LayoutParams
|
||||||
|
lp.width = viewModel.sensorBounds.width()
|
||||||
|
lp.height = viewModel.sensorBounds.height()
|
||||||
|
val relativeToView =
|
||||||
|
getBoundsRelativeToView(
|
||||||
|
inflatedInternalView,
|
||||||
|
RectF(viewModel.sensorBounds),
|
||||||
|
)
|
||||||
|
lp.setMarginsRelative(
|
||||||
|
relativeToView.left.toInt(),
|
||||||
|
relativeToView.top.toInt(),
|
||||||
|
relativeToView.right.toInt(),
|
||||||
|
relativeToView.bottom.toInt(),
|
||||||
|
)
|
||||||
|
parent!!.addView(inflatedInternalView, lp)
|
||||||
|
} else {
|
||||||
|
parent!!.addView(inflatedInternalView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val inflater = AsyncLayoutInflater(view.context)
|
||||||
|
inflater.inflate(R.layout.udfps_keyguard_view_internal, view, layoutInflaterFinishListener)
|
||||||
|
|
||||||
|
view.repeatWhenAttached {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||||
|
launch {
|
||||||
|
combine(aodViewModel.isVisible, fingerprintViewModel.visible) {
|
||||||
|
isAodVisible,
|
||||||
|
isFingerprintVisible ->
|
||||||
|
isAodVisible || isFingerprintVisible
|
||||||
|
}
|
||||||
|
.collect { view.setVisible(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts coordinates of RectF relative to the screen to coordinates relative to this view.
|
||||||
|
*
|
||||||
|
* @param bounds RectF based off screen coordinates in current orientation
|
||||||
|
*/
|
||||||
|
private fun getBoundsRelativeToView(view: View, bounds: RectF): RectF {
|
||||||
|
val pos: IntArray = view.locationOnScreen
|
||||||
|
return RectF(
|
||||||
|
bounds.left - pos[0],
|
||||||
|
bounds.top - pos[1],
|
||||||
|
bounds.right - pos[0],
|
||||||
|
bounds.bottom - pos[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
/** View-model for UDFPS AOD view. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class UdfpsAodViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
val interactor: UdfpsKeyguardInteractor,
|
||||||
|
val context: Context,
|
||||||
|
) {
|
||||||
|
val alpha: Flow<Float> = interactor.dozeAmount
|
||||||
|
val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
|
||||||
|
val isVisible: Flow<Boolean> = alpha.map { it != 0f }
|
||||||
|
|
||||||
|
// Padding between the fingerprint icon and its bounding box in pixels.
|
||||||
|
val padding: Flow<Int> =
|
||||||
|
interactor.scaleForResolution.map { scale ->
|
||||||
|
(context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale)
|
||||||
|
.roundToInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import com.android.systemui.biometrics.UdfpsKeyguardAccessibilityDelegate
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class UdfpsKeyguardInternalViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(val accessibilityDelegate: UdfpsKeyguardAccessibilityDelegate)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
|
import com.android.systemui.flags.FeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class UdfpsKeyguardViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val featureFlags: FeatureFlags,
|
||||||
|
) {
|
||||||
|
var sensorBounds: Rect = Rect()
|
||||||
|
|
||||||
|
fun useExpandedOverlay(): Boolean {
|
||||||
|
return featureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.android.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
|
import com.android.systemui.biometrics.UdfpsKeyguardView
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.keyguard.ui.binder.UdfpsKeyguardViewBinder
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SysUISingleton
|
||||||
|
class UdfpsKeyguardViewModels
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val viewModel: UdfpsKeyguardViewModel,
|
||||||
|
private val internalViewModel: UdfpsKeyguardInternalViewModel,
|
||||||
|
private val aodViewModel: UdfpsAodViewModel,
|
||||||
|
private val lockscreenFingerprintViewModel: FingerprintViewModel,
|
||||||
|
private val lockscreenBackgroundViewModel: BackgroundViewModel,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun setSensorBounds(sensorBounds: Rect) {
|
||||||
|
viewModel.sensorBounds = sensorBounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bindViews(view: UdfpsKeyguardView) {
|
||||||
|
UdfpsKeyguardViewBinder.bind(
|
||||||
|
view,
|
||||||
|
viewModel,
|
||||||
|
internalViewModel,
|
||||||
|
aodViewModel,
|
||||||
|
lockscreenFingerprintViewModel,
|
||||||
|
lockscreenBackgroundViewModel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import com.android.settingslib.Utils.getColorAttrDefaultColor
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.BurnInOffsets
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
|
||||||
|
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
|
||||||
|
/** View-model for UDFPS lockscreen views. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
open class UdfpsLockscreenViewModel(
|
||||||
|
context: Context,
|
||||||
|
lockscreenColorResId: Int,
|
||||||
|
alternateBouncerColorResId: Int,
|
||||||
|
transitionInteractor: KeyguardTransitionInteractor,
|
||||||
|
) {
|
||||||
|
private val toLockscreen: Flow<TransitionViewModel> =
|
||||||
|
transitionInteractor.anyStateToLockscreenTransition.map {
|
||||||
|
TransitionViewModel(
|
||||||
|
alpha =
|
||||||
|
if (it.from == KeyguardState.AOD) {
|
||||||
|
it.value // animate
|
||||||
|
} else {
|
||||||
|
1f
|
||||||
|
},
|
||||||
|
scale = 1f,
|
||||||
|
color = getColorAttrDefaultColor(context, lockscreenColorResId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val toAlternateBouncer: Flow<TransitionViewModel> =
|
||||||
|
transitionInteractor.anyStateToAlternateBouncerTransition.map {
|
||||||
|
TransitionViewModel(
|
||||||
|
alpha = 1f,
|
||||||
|
scale =
|
||||||
|
if (visibleInKeyguardState(it.from)) {
|
||||||
|
1f
|
||||||
|
} else {
|
||||||
|
it.value
|
||||||
|
},
|
||||||
|
color = getColorAttrDefaultColor(context, alternateBouncerColorResId),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fadeOut: Flow<TransitionViewModel> =
|
||||||
|
merge(
|
||||||
|
transitionInteractor.anyStateToGoneTransition,
|
||||||
|
transitionInteractor.anyStateToAodTransition,
|
||||||
|
transitionInteractor.anyStateToOccludedTransition,
|
||||||
|
transitionInteractor.anyStateToPrimaryBouncerTransition,
|
||||||
|
transitionInteractor.anyStateToDreamingTransition,
|
||||||
|
)
|
||||||
|
.map {
|
||||||
|
TransitionViewModel(
|
||||||
|
alpha =
|
||||||
|
if (visibleInKeyguardState(it.from)) {
|
||||||
|
1f - it.value
|
||||||
|
} else {
|
||||||
|
0f
|
||||||
|
},
|
||||||
|
scale = 1f,
|
||||||
|
color =
|
||||||
|
if (it.from == KeyguardState.ALTERNATE_BOUNCER) {
|
||||||
|
getColorAttrDefaultColor(context, alternateBouncerColorResId)
|
||||||
|
} else {
|
||||||
|
getColorAttrDefaultColor(context, lockscreenColorResId)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visibleInKeyguardState(state: KeyguardState): Boolean {
|
||||||
|
return when (state) {
|
||||||
|
KeyguardState.OFF,
|
||||||
|
KeyguardState.DOZING,
|
||||||
|
KeyguardState.DREAMING,
|
||||||
|
KeyguardState.AOD,
|
||||||
|
KeyguardState.PRIMARY_BOUNCER,
|
||||||
|
KeyguardState.GONE,
|
||||||
|
KeyguardState.OCCLUDED -> false
|
||||||
|
KeyguardState.LOCKSCREEN,
|
||||||
|
KeyguardState.ALTERNATE_BOUNCER -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val transition: Flow<TransitionViewModel> =
|
||||||
|
merge(
|
||||||
|
toAlternateBouncer,
|
||||||
|
toLockscreen,
|
||||||
|
fadeOut,
|
||||||
|
)
|
||||||
|
val visible: Flow<Boolean> = transition.map { it.alpha != 0f }
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class FingerprintViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
val context: Context,
|
||||||
|
transitionInteractor: KeyguardTransitionInteractor,
|
||||||
|
interactor: UdfpsKeyguardInteractor,
|
||||||
|
) :
|
||||||
|
UdfpsLockscreenViewModel(
|
||||||
|
context,
|
||||||
|
android.R.attr.textColorPrimary,
|
||||||
|
com.android.internal.R.attr.materialColorOnPrimaryFixed,
|
||||||
|
transitionInteractor,
|
||||||
|
) {
|
||||||
|
val dozeAmount: Flow<Float> = interactor.dozeAmount
|
||||||
|
val burnInOffsets: Flow<BurnInOffsets> = interactor.burnInOffsets
|
||||||
|
|
||||||
|
// Padding between the fingerprint icon and its bounding box in pixels.
|
||||||
|
val padding: Flow<Int> =
|
||||||
|
interactor.scaleForResolution.map { scale ->
|
||||||
|
(context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale)
|
||||||
|
.roundToInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class BackgroundViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
val context: Context,
|
||||||
|
transitionInteractor: KeyguardTransitionInteractor,
|
||||||
|
) :
|
||||||
|
UdfpsLockscreenViewModel(
|
||||||
|
context,
|
||||||
|
com.android.internal.R.attr.colorSurface,
|
||||||
|
com.android.internal.R.attr.materialColorPrimaryFixed,
|
||||||
|
transitionInteractor,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TransitionViewModel(
|
||||||
|
val alpha: Float,
|
||||||
|
val scale: Float,
|
||||||
|
@ColorInt val color: Int,
|
||||||
|
)
|
||||||
@@ -43,11 +43,12 @@ import com.android.systemui.R
|
|||||||
import com.android.systemui.RoboPilotTest
|
import com.android.systemui.RoboPilotTest
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.animation.ActivityLaunchAnimator
|
import com.android.systemui.animation.ActivityLaunchAnimator
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
import com.android.systemui.flags.FeatureFlags
|
import com.android.systemui.flags.FeatureFlags
|
||||||
import com.android.systemui.flags.Flags
|
import com.android.systemui.flags.Flags
|
||||||
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels
|
||||||
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
|
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||||
import com.android.systemui.shade.ShadeExpansionStateManager
|
import com.android.systemui.shade.ShadeExpansionStateManager
|
||||||
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
import com.android.systemui.statusbar.LockscreenShadeTransitionController
|
||||||
@@ -58,6 +59,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController
|
|||||||
import com.android.systemui.statusbar.policy.KeyguardStateController
|
import com.android.systemui.statusbar.policy.KeyguardStateController
|
||||||
import com.android.systemui.util.settings.SecureSettings
|
import com.android.systemui.util.settings.SecureSettings
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -70,6 +72,7 @@ import org.mockito.Mock
|
|||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.junit.MockitoJUnit
|
import org.mockito.junit.MockitoJUnit
|
||||||
|
import javax.inject.Provider
|
||||||
import org.mockito.Mockito.`when` as whenever
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
private const val REQUEST_ID = 2L
|
private const val REQUEST_ID = 2L
|
||||||
@@ -80,6 +83,7 @@ private const val DISPLAY_HEIGHT = 1920
|
|||||||
private const val SENSOR_WIDTH = 30
|
private const val SENSOR_WIDTH = 30
|
||||||
private const val SENSOR_HEIGHT = 60
|
private const val SENSOR_HEIGHT = 60
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RoboPilotTest
|
@RoboPilotTest
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@@ -116,6 +120,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
|||||||
@Mock private lateinit var udfpsUtils: UdfpsUtils
|
@Mock private lateinit var udfpsUtils: UdfpsUtils
|
||||||
@Mock private lateinit var udfpsKeyguardAccessibilityDelegate:
|
@Mock private lateinit var udfpsKeyguardAccessibilityDelegate:
|
||||||
UdfpsKeyguardAccessibilityDelegate
|
UdfpsKeyguardAccessibilityDelegate
|
||||||
|
@Mock private lateinit var udfpsKeyguardViewModels: Provider<UdfpsKeyguardViewModels>
|
||||||
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
|
@Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
|
||||||
|
|
||||||
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
|
private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
|
||||||
@@ -148,6 +153,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
|
|||||||
controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
|
controllerCallback, onTouch, activityLaunchAnimator, featureFlags,
|
||||||
primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable, udfpsUtils,
|
primaryBouncerInteractor, alternateBouncerInteractor, isDebuggable, udfpsUtils,
|
||||||
udfpsKeyguardAccessibilityDelegate,
|
udfpsKeyguardAccessibilityDelegate,
|
||||||
|
udfpsKeyguardViewModels,
|
||||||
)
|
)
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,13 +83,14 @@ import com.android.systemui.biometrics.udfps.InteractionEvent;
|
|||||||
import com.android.systemui.biometrics.udfps.NormalizedTouchData;
|
import com.android.systemui.biometrics.udfps.NormalizedTouchData;
|
||||||
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
|
import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
|
||||||
import com.android.systemui.biometrics.udfps.TouchProcessorResult;
|
import com.android.systemui.biometrics.udfps.TouchProcessorResult;
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
|
||||||
|
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
import com.android.systemui.flags.FeatureFlags;
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
import com.android.systemui.flags.Flags;
|
import com.android.systemui.flags.Flags;
|
||||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||||
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
|
|
||||||
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
|
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
|
||||||
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
|
import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModels;
|
||||||
import com.android.systemui.log.SessionTracker;
|
import com.android.systemui.log.SessionTracker;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
@@ -219,6 +220,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
|||||||
private SecureSettings mSecureSettings;
|
private SecureSettings mSecureSettings;
|
||||||
@Mock
|
@Mock
|
||||||
private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
|
private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
|
||||||
|
@Mock
|
||||||
|
private Provider<UdfpsKeyguardViewModels> mUdfpsKeyguardViewModels;
|
||||||
|
|
||||||
// Capture listeners so that they can be used to send events
|
// Capture listeners so that they can be used to send events
|
||||||
@Captor
|
@Captor
|
||||||
@@ -318,7 +321,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
|||||||
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker,
|
mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker,
|
||||||
mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils,
|
mAlternateBouncerInteractor, mSecureSettings, mInputManager, mUdfpsUtils,
|
||||||
mock(KeyguardFaceAuthInteractor.class),
|
mock(KeyguardFaceAuthInteractor.class),
|
||||||
mUdfpsKeyguardAccessibilityDelegate);
|
mUdfpsKeyguardAccessibilityDelegate, mUdfpsKeyguardViewModels);
|
||||||
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
|
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
|
||||||
mOverlayController = mOverlayCaptor.getValue();
|
mOverlayController = mOverlayCaptor.getValue();
|
||||||
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
|
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.domain.interactor
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
||||||
|
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
|
||||||
|
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.doze.util.BurnInHelperWrapper
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||||
|
import com.android.systemui.keyguard.shared.model.StatusBarState
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakeSleepReason
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||||
|
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||||
|
import com.android.systemui.util.mockito.eq
|
||||||
|
import com.android.systemui.util.mockito.whenever
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class UdfpsKeyguardInteractorTest : SysuiTestCase() {
|
||||||
|
private val burnInProgress = 1f
|
||||||
|
private val burnInYOffset = 20
|
||||||
|
private val burnInXOffset = 10
|
||||||
|
|
||||||
|
private lateinit var testScope: TestScope
|
||||||
|
private lateinit var configRepository: FakeConfigurationRepository
|
||||||
|
private lateinit var bouncerRepository: KeyguardBouncerRepository
|
||||||
|
private lateinit var keyguardRepository: FakeKeyguardRepository
|
||||||
|
private lateinit var fakeCommandQueue: FakeCommandQueue
|
||||||
|
private lateinit var featureFlags: FakeFeatureFlags
|
||||||
|
private lateinit var burnInInteractor: BurnInInteractor
|
||||||
|
|
||||||
|
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
|
||||||
|
|
||||||
|
private lateinit var underTest: UdfpsKeyguardInteractor
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
|
testScope = TestScope()
|
||||||
|
configRepository = FakeConfigurationRepository()
|
||||||
|
keyguardRepository = FakeKeyguardRepository()
|
||||||
|
bouncerRepository = FakeKeyguardBouncerRepository()
|
||||||
|
fakeCommandQueue = FakeCommandQueue()
|
||||||
|
featureFlags =
|
||||||
|
FakeFeatureFlags().apply {
|
||||||
|
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
|
||||||
|
set(Flags.FACE_AUTH_REFACTOR, false)
|
||||||
|
}
|
||||||
|
burnInInteractor =
|
||||||
|
BurnInInteractor(
|
||||||
|
context,
|
||||||
|
burnInHelper,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
configRepository,
|
||||||
|
FakeSystemClock(),
|
||||||
|
)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
UdfpsKeyguardInteractor(
|
||||||
|
configRepository,
|
||||||
|
burnInInteractor,
|
||||||
|
KeyguardInteractor(
|
||||||
|
keyguardRepository,
|
||||||
|
fakeCommandQueue,
|
||||||
|
featureFlags,
|
||||||
|
bouncerRepository,
|
||||||
|
configRepository,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dozeChanges_updatesUdfpsAodModel() =
|
||||||
|
testScope.runTest {
|
||||||
|
val burnInOffsets by collectLastValue(underTest.burnInOffsets)
|
||||||
|
initializeBurnInOffsets()
|
||||||
|
|
||||||
|
// WHEN we're not dozing
|
||||||
|
setAwake()
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
// THEN burn in offsets are 0
|
||||||
|
assertThat(burnInOffsets?.burnInProgress).isEqualTo(0f)
|
||||||
|
assertThat(burnInOffsets?.burnInYOffset).isEqualTo(0)
|
||||||
|
assertThat(burnInOffsets?.burnInXOffset).isEqualTo(0)
|
||||||
|
|
||||||
|
// WHEN we're in the middle of the doze amount change
|
||||||
|
keyguardRepository.setDozeAmount(.50f)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
// THEN burn in is updated (between 0 and the full offset)
|
||||||
|
assertThat(burnInOffsets?.burnInProgress).isGreaterThan(0f)
|
||||||
|
assertThat(burnInOffsets?.burnInYOffset).isGreaterThan(0)
|
||||||
|
assertThat(burnInOffsets?.burnInXOffset).isGreaterThan(0)
|
||||||
|
assertThat(burnInOffsets?.burnInProgress).isLessThan(burnInProgress)
|
||||||
|
assertThat(burnInOffsets?.burnInYOffset).isLessThan(burnInYOffset)
|
||||||
|
assertThat(burnInOffsets?.burnInXOffset).isLessThan(burnInXOffset)
|
||||||
|
|
||||||
|
// WHEN we're fully dozing
|
||||||
|
keyguardRepository.setDozeAmount(1f)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
// THEN burn in offsets are updated to final current values (for the given time)
|
||||||
|
assertThat(burnInOffsets?.burnInProgress).isEqualTo(burnInProgress)
|
||||||
|
assertThat(burnInOffsets?.burnInYOffset).isEqualTo(burnInYOffset)
|
||||||
|
assertThat(burnInOffsets?.burnInXOffset).isEqualTo(burnInXOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeBurnInOffsets() {
|
||||||
|
whenever(burnInHelper.burnInProgressOffset()).thenReturn(burnInProgress)
|
||||||
|
whenever(burnInHelper.burnInOffset(anyInt(), /* xAxis */ eq(true)))
|
||||||
|
.thenReturn(burnInXOffset)
|
||||||
|
whenever(burnInHelper.burnInOffset(anyInt(), /* xAxis */ eq(false)))
|
||||||
|
.thenReturn(burnInYOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setAwake() {
|
||||||
|
keyguardRepository.setDozeAmount(0f)
|
||||||
|
burnInInteractor.dozeTimeTick()
|
||||||
|
|
||||||
|
bouncerRepository.setAlternateVisible(false)
|
||||||
|
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
|
||||||
|
bouncerRepository.setPrimaryShow(false)
|
||||||
|
keyguardRepository.setWakefulnessModel(
|
||||||
|
WakefulnessModel(
|
||||||
|
WakefulnessState.AWAKE,
|
||||||
|
WakeSleepReason.POWER_BUTTON,
|
||||||
|
WakeSleepReason.POWER_BUTTON,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.RoboPilotTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
||||||
|
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
|
||||||
|
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.doze.util.BurnInHelperWrapper
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SmallTest
|
||||||
|
@RoboPilotTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class UdfpsAodViewModelTest : SysuiTestCase() {
|
||||||
|
private val defaultPadding = 12
|
||||||
|
private lateinit var underTest: UdfpsAodViewModel
|
||||||
|
|
||||||
|
private lateinit var testScope: TestScope
|
||||||
|
private lateinit var configRepository: FakeConfigurationRepository
|
||||||
|
private lateinit var bouncerRepository: KeyguardBouncerRepository
|
||||||
|
private lateinit var keyguardRepository: FakeKeyguardRepository
|
||||||
|
private lateinit var fakeCommandQueue: FakeCommandQueue
|
||||||
|
private lateinit var featureFlags: FakeFeatureFlags
|
||||||
|
|
||||||
|
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
overrideResource(com.android.systemui.R.dimen.lock_icon_padding, defaultPadding)
|
||||||
|
testScope = TestScope()
|
||||||
|
configRepository = FakeConfigurationRepository()
|
||||||
|
keyguardRepository = FakeKeyguardRepository()
|
||||||
|
bouncerRepository = FakeKeyguardBouncerRepository()
|
||||||
|
fakeCommandQueue = FakeCommandQueue()
|
||||||
|
featureFlags =
|
||||||
|
FakeFeatureFlags().apply {
|
||||||
|
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
|
||||||
|
set(Flags.FACE_AUTH_REFACTOR, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val udfpsKeyguardInteractor =
|
||||||
|
UdfpsKeyguardInteractor(
|
||||||
|
configRepository,
|
||||||
|
BurnInInteractor(
|
||||||
|
context,
|
||||||
|
burnInHelper,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
configRepository,
|
||||||
|
FakeSystemClock(),
|
||||||
|
),
|
||||||
|
KeyguardInteractor(
|
||||||
|
keyguardRepository,
|
||||||
|
fakeCommandQueue,
|
||||||
|
featureFlags,
|
||||||
|
bouncerRepository,
|
||||||
|
configRepository,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
UdfpsAodViewModel(
|
||||||
|
udfpsKeyguardInteractor,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun alphaAndVisibleUpdates_onDozeAmountChanges() =
|
||||||
|
testScope.runTest {
|
||||||
|
val alpha by collectLastValue(underTest.alpha)
|
||||||
|
val visible by collectLastValue(underTest.isVisible)
|
||||||
|
|
||||||
|
keyguardRepository.setDozeAmount(0f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(alpha).isEqualTo(0f)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
|
||||||
|
keyguardRepository.setDozeAmount(.65f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(alpha).isEqualTo(.65f)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
keyguardRepository.setDozeAmount(.23f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(alpha).isEqualTo(.23f)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
keyguardRepository.setDozeAmount(1f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(alpha).isEqualTo(1f)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun paddingUpdates_onScaleForResolutionChanges() =
|
||||||
|
testScope.runTest {
|
||||||
|
val padding by collectLastValue(underTest.padding)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(1f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo(defaultPadding)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(2f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo(defaultPadding * 2)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(.5f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo((defaultPadding * .5f).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
|
||||||
|
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
|
||||||
|
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.doze.util.BurnInHelperWrapper
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags
|
||||||
|
import com.android.systemui.flags.Flags
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.BurnInInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.UdfpsKeyguardInteractor
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/** Tests UdfpsFingerprintViewModel specific flows. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class UdfpsFingerprintViewModelTest : SysuiTestCase() {
|
||||||
|
private val defaultPadding = 12
|
||||||
|
private lateinit var underTest: FingerprintViewModel
|
||||||
|
|
||||||
|
private lateinit var testScope: TestScope
|
||||||
|
private lateinit var configRepository: FakeConfigurationRepository
|
||||||
|
private lateinit var bouncerRepository: KeyguardBouncerRepository
|
||||||
|
private lateinit var keyguardRepository: FakeKeyguardRepository
|
||||||
|
private lateinit var fakeCommandQueue: FakeCommandQueue
|
||||||
|
private lateinit var featureFlags: FakeFeatureFlags
|
||||||
|
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
|
||||||
|
|
||||||
|
@Mock private lateinit var burnInHelper: BurnInHelperWrapper
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
overrideResource(com.android.systemui.R.dimen.lock_icon_padding, defaultPadding)
|
||||||
|
testScope = TestScope()
|
||||||
|
configRepository = FakeConfigurationRepository()
|
||||||
|
keyguardRepository = FakeKeyguardRepository()
|
||||||
|
bouncerRepository = FakeKeyguardBouncerRepository()
|
||||||
|
fakeCommandQueue = FakeCommandQueue()
|
||||||
|
featureFlags =
|
||||||
|
FakeFeatureFlags().apply {
|
||||||
|
set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
|
||||||
|
set(Flags.FACE_AUTH_REFACTOR, false)
|
||||||
|
}
|
||||||
|
bouncerRepository = FakeKeyguardBouncerRepository()
|
||||||
|
transitionRepository = FakeKeyguardTransitionRepository()
|
||||||
|
val transitionInteractor =
|
||||||
|
KeyguardTransitionInteractor(
|
||||||
|
transitionRepository,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
val udfpsKeyguardInteractor =
|
||||||
|
UdfpsKeyguardInteractor(
|
||||||
|
configRepository,
|
||||||
|
BurnInInteractor(
|
||||||
|
context,
|
||||||
|
burnInHelper,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
configRepository,
|
||||||
|
FakeSystemClock(),
|
||||||
|
),
|
||||||
|
KeyguardInteractor(
|
||||||
|
keyguardRepository,
|
||||||
|
fakeCommandQueue,
|
||||||
|
featureFlags,
|
||||||
|
bouncerRepository,
|
||||||
|
configRepository,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
underTest =
|
||||||
|
FingerprintViewModel(
|
||||||
|
context,
|
||||||
|
transitionInteractor,
|
||||||
|
udfpsKeyguardInteractor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun paddingUpdates_onScaleForResolutionChanges() =
|
||||||
|
testScope.runTest {
|
||||||
|
val padding by collectLastValue(underTest.padding)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(1f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo(defaultPadding)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(2f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo(defaultPadding * 2)
|
||||||
|
|
||||||
|
configRepository.setScaleForResolution(.5f)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(padding).isEqualTo((defaultPadding * .5).toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,505 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.keyguard.ui.viewmodel
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.settingslib.Utils
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
|
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||||
|
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||||
|
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||||
|
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||||
|
import com.google.common.collect.Range
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/** Tests UDFPS lockscreen view model transitions. */
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class UdfpsLockscreenViewModelTest : SysuiTestCase() {
|
||||||
|
private val lockscreenColorResId = android.R.attr.textColorPrimary
|
||||||
|
private val alternateBouncerResId = com.android.internal.R.attr.materialColorOnPrimaryFixed
|
||||||
|
private val lockscreenColor = Utils.getColorAttrDefaultColor(context, lockscreenColorResId)
|
||||||
|
private val alternateBouncerColor =
|
||||||
|
Utils.getColorAttrDefaultColor(context, alternateBouncerResId)
|
||||||
|
|
||||||
|
private lateinit var underTest: UdfpsLockscreenViewModel
|
||||||
|
private lateinit var testScope: TestScope
|
||||||
|
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
testScope = TestScope()
|
||||||
|
transitionRepository = FakeKeyguardTransitionRepository()
|
||||||
|
val transitionInteractor =
|
||||||
|
KeyguardTransitionInteractor(
|
||||||
|
transitionRepository,
|
||||||
|
testScope.backgroundScope,
|
||||||
|
)
|
||||||
|
underTest =
|
||||||
|
UdfpsLockscreenViewModel(
|
||||||
|
context,
|
||||||
|
lockscreenColorResId,
|
||||||
|
alternateBouncerResId,
|
||||||
|
transitionInteractor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun goneToAodTransition() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: gone -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.GONE,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "goneToAodTransition",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: gone -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.GONE,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "goneToAodTransition",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: gone -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.GONE,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "goneToAodTransition",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockscreenToAod() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: lockscreen -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "lockscreenToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: lockscreen -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "lockscreenToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isIn(Range.closed(.39f, .41f))
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: lockscreen -> AOD
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "lockscreenToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aodToLockscreen() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: AOD -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.AOD,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "aodToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: AOD -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.AOD,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "aodToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isIn(Range.closed(.59f, .61f))
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: AOD -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.AOD,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "aodToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockscreenToAlternateBouncer() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: lockscreen -> alternate bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "lockscreenToAlternateBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: lockscreen -> alternate bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "lockscreenToAlternateBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: lockscreen -> alternate bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "lockscreenToAlternateBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun alternateBouncerToPrimaryBouncer() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: alternate bouncer -> primary bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.PRIMARY_BOUNCER,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "alternateBouncerToPrimaryBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: alternate bouncer -> primary bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.PRIMARY_BOUNCER,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "alternateBouncerToPrimaryBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isIn(Range.closed(.59f, .61f))
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: alternate bouncer -> primary bouncer
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.PRIMARY_BOUNCER,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "alternateBouncerToPrimaryBouncer",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun alternateBouncerToAod() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: alternate bouncer -> aod
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "alternateBouncerToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: alternate bouncer -> aod
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "alternateBouncerToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isIn(Range.closed(.39f, .41f))
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: alternate bouncer -> aod
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.ALTERNATE_BOUNCER,
|
||||||
|
to = KeyguardState.AOD,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "alternateBouncerToAod",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(alternateBouncerColor)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun lockscreenToOccluded() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: lockscreen -> occluded
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.OCCLUDED,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "lockscreenToOccluded",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: lockscreen -> occluded
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.OCCLUDED,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "lockscreenToOccluded",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isIn(Range.closed(.39f, .41f))
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: lockscreen -> occluded
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.LOCKSCREEN,
|
||||||
|
to = KeyguardState.OCCLUDED,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "lockscreenToOccluded",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(0f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun occludedToLockscreen() =
|
||||||
|
testScope.runTest {
|
||||||
|
val transition by collectLastValue(underTest.transition)
|
||||||
|
val visible by collectLastValue(underTest.visible)
|
||||||
|
|
||||||
|
// TransitionState.STARTED: occluded -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.OCCLUDED,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = 0f,
|
||||||
|
transitionState = TransitionState.STARTED,
|
||||||
|
ownerName = "occludedToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.RUNNING: occluded -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.OCCLUDED,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = .6f,
|
||||||
|
transitionState = TransitionState.RUNNING,
|
||||||
|
ownerName = "occludedToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
|
||||||
|
// TransitionState.FINISHED: occluded -> lockscreen
|
||||||
|
transitionRepository.sendTransitionStep(
|
||||||
|
TransitionStep(
|
||||||
|
from = KeyguardState.OCCLUDED,
|
||||||
|
to = KeyguardState.LOCKSCREEN,
|
||||||
|
value = 1f,
|
||||||
|
transitionState = TransitionState.FINISHED,
|
||||||
|
ownerName = "occludedToLockscreen",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
runCurrent()
|
||||||
|
assertThat(transition?.alpha).isEqualTo(1f)
|
||||||
|
assertThat(transition?.scale).isEqualTo(1f)
|
||||||
|
assertThat(transition?.color).isEqualTo(lockscreenColor)
|
||||||
|
assertThat(visible).isTrue()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user