• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.biometrics
18 
19 import android.annotation.DrawableRes
20 import android.content.Context
21 import android.content.res.Configuration
22 import android.graphics.drawable.Animatable2
23 import android.graphics.drawable.AnimatedVectorDrawable
24 import android.graphics.drawable.Drawable
25 import android.util.Log
26 import com.airbnb.lottie.LottieAnimationView
27 import com.airbnb.lottie.LottieCompositionFactory
28 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
29 
30 private const val TAG = "AuthIconController"
31 
32 /** Controller for animating the BiometricPrompt icon/affordance. */
33 abstract class AuthIconController(
34     protected val context: Context,
35     protected val iconView: LottieAnimationView
36 ) : Animatable2.AnimationCallback() {
37 
38     /** If this controller should ignore events and pause. */
39     var deactivated: Boolean = false
40 
41     /** If the icon view should be treated as an alternate "confirm" button. */
42     open val actsAsConfirmButton: Boolean = false
43 
onAnimationStartnull44     final override fun onAnimationStart(drawable: Drawable) {
45         super.onAnimationStart(drawable)
46     }
47 
onAnimationEndnull48     final override fun onAnimationEnd(drawable: Drawable) {
49         super.onAnimationEnd(drawable)
50 
51         if (!deactivated) {
52             handleAnimationEnd(drawable)
53         }
54     }
55 
56     /** Set the icon to a static image. */
showStaticDrawablenull57     protected fun showStaticDrawable(@DrawableRes iconRes: Int) {
58         iconView.setImageDrawable(context.getDrawable(iconRes))
59     }
60 
61     /** Animate a resource. */
animateIconOncenull62     protected fun animateIconOnce(@DrawableRes iconRes: Int) {
63         animateIcon(iconRes, false)
64     }
65 
66     /** Animate a resource. */
animateIconnull67     protected fun animateIcon(@DrawableRes iconRes: Int, repeat: Boolean) {
68         if (!deactivated) {
69             val icon = context.getDrawable(iconRes) as AnimatedVectorDrawable
70             iconView.setImageDrawable(icon)
71             icon.forceAnimationOnUI()
72             if (repeat) {
73                 icon.registerAnimationCallback(this)
74             }
75             icon.start()
76         }
77     }
78 
79     /** Update the icon to reflect the [newState]. */
updateStatenull80     fun updateState(@BiometricState lastState: Int, @BiometricState newState: Int) {
81         if (deactivated) {
82             Log.w(TAG, "Ignoring updateState when deactivated: $newState")
83         } else {
84             updateIcon(lastState, newState)
85         }
86     }
87 
88     /** If the icon should act as a "retry" button in the [currentState]. */
iconTapSendsRetryWhennull89     fun iconTapSendsRetryWhen(@BiometricState currentState: Int): Boolean = false
90 
91     /** Call during [updateState] if the controller is not [deactivated]. */
92     abstract fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int)
93 
94     /** Called during [onAnimationEnd] if the controller is not [deactivated]. */
95     open fun handleAnimationEnd(drawable: Drawable) {}
96 
onConfigurationChangednull97     open fun onConfigurationChanged(newConfig: Configuration) {}
98 
99     // TODO(b/251476085): Migrate this to an extension at the appropriate level?
100     /** Load the given [rawResources] immediately so they are cached for use in the [context]. */
cacheLottieAssetsInContextnull101     protected fun cacheLottieAssetsInContext(context: Context, vararg rawResources: Int) {
102         for (res in rawResources) {
103             LottieCompositionFactory.fromRawRes(context, res)
104         }
105     }
106 }
107