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 // mAlpha takes into consideration the status bar expansion amount and dialog suggested alpha 41 private int mAlpha; 42 boolean mPauseAuth; 43 UdfpsAnimationView(Context context, @Nullable AttributeSet attrs)44 public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) { 45 super(context, attrs); 46 } 47 48 /** 49 * Fingerprint drawable 50 */ getDrawable()51 abstract UdfpsDrawable getDrawable(); 52 onSensorRectUpdated(RectF bounds)53 void onSensorRectUpdated(RectF bounds) { 54 getDrawable().onSensorRectUpdated(bounds); 55 } 56 onDisplayConfiguring()57 void onDisplayConfiguring() { 58 getDrawable().setDisplayConfigured(true); 59 getDrawable().invalidateSelf(); 60 } 61 onDisplayUnconfigured()62 void onDisplayUnconfigured() { 63 getDrawable().setDisplayConfigured(false); 64 getDrawable().invalidateSelf(); 65 } 66 67 /** 68 * @return true if changed 69 */ setPauseAuth(boolean pauseAuth)70 boolean setPauseAuth(boolean pauseAuth) { 71 if (pauseAuth != mPauseAuth) { 72 mPauseAuth = pauseAuth; 73 updateAlpha(); 74 return true; 75 } 76 return false; 77 } 78 79 /** 80 * @return current alpha 81 */ updateAlpha()82 protected int updateAlpha() { 83 int alpha = calculateAlpha(); 84 getDrawable().setAlpha(alpha); 85 86 // this is necessary so that touches won't be intercepted if udfps is paused: 87 if (mPauseAuth && alpha == 0 && getParent() != null) { 88 ((ViewGroup) getParent()).setVisibility(View.INVISIBLE); 89 } else { 90 ((ViewGroup) getParent()).setVisibility(View.VISIBLE); 91 } 92 93 return alpha; 94 } 95 calculateAlpha()96 int calculateAlpha() { 97 int alpha = expansionToAlpha(mNotificationShadeExpansion); 98 alpha *= mDialogSuggestedAlpha; 99 mAlpha = alpha; 100 101 return mPauseAuth ? mAlpha : 255; 102 } 103 isPauseAuth()104 boolean isPauseAuth() { 105 return mPauseAuth; 106 } 107 expansionToAlpha(float expansion)108 private int expansionToAlpha(float expansion) { 109 // Fade to 0 opacity when reaching this expansion amount 110 final float maxExpansion = 0.4f; 111 112 if (expansion >= maxExpansion) { 113 return 0; // transparent 114 } 115 116 final float percent = expansion / maxExpansion; 117 return (int) ((1 - percent) * 255); 118 } 119 120 /** 121 * Converts coordinates of RectF relative to the screen to coordinates relative to this view. 122 * 123 * @param bounds RectF based off screen coordinates in current orientation 124 */ getBoundsRelativeToView(RectF bounds)125 RectF getBoundsRelativeToView(RectF bounds) { 126 int[] pos = getLocationOnScreen(); 127 128 RectF output = new RectF( 129 bounds.left - pos[0], 130 bounds.top - pos[1], 131 bounds.right - pos[0], 132 bounds.bottom - pos[1] 133 ); 134 135 return output; 136 } 137 138 /** 139 * Set the suggested alpha based on whether a dialog was recently shown or hidden. 140 * @param dialogSuggestedAlpha value from 0f to 1f. 141 */ setDialogSuggestedAlpha(float dialogSuggestedAlpha)142 public void setDialogSuggestedAlpha(float dialogSuggestedAlpha) { 143 mDialogSuggestedAlpha = dialogSuggestedAlpha; 144 updateAlpha(); 145 } 146 getDialogSuggestedAlpha()147 public float getDialogSuggestedAlpha() { 148 return mDialogSuggestedAlpha; 149 } 150 151 /** 152 * Sets the amount the notification shade is expanded. This will influence the opacity of the 153 * this visual affordance. 154 * @param expansion amount the shade has expanded from 0f to 1f. 155 */ onExpansionChanged(float expansion)156 public void onExpansionChanged(float expansion) { 157 mNotificationShadeExpansion = expansion; 158 updateAlpha(); 159 } 160 161 /** 162 * @return true if handled 163 */ dozeTimeTick()164 boolean dozeTimeTick() { 165 return false; 166 } 167 } 168