1 /* 2 * Copyright (C) 2021 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 static com.android.systemui.statusbar.StatusBarState.KEYGUARD; 20 21 import android.annotation.NonNull; 22 import android.content.res.Configuration; 23 import android.util.MathUtils; 24 import android.view.MotionEvent; 25 26 import com.android.keyguard.KeyguardUpdateMonitor; 27 import com.android.systemui.R; 28 import com.android.systemui.dump.DumpManager; 29 import com.android.systemui.keyguard.KeyguardViewMediator; 30 import com.android.systemui.plugins.statusbar.StatusBarStateController; 31 import com.android.systemui.statusbar.LockscreenShadeTransitionController; 32 import com.android.systemui.statusbar.StatusBarState; 33 import com.android.systemui.statusbar.phone.KeyguardBouncer; 34 import com.android.systemui.statusbar.phone.StatusBar; 35 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 36 import com.android.systemui.statusbar.policy.ConfigurationController; 37 import com.android.systemui.util.concurrency.DelayableExecutor; 38 39 import java.io.FileDescriptor; 40 import java.io.PrintWriter; 41 42 43 /** 44 * Class that coordinates non-HBM animations during keyguard authentication. 45 */ 46 public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> { 47 @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; 48 @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 49 @NonNull private final DelayableExecutor mExecutor; 50 @NonNull private final KeyguardViewMediator mKeyguardViewMediator; 51 @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController; 52 @NonNull private final ConfigurationController mConfigurationController; 53 @NonNull private final UdfpsController mUdfpsController; 54 55 private boolean mShowingUdfpsBouncer; 56 private boolean mUdfpsRequested; 57 private boolean mQsExpanded; 58 private boolean mFaceDetectRunning; 59 private int mStatusBarState; 60 private float mTransitionToFullShadeProgress; 61 private float mLastDozeAmount; 62 63 /** 64 * hidden amount of pin/pattern/password bouncer 65 * {@link KeyguardBouncer#EXPANSION_VISIBLE} (0f) to 66 * {@link KeyguardBouncer#EXPANSION_HIDDEN} (1f) 67 */ 68 private float mInputBouncerHiddenAmount; 69 private boolean mIsBouncerVisible; 70 UdfpsKeyguardViewController( @onNull UdfpsKeyguardView view, @NonNull StatusBarStateController statusBarStateController, @NonNull StatusBar statusBar, @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, @NonNull DelayableExecutor mainDelayableExecutor, @NonNull DumpManager dumpManager, @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull LockscreenShadeTransitionController transitionController, @NonNull ConfigurationController configurationController, @NonNull UdfpsController udfpsController)71 protected UdfpsKeyguardViewController( 72 @NonNull UdfpsKeyguardView view, 73 @NonNull StatusBarStateController statusBarStateController, 74 @NonNull StatusBar statusBar, 75 @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, 76 @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, 77 @NonNull DelayableExecutor mainDelayableExecutor, 78 @NonNull DumpManager dumpManager, 79 @NonNull KeyguardViewMediator keyguardViewMediator, 80 @NonNull LockscreenShadeTransitionController transitionController, 81 @NonNull ConfigurationController configurationController, 82 @NonNull UdfpsController udfpsController) { 83 super(view, statusBarStateController, statusBar, dumpManager); 84 mKeyguardViewManager = statusBarKeyguardViewManager; 85 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 86 mExecutor = mainDelayableExecutor; 87 mKeyguardViewMediator = keyguardViewMediator; 88 mLockScreenShadeTransitionController = transitionController; 89 mConfigurationController = configurationController; 90 mUdfpsController = udfpsController; 91 } 92 93 @Override getTag()94 @NonNull String getTag() { 95 return "UdfpsKeyguardViewController"; 96 } 97 98 @Override onViewAttached()99 protected void onViewAttached() { 100 super.onViewAttached(); 101 final float dozeAmount = mStatusBarStateController.getDozeAmount(); 102 mLastDozeAmount = dozeAmount; 103 mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount); 104 mStatusBarStateController.addCallback(mStateListener); 105 106 mUdfpsRequested = false; 107 108 mStatusBarState = mStatusBarStateController.getState(); 109 mQsExpanded = mKeyguardViewManager.isQsExpanded(); 110 mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN; 111 mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing(); 112 mConfigurationController.addCallback(mConfigurationListener); 113 updateAlpha(); 114 updatePauseAuth(); 115 116 mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); 117 mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this); 118 } 119 120 @Override onViewDetached()121 protected void onViewDetached() { 122 super.onViewDetached(); 123 mFaceDetectRunning = false; 124 125 mStatusBarStateController.removeCallback(mStateListener); 126 mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor); 127 mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false); 128 mConfigurationController.removeCallback(mConfigurationListener); 129 if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) { 130 mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null); 131 } 132 } 133 134 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)135 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 136 super.dump(fd, pw, args); 137 pw.println("mShowingUdfpsBouncer=" + mShowingUdfpsBouncer); 138 pw.println("mFaceDetectRunning=" + mFaceDetectRunning); 139 pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState)); 140 pw.println("mQsExpanded=" + mQsExpanded); 141 pw.println("mIsBouncerVisible=" + mIsBouncerVisible); 142 pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount); 143 pw.println("mAlpha=" + mView.getAlpha()); 144 pw.println("mUdfpsRequested=" + mUdfpsRequested); 145 pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested); 146 } 147 148 /** 149 * Overrides non-bouncer show logic in shouldPauseAuth to still show icon. 150 * @return whether the udfpsBouncer has been newly shown or hidden 151 */ showUdfpsBouncer(boolean show)152 private boolean showUdfpsBouncer(boolean show) { 153 if (mShowingUdfpsBouncer == show) { 154 return false; 155 } 156 157 mShowingUdfpsBouncer = show; 158 updatePauseAuth(); 159 if (mShowingUdfpsBouncer) { 160 if (mStatusBarState == StatusBarState.SHADE_LOCKED) { 161 mView.animateInUdfpsBouncer(null); 162 } 163 164 if (mKeyguardViewManager.isOccluded()) { 165 mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true); 166 } 167 168 mView.announceForAccessibility(mView.getContext().getString( 169 R.string.accessibility_fingerprint_bouncer)); 170 } else { 171 mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false); 172 } 173 return true; 174 } 175 176 /** 177 * Returns true if the fingerprint manager is running but we want to temporarily pause 178 * authentication. On the keyguard, we may want to show udfps when the shade 179 * is expanded, so this can be overridden with the showBouncer method. 180 */ shouldPauseAuth()181 public boolean shouldPauseAuth() { 182 if (mShowingUdfpsBouncer) { 183 return false; 184 } 185 186 if (mUdfpsRequested && !mNotificationShadeExpanded 187 && (!mIsBouncerVisible 188 || mInputBouncerHiddenAmount != KeyguardBouncer.EXPANSION_VISIBLE)) { 189 return false; 190 } 191 192 if (mStatusBarState != KEYGUARD) { 193 return true; 194 } 195 196 if (mQsExpanded) { 197 return true; 198 } 199 200 if (mInputBouncerHiddenAmount < .5f || mIsBouncerVisible) { 201 return true; 202 } 203 204 return false; 205 } 206 207 @Override listenForTouchesOutsideView()208 public boolean listenForTouchesOutsideView() { 209 return true; 210 } 211 212 @Override onTouchOutsideView()213 public void onTouchOutsideView() { 214 maybeShowInputBouncer(); 215 } 216 217 /** 218 * If we were previously showing the udfps bouncer, hide it and instead show the regular 219 * (pin/pattern/password) bouncer. 220 * 221 * Does nothing if we weren't previously showing the udfps bouncer. 222 */ maybeShowInputBouncer()223 private void maybeShowInputBouncer() { 224 if (mShowingUdfpsBouncer) { 225 mKeyguardViewManager.showBouncer(true); 226 mKeyguardViewManager.resetAlternateAuth(false); 227 } 228 } 229 230 /** 231 * Set the progress we're currently transitioning to the full shade. 0.0f means we're not 232 * transitioning yet, while 1.0f means we've fully dragged down. 233 */ setTransitionToFullShadeProgress(float progress)234 public void setTransitionToFullShadeProgress(float progress) { 235 mTransitionToFullShadeProgress = progress; 236 updateAlpha(); 237 } 238 updateAlpha()239 private void updateAlpha() { 240 // fade icon on transition to showing bouncer 241 int alpha = mShowingUdfpsBouncer ? 255 242 : (int) MathUtils.constrain( 243 MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount), 244 0f, 255f); 245 alpha *= (1.0f - mTransitionToFullShadeProgress); 246 mView.setUnpausedAlpha(alpha); 247 } 248 249 private final StatusBarStateController.StateListener mStateListener = 250 new StatusBarStateController.StateListener() { 251 @Override 252 public void onDozeAmountChanged(float linear, float eased) { 253 if (mLastDozeAmount < linear) { 254 showUdfpsBouncer(false); 255 } 256 mView.onDozeAmountChanged(linear, eased); 257 mLastDozeAmount = linear; 258 updatePauseAuth(); 259 } 260 261 @Override 262 public void onStateChanged(int statusBarState) { 263 mStatusBarState = statusBarState; 264 mView.setStatusBarState(statusBarState); 265 updatePauseAuth(); 266 } 267 }; 268 269 private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor = 270 new StatusBarKeyguardViewManager.AlternateAuthInterceptor() { 271 @Override 272 public boolean showAlternateAuthBouncer() { 273 return showUdfpsBouncer(true); 274 } 275 276 @Override 277 public boolean hideAlternateAuthBouncer() { 278 return showUdfpsBouncer(false); 279 } 280 281 @Override 282 public boolean isShowingAlternateAuthBouncer() { 283 return mShowingUdfpsBouncer; 284 } 285 286 @Override 287 public void requestUdfps(boolean request, int color) { 288 mUdfpsRequested = request; 289 mView.requestUdfps(request, color); 290 updatePauseAuth(); 291 } 292 293 @Override 294 public boolean isAnimating() { 295 return false; 296 } 297 298 @Override 299 public void setQsExpanded(boolean expanded) { 300 mQsExpanded = expanded; 301 updatePauseAuth(); 302 } 303 304 @Override 305 public boolean onTouch(MotionEvent event) { 306 if (mTransitionToFullShadeProgress != 0) { 307 return false; 308 } 309 return mUdfpsController.onTouch(event); 310 } 311 312 @Override 313 public void setBouncerExpansionChanged(float expansion) { 314 mInputBouncerHiddenAmount = expansion; 315 updateAlpha(); 316 updatePauseAuth(); 317 } 318 319 @Override 320 public void onBouncerVisibilityChanged() { 321 mIsBouncerVisible = mKeyguardViewManager.isBouncerShowing(); 322 if (!mIsBouncerVisible) { 323 mInputBouncerHiddenAmount = 1f; 324 } else if (mKeyguardViewManager.isBouncerShowing()) { 325 mInputBouncerHiddenAmount = 0f; 326 } 327 updateAlpha(); 328 updatePauseAuth(); 329 } 330 331 @Override 332 public void dump(PrintWriter pw) { 333 pw.println(getTag()); 334 } 335 }; 336 337 private final ConfigurationController.ConfigurationListener mConfigurationListener = 338 new ConfigurationController.ConfigurationListener() { 339 @Override 340 public void onUiModeChanged() { 341 mView.updateColor(); 342 } 343 344 @Override 345 public void onThemeChanged() { 346 mView.updateColor(); 347 } 348 349 @Override 350 public void onOverlayChanged() { 351 mView.updateColor(); 352 } 353 354 @Override 355 public void onConfigChanged(Configuration newConfig) { 356 mView.updateColor(); 357 } 358 }; 359 } 360