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 android.annotation.Nullable; 20 import android.content.Context; 21 import android.graphics.RectF; 22 import android.util.AttributeSet; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.FrameLayout; 26 27 /** 28 * Base class for views containing UDFPS animations. Note that this is a FrameLayout so that we 29 * can support multiple child views drawing in the same region around the sensor location. 30 * 31 * - hides animation view when pausing auth 32 * - sends illumination events to fingerprint drawable 33 * - sends sensor rect updates to fingerprint drawable 34 * - optionally can override dozeTimeTick to adjust views for burn-in mitigation 35 */ 36 public abstract class UdfpsAnimationView extends FrameLayout { 37 private float mDialogSuggestedAlpha = 1f; 38 private float mNotificationShadeExpansion = 0f; 39 40 // Used for Udfps ellipse detection when flag is true, set by AnimationViewController 41 boolean mUseExpandedOverlay = false; 42 43 // mAlpha takes into consideration the status bar expansion amount and dialog suggested alpha 44 private int mAlpha; 45 boolean mPauseAuth; 46 UdfpsAnimationView(Context context, @Nullable AttributeSet attrs)47 public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) { 48 super(context, attrs); 49 } 50 51 /** 52 * Fingerprint drawable 53 */ getDrawable()54 abstract UdfpsDrawable getDrawable(); 55 onSensorRectUpdated(RectF bounds)56 void onSensorRectUpdated(RectF bounds) { 57 getDrawable().onSensorRectUpdated(bounds); 58 } 59 onDisplayConfiguring()60 void onDisplayConfiguring() { 61 getDrawable().setDisplayConfigured(true); 62 getDrawable().invalidateSelf(); 63 } 64 onDisplayUnconfigured()65 void onDisplayUnconfigured() { 66 getDrawable().setDisplayConfigured(false); 67 getDrawable().invalidateSelf(); 68 } 69 70 /** 71 * @return true if changed 72 */ setPauseAuth(boolean pauseAuth)73 boolean setPauseAuth(boolean pauseAuth) { 74 if (pauseAuth != mPauseAuth) { 75 mPauseAuth = pauseAuth; 76 updateAlpha(); 77 return true; 78 } 79 return false; 80 } 81 82 /** 83 * @return current alpha 84 */ updateAlpha()85 protected int updateAlpha() { 86 int alpha = calculateAlpha(); 87 getDrawable().setAlpha(alpha); 88 89 // this is necessary so that touches won't be intercepted if udfps is paused: 90 if (mPauseAuth && alpha == 0 && getParent() != null) { 91 ((ViewGroup) getParent()).setVisibility(View.INVISIBLE); 92 } else { 93 ((ViewGroup) getParent()).setVisibility(View.VISIBLE); 94 } 95 96 return alpha; 97 } 98 calculateAlpha()99 int calculateAlpha() { 100 int alpha = expansionToAlpha(mNotificationShadeExpansion); 101 alpha *= mDialogSuggestedAlpha; 102 mAlpha = alpha; 103 104 return mPauseAuth ? mAlpha : 255; 105 } 106 isPauseAuth()107 boolean isPauseAuth() { 108 return mPauseAuth; 109 } 110 expansionToAlpha(float expansion)111 private int expansionToAlpha(float expansion) { 112 // Fade to 0 opacity when reaching this expansion amount 113 final float maxExpansion = 0.4f; 114 115 if (expansion >= maxExpansion) { 116 return 0; // transparent 117 } 118 119 final float percent = expansion / maxExpansion; 120 return (int) ((1 - percent) * 255); 121 } 122 123 /** 124 * Converts coordinates of RectF relative to the screen to coordinates relative to this view. 125 * 126 * @param bounds RectF based off screen coordinates in current orientation 127 */ getBoundsRelativeToView(RectF bounds)128 RectF getBoundsRelativeToView(RectF bounds) { 129 int[] pos = getLocationOnScreen(); 130 131 RectF output = new RectF( 132 bounds.left - pos[0], 133 bounds.top - pos[1], 134 bounds.right - pos[0], 135 bounds.bottom - pos[1] 136 ); 137 138 return output; 139 } 140 141 /** 142 * Set the suggested alpha based on whether a dialog was recently shown or hidden. 143 * @param dialogSuggestedAlpha value from 0f to 1f. 144 */ setDialogSuggestedAlpha(float dialogSuggestedAlpha)145 public void setDialogSuggestedAlpha(float dialogSuggestedAlpha) { 146 mDialogSuggestedAlpha = dialogSuggestedAlpha; 147 updateAlpha(); 148 } 149 getDialogSuggestedAlpha()150 public float getDialogSuggestedAlpha() { 151 return mDialogSuggestedAlpha; 152 } 153 154 /** 155 * Sets the amount the notification shade is expanded. This will influence the opacity of the 156 * this visual affordance. 157 * @param expansion amount the shade has expanded from 0f to 1f. 158 */ onExpansionChanged(float expansion)159 public void onExpansionChanged(float expansion) { 160 mNotificationShadeExpansion = expansion; 161 updateAlpha(); 162 } 163 164 /** 165 * @return true if handled 166 */ dozeTimeTick()167 boolean dozeTimeTick() { 168 return false; 169 } 170 } 171