blob: ecfc45bb11829a1c10590ed7bb3ab925280291b5 [file] [log] [blame]
Jorim Jaggi27267d62015-04-28 13:27:12 -07001/*
2 * Copyright (C) 2015 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
17package com.android.systemui.statusbar.phone;
18
Lucas Dupin2e838ac2019-04-17 16:50:58 -070019import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
20
Amin Shaikh5877c022019-05-24 10:26:05 -040021import android.annotation.IntDef;
Jorim Jaggi27267d62015-04-28 13:27:12 -070022import android.content.Context;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070023import android.content.res.ColorStateList;
Selim Cinek6ebba592016-05-31 15:28:28 -070024import android.content.res.Configuration;
Lucas Dupinc9e5d762019-01-28 09:34:30 -080025import android.content.res.TypedArray;
Lucas Dupinc90a6bf2018-10-10 13:53:20 -070026import android.graphics.Color;
Lucas Dupinf3b26292019-03-14 16:06:22 -070027import android.graphics.drawable.Animatable2;
Jorim Jaggi27267d62015-04-28 13:27:12 -070028import android.graphics.drawable.AnimatedVectorDrawable;
29import android.graphics.drawable.Drawable;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070030import android.hardware.biometrics.BiometricSourceType;
Ianaee1b2a2019-05-10 16:48:22 -070031import android.os.Trace;
Amin Shaikh5877c022019-05-24 10:26:05 -040032import android.provider.Settings;
33import android.text.TextUtils;
Jorim Jaggi27267d62015-04-28 13:27:12 -070034import android.util.AttributeSet;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070035import android.view.ViewGroup;
Lucas Dupinad2577e2019-06-25 19:52:26 -070036import android.view.ViewTreeObserver;
Selim Cinekc99d9a952015-06-19 18:44:50 -070037import android.view.accessibility.AccessibilityNodeInfo;
Jorim Jaggi27267d62015-04-28 13:27:12 -070038
Lucas Dupind7221352019-04-29 19:43:11 -070039import androidx.annotation.Nullable;
40
Lucas Dupinc90a6bf2018-10-10 13:53:20 -070041import com.android.internal.graphics.ColorUtils;
Lucas Dupinda069d72019-05-04 11:29:47 -070042import com.android.internal.telephony.IccCardConstants;
Jorim Jaggi27267d62015-04-28 13:27:12 -070043import com.android.keyguard.KeyguardUpdateMonitor;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070044import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupinad2577e2019-06-25 19:52:26 -070045import com.android.systemui.Interpolators;
Jorim Jaggi27267d62015-04-28 13:27:12 -070046import com.android.systemui.R;
Lucas Dupind7221352019-04-29 19:43:11 -070047import com.android.systemui.dock.DockManager;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070048import com.android.systemui.plugins.statusbar.StatusBarStateController;
Jorim Jaggi27267d62015-04-28 13:27:12 -070049import com.android.systemui.statusbar.KeyguardAffordanceView;
Selim Cinek820ba2d2019-06-18 18:59:09 -070050import com.android.systemui.statusbar.StatusBarState;
51import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
Lucas Dupincdbb1cb2019-05-16 19:48:30 -070052import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
Jorim Jaggi27267d62015-04-28 13:27:12 -070053import com.android.systemui.statusbar.policy.AccessibilityController;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070054import com.android.systemui.statusbar.policy.ConfigurationController;
Lucas Dupin1cad65e2019-05-15 13:47:05 -070055import com.android.systemui.statusbar.policy.KeyguardMonitor;
Selim Cinek60ee7fd2019-06-26 13:06:00 -070056import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
Zachary Iqbalf50284c2017-01-22 18:54:46 -080057import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
Jorim Jaggi27267d62015-04-28 13:27:12 -070058
Amin Shaikh5877c022019-05-24 10:26:05 -040059import java.lang.annotation.Retention;
60import java.lang.annotation.RetentionPolicy;
61
Lucas Dupin2e838ac2019-04-17 16:50:58 -070062import javax.inject.Inject;
63import javax.inject.Named;
64
Jorim Jaggi27267d62015-04-28 13:27:12 -070065/**
66 * Manages the different states and animations of the unlock icon.
67 */
Lucas Dupin2e838ac2019-04-17 16:50:58 -070068public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChangedListener,
69 StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
Selim Cinek820ba2d2019-06-18 18:59:09 -070070 UnlockMethodCache.OnUnlockMethodChangedListener,
Selim Cinek60ee7fd2019-06-26 13:06:00 -070071 NotificationWakeUpCoordinator.WakeUpListener, ViewTreeObserver.OnPreDrawListener,
72 OnHeadsUpChangedListener {
Jorim Jaggi27267d62015-04-28 13:27:12 -070073
Jorim Jaggi27267d62015-04-28 13:27:12 -070074 private static final int STATE_LOCKED = 0;
75 private static final int STATE_LOCK_OPEN = 1;
Lucas Dupinc2d11b32019-03-06 16:02:18 -080076 private static final int STATE_SCANNING_FACE = 2;
77 private static final int STATE_BIOMETRICS_ERROR = 3;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070078 private final ConfigurationController mConfigurationController;
79 private final StatusBarStateController mStatusBarStateController;
80 private final UnlockMethodCache mUnlockMethodCache;
81 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
82 private final AccessibilityController mAccessibilityController;
Lucas Dupind7221352019-04-29 19:43:11 -070083 private final DockManager mDockManager;
Lucas Dupin1cad65e2019-05-15 13:47:05 -070084 private final KeyguardMonitor mKeyguardMonitor;
Selim Cinek820ba2d2019-06-18 18:59:09 -070085 private final KeyguardBypassController mBypassController;
86 private final NotificationWakeUpCoordinator mWakeUpCoordinator;
Selim Cinek60ee7fd2019-06-26 13:06:00 -070087 private final HeadsUpManagerPhone mHeadsUpManager;
Jorim Jaggi27267d62015-04-28 13:27:12 -070088
89 private int mLastState = 0;
Lucas Dupinad2577e2019-06-25 19:52:26 -070090 private boolean mForceUpdate;
Lucas Dupinc9e5d762019-01-28 09:34:30 -080091 private boolean mTransientBiometricsError;
Lucas Dupinc9e5d762019-01-28 09:34:30 -080092 private boolean mIsFaceUnlockState;
Lucas Dupinda069d72019-05-04 11:29:47 -070093 private boolean mSimLocked;
Selim Cinek6ebba592016-05-31 15:28:28 -070094 private int mDensity;
Lucas Dupinf22194f2018-12-26 11:43:57 -080095 private boolean mPulsing;
96 private boolean mDozing;
Lucas Dupind7221352019-04-29 19:43:11 -070097 private boolean mDocked;
Selim Cinek390f1b92019-06-28 18:07:28 -070098 private boolean mBlockUpdates;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070099 private int mIconColor;
Lucas Dupind7221352019-04-29 19:43:11 -0700100 private float mDozeAmount;
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700101 private boolean mBouncerShowingScrimmed;
Lucas Dupin71f38042019-05-10 16:23:04 -0700102 private boolean mWakeAndUnlockRunning;
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700103 private boolean mKeyguardShowing;
Lucas Dupin23964c72019-05-21 16:12:45 -0700104 private boolean mShowingLaunchAffordance;
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700105 private boolean mKeyguardJustShown;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700106 private boolean mUpdatePending;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700107
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700108 private final KeyguardMonitor.Callback mKeyguardMonitorCallback =
109 new KeyguardMonitor.Callback() {
110 @Override
111 public void onKeyguardShowingChanged() {
Selim Cinek390f1b92019-06-28 18:07:28 -0700112 boolean force = false;
113 boolean wasShowing = mKeyguardShowing;
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700114 mKeyguardShowing = mKeyguardMonitor.isShowing();
Selim Cinek390f1b92019-06-28 18:07:28 -0700115 if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
116 mBlockUpdates = false;
117 force = true;
118 }
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700119 if (!wasShowing && mKeyguardShowing) {
120 mKeyguardJustShown = true;
121 }
Selim Cinek390f1b92019-06-28 18:07:28 -0700122 update(force);
123 }
124
125 @Override
126 public void onKeyguardFadingAwayChanged() {
127 if (!mKeyguardMonitor.isKeyguardFadingAway() && mBlockUpdates) {
128 mBlockUpdates = false;
129 update(true /* force */);
130 }
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700131 }
132 };
Lucas Dupind7221352019-04-29 19:43:11 -0700133 private final DockManager.DockEventListener mDockEventListener =
134 new DockManager.DockEventListener() {
135 @Override
136 public void onEvent(int event) {
137 boolean docked = event == DockManager.STATE_DOCKED
138 || event == DockManager.STATE_DOCKED_HIDE;
139 if (docked != mDocked) {
140 mDocked = docked;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700141 update();
Lucas Dupind7221352019-04-29 19:43:11 -0700142 }
143 }
144 };
Jorim Jaggi8dea48c2016-11-28 14:47:45 +0100145
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700146 private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
147 new KeyguardUpdateMonitorCallback() {
148 @Override
Lucas Dupinda069d72019-05-04 11:29:47 -0700149 public void onSimStateChanged(int subId, int slotId,
150 IccCardConstants.State simState) {
Lucas Dupinda069d72019-05-04 11:29:47 -0700151 mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
Lucas Dupinad2577e2019-06-25 19:52:26 -0700152 update();
Lucas Dupinda069d72019-05-04 11:29:47 -0700153 }
154
155 @Override
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700156 public void onKeyguardVisibilityChanged(boolean showing) {
157 update();
158 }
159
160 @Override
161 public void onBiometricRunningStateChanged(boolean running,
162 BiometricSourceType biometricSourceType) {
163 update();
164 }
165
166 @Override
167 public void onStrongAuthStateChanged(int userId) {
168 update();
169 }
170 };
171
172 @Inject
173 public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
174 StatusBarStateController statusBarStateController,
175 ConfigurationController configurationController,
Lucas Dupind7221352019-04-29 19:43:11 -0700176 AccessibilityController accessibilityController,
Selim Cinek820ba2d2019-06-18 18:59:09 -0700177 KeyguardBypassController bypassController,
178 NotificationWakeUpCoordinator wakeUpCoordinator,
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700179 KeyguardMonitor keyguardMonitor,
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700180 @Nullable DockManager dockManager,
181 HeadsUpManagerPhone headsUpManager) {
Jorim Jaggi27267d62015-04-28 13:27:12 -0700182 super(context, attrs);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700183 mContext = context;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700184 mUnlockMethodCache = UnlockMethodCache.getInstance(context);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700185 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
186 mAccessibilityController = accessibilityController;
187 mConfigurationController = configurationController;
188 mStatusBarStateController = statusBarStateController;
Selim Cinek820ba2d2019-06-18 18:59:09 -0700189 mBypassController = bypassController;
190 mWakeUpCoordinator = wakeUpCoordinator;
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700191 mKeyguardMonitor = keyguardMonitor;
Lucas Dupind7221352019-04-29 19:43:11 -0700192 mDockManager = dockManager;
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700193 mHeadsUpManager = headsUpManager;
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700194 }
195
196 @Override
197 protected void onAttachedToWindow() {
198 super.onAttachedToWindow();
199 mStatusBarStateController.addCallback(this);
200 mConfigurationController.addCallback(this);
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700201 mKeyguardMonitor.addCallback(mKeyguardMonitorCallback);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700202 mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
203 mUnlockMethodCache.addListener(this);
Selim Cinek820ba2d2019-06-18 18:59:09 -0700204 mWakeUpCoordinator.addListener(this);
Lucas Dupinda069d72019-05-04 11:29:47 -0700205 mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
Lucas Dupind7221352019-04-29 19:43:11 -0700206 if (mDockManager != null) {
207 mDockManager.addListener(mDockEventListener);
208 }
Lucas Dupin12dab902019-04-19 11:10:48 -0700209 onThemeChanged();
Lucas Dupinad2577e2019-06-25 19:52:26 -0700210 update();
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700211 }
212
213 @Override
214 protected void onDetachedFromWindow() {
215 super.onDetachedFromWindow();
216 mStatusBarStateController.removeCallback(this);
217 mConfigurationController.removeCallback(this);
218 mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
Lucas Dupin1cad65e2019-05-15 13:47:05 -0700219 mKeyguardMonitor.removeCallback(mKeyguardMonitorCallback);
Selim Cinek8ee02b12019-07-22 14:49:18 -0700220 mWakeUpCoordinator.removeListener(this);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700221 mUnlockMethodCache.removeListener(this);
Lucas Dupind7221352019-04-29 19:43:11 -0700222 if (mDockManager != null) {
223 mDockManager.removeListener(mDockEventListener);
224 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700225 }
226
227 @Override
228 public void onThemeChanged() {
229 TypedArray typedArray = mContext.getTheme().obtainStyledAttributes(
230 null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
231 mIconColor = typedArray.getColor(0, Color.WHITE);
232 typedArray.recycle();
233 updateDarkTint();
Jorim Jaggi27267d62015-04-28 13:27:12 -0700234 }
235
236 @Override
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800237 public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800238 update();
239 }
240
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800241 /**
242 * If we're currently presenting an authentication error message.
243 */
244 public void setTransientBiometricsError(boolean transientBiometricsError) {
245 mTransientBiometricsError = transientBiometricsError;
Jorim Jaggi864e64b2015-05-20 14:13:23 -0700246 update();
247 }
248
Selim Cinek6ebba592016-05-31 15:28:28 -0700249 @Override
250 protected void onConfigurationChanged(Configuration newConfig) {
251 super.onConfigurationChanged(newConfig);
252 final int density = newConfig.densityDpi;
253 if (density != mDensity) {
254 mDensity = density;
Selim Cinek6ebba592016-05-31 15:28:28 -0700255 update();
256 }
257 }
258
Jorim Jaggi27267d62015-04-28 13:27:12 -0700259 public void update() {
Selim Cinek6ebba592016-05-31 15:28:28 -0700260 update(false /* force */);
261 }
262
263 public void update(boolean force) {
Lucas Dupinad2577e2019-06-25 19:52:26 -0700264 if (force) {
265 mForceUpdate = true;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700266 }
Lucas Dupinad2577e2019-06-25 19:52:26 -0700267 if (!mUpdatePending) {
268 mUpdatePending = true;
269 getViewTreeObserver().addOnPreDrawListener(this);
270 }
271 }
272
273 @Override
274 public boolean onPreDraw() {
275 mUpdatePending = false;
276 getViewTreeObserver().removeOnPreDrawListener(this);
277
278 int state = getState();
279 int lastState = mLastState;
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700280 boolean keyguardJustShown = mKeyguardJustShown;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700281 mIsFaceUnlockState = state == STATE_SCANNING_FACE;
282 mLastState = state;
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700283 mKeyguardJustShown = false;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700284
Selim Cinek390f1b92019-06-28 18:07:28 -0700285 boolean shouldUpdate = lastState != state || mForceUpdate;
286 if (mBlockUpdates && canBlockUpdates()) {
287 shouldUpdate = false;
288 }
289 if (shouldUpdate) {
Lucas Dupinad2577e2019-06-25 19:52:26 -0700290 mForceUpdate = false;
291 @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700292 state, mPulsing, mDozing, keyguardJustShown);
Lucas Dupinad2577e2019-06-25 19:52:26 -0700293 boolean isAnim = lockAnimIndex != -1;
294 int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
295
296 Drawable icon = mContext.getDrawable(iconRes);
297 final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
298 ? (AnimatedVectorDrawable) icon
299 : null;
300 setImageDrawable(icon, false);
301 if (mIsFaceUnlockState) {
302 announceForAccessibility(getContext().getString(
303 R.string.accessibility_scanning_face));
304 }
305
306 if (animation != null && isAnim) {
307 animation.forceAnimationOnUI();
308 animation.clearAnimationCallbacks();
309 animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
310 @Override
311 public void onAnimationEnd(Drawable drawable) {
312 if (getDrawable() == animation && state == getState()
313 && doesAnimationLoop(lockAnimIndex)) {
314 animation.start();
315 } else {
316 Trace.endAsyncSection("LockIcon#Animation", state);
317 }
318 }
319 });
320 Trace.beginAsyncSection("LockIcon#Animation", state);
321 animation.start();
322 }
323 }
324 updateDarkTint();
Jorim Jaggi27267d62015-04-28 13:27:12 -0700325
Selim Cineka678b0e2019-07-23 13:12:55 -0700326 updateIconVisibility();
327 updateClickability();
328
329 return true;
330 }
331
332 /**
333 * Update the icon visibility
334 * @return true if the visibility changed
335 */
336 private boolean updateIconVisibility() {
Lucas Dupin71f38042019-05-10 16:23:04 -0700337 boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
Lucas Dupin23964c72019-05-21 16:12:45 -0700338 boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
339 || mShowingLaunchAffordance;
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700340 if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
Selim Cinek5bc77a12019-07-26 22:25:49 -0700341 if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
342 || mStatusBarStateController.getState() == StatusBarState.KEYGUARD)
Selim Cineka678b0e2019-07-23 13:12:55 -0700343 && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700344 invisible = true;
345 }
Selim Cinek820ba2d2019-06-18 18:59:09 -0700346 }
Lucas Dupinad2577e2019-06-25 19:52:26 -0700347 boolean wasInvisible = getVisibility() == INVISIBLE;
348 if (invisible != wasInvisible) {
349 setVisibility(invisible ? INVISIBLE : VISIBLE);
350 animate().cancel();
351 if (!invisible) {
352 setScaleX(0);
353 setScaleY(0);
354 animate()
355 .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
356 .scaleX(1)
357 .scaleY(1)
358 .withLayer()
359 .setDuration(233)
360 .start();
361 }
Selim Cineka678b0e2019-07-23 13:12:55 -0700362 return true;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700363 }
Selim Cineka678b0e2019-07-23 13:12:55 -0700364 return false;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700365 }
366
Selim Cinek390f1b92019-06-28 18:07:28 -0700367 private boolean canBlockUpdates() {
368 return mKeyguardShowing || mKeyguardMonitor.isKeyguardFadingAway();
369 }
370
Jorim Jaggi27267d62015-04-28 13:27:12 -0700371 private void updateClickability() {
372 if (mAccessibilityController == null) {
373 return;
374 }
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800375 boolean canLock = mUnlockMethodCache.isMethodSecure()
376 && mUnlockMethodCache.canSkipBouncer();
Adrian Roosa94e9642017-08-17 17:29:19 +0200377 boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700378 setClickable(clickToUnlock);
379 setLongClickable(canLock && !clickToUnlock);
Jorim Jaggi27267d62015-04-28 13:27:12 -0700380 setFocusable(mAccessibilityController.isAccessibilityEnabled());
381 }
382
Selim Cinekc99d9a952015-06-19 18:44:50 -0700383 @Override
384 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
385 super.onInitializeAccessibilityNodeInfo(info);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700386 boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
387 boolean unlockingAllowed = mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed();
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800388 if (fingerprintRunning && unlockingAllowed) {
Selim Cinekc99d9a952015-06-19 18:44:50 -0700389 AccessibilityNodeInfo.AccessibilityAction unlock
390 = new AccessibilityNodeInfo.AccessibilityAction(
391 AccessibilityNodeInfo.ACTION_CLICK,
392 getContext().getString(R.string.accessibility_unlock_without_fingerprint));
393 info.addAction(unlock);
Selim Cinek947c77c2017-03-23 14:20:32 -0700394 info.setHintText(getContext().getString(
395 R.string.accessibility_waiting_for_fingerprint));
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800396 } else if (mIsFaceUnlockState) {
Bingyu Zhangbfe6dcf2018-04-25 10:20:36 -0700397 //Avoid 'button' to be spoken for scanning face
398 info.setClassName(LockIcon.class.getName());
399 info.setContentDescription(getContext().getString(
400 R.string.accessibility_scanning_face));
Selim Cinekc99d9a952015-06-19 18:44:50 -0700401 }
402 }
403
Lucas Dupin1aec88f2019-05-01 22:25:22 -0700404 private int getIconForState(int state) {
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800405 int iconRes;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700406 switch (state) {
407 case STATE_LOCKED:
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800408 // Scanning animation is a pulsing padlock. This means that the resting state is
409 // just a padlock.
410 case STATE_SCANNING_FACE:
411 // Error animation also starts and ands on the padlock.
412 case STATE_BIOMETRICS_ERROR:
Lucas Dupince56d3b2019-03-07 13:02:25 -0800413 iconRes = com.android.internal.R.drawable.ic_lock;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800414 break;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700415 case STATE_LOCK_OPEN:
Lucas Dupince56d3b2019-03-07 13:02:25 -0800416 iconRes = com.android.internal.R.drawable.ic_lock_open;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800417 break;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700418 default:
419 throw new IllegalArgumentException();
420 }
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800421
Lucas Dupin1aec88f2019-05-01 22:25:22 -0700422 return iconRes;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700423 }
424
Amin Shaikh5877c022019-05-24 10:26:05 -0400425 private boolean doesAnimationLoop(@LockAnimIndex int lockAnimIndex) {
426 return lockAnimIndex == SCANNING;
Lucas Dupinf3b26292019-03-14 16:06:22 -0700427 }
428
Lucas Dupinad2577e2019-06-25 19:52:26 -0700429 private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700430 boolean dozing, boolean keyguardJustShown) {
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800431
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800432 // Never animate when screen is off
Lucas Dupinad2577e2019-06-25 19:52:26 -0700433 if (dozing && !pulsing) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800434 return -1;
435 }
436
Lucas Dupinad2577e2019-06-25 19:52:26 -0700437 if (newState == STATE_BIOMETRICS_ERROR) {
Amin Shaikh5877c022019-05-24 10:26:05 -0400438 return ERROR;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700439 } else if (oldState != STATE_LOCK_OPEN && newState == STATE_LOCK_OPEN) {
Amin Shaikh5877c022019-05-24 10:26:05 -0400440 return UNLOCK;
Lucas Dupin0fdd8f12019-07-17 15:28:18 -0700441 } else if (oldState == STATE_LOCK_OPEN && newState == STATE_LOCKED && !keyguardJustShown) {
Amin Shaikh5877c022019-05-24 10:26:05 -0400442 return LOCK;
Lucas Dupin71d2fb22019-05-30 18:26:54 -0700443 } else if (newState == STATE_SCANNING_FACE) {
Amin Shaikh5877c022019-05-24 10:26:05 -0400444 return SCANNING;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700445 }
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800446 return -1;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700447 }
448
Selim Cinek820ba2d2019-06-18 18:59:09 -0700449 @Override
450 public void onFullyHiddenChanged(boolean isFullyHidden) {
451 if (mBypassController.getBypassEnabled()) {
Selim Cineka678b0e2019-07-23 13:12:55 -0700452 boolean changed = updateIconVisibility();
453 if (changed) {
454 update();
455 }
Selim Cinek820ba2d2019-06-18 18:59:09 -0700456 }
457 }
458
Selim Cinek60ee7fd2019-06-26 13:06:00 -0700459 public void setBouncerShowingScrimmed(boolean bouncerShowing) {
460 mBouncerShowingScrimmed = bouncerShowing;
Selim Cinek820ba2d2019-06-18 18:59:09 -0700461 if (mBypassController.getBypassEnabled()) {
462 update();
463 }
464 }
465
Amin Shaikh5877c022019-05-24 10:26:05 -0400466 @Retention(RetentionPolicy.SOURCE)
Lucas Dupinad2577e2019-06-25 19:52:26 -0700467 @IntDef({ERROR, UNLOCK, LOCK, SCANNING})
Amin Shaikh5877c022019-05-24 10:26:05 -0400468 @interface LockAnimIndex {}
Lucas Dupinad2577e2019-06-25 19:52:26 -0700469 private static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
Amin Shaikh5877c022019-05-24 10:26:05 -0400470 private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
471 {
472 R.anim.lock_to_error,
473 R.anim.lock_unlock,
474 R.anim.lock_lock,
Lucas Dupinad2577e2019-06-25 19:52:26 -0700475 R.anim.lock_scanning
Amin Shaikh5877c022019-05-24 10:26:05 -0400476 },
477 {
478 R.anim.lock_to_error_circular,
479 R.anim.lock_unlock_circular,
480 R.anim.lock_lock_circular,
Lucas Dupinad2577e2019-06-25 19:52:26 -0700481 R.anim.lock_scanning_circular
Amin Shaikh5877c022019-05-24 10:26:05 -0400482 },
483 {
484 R.anim.lock_to_error_filled,
485 R.anim.lock_unlock_filled,
486 R.anim.lock_lock_filled,
Lucas Dupinad2577e2019-06-25 19:52:26 -0700487 R.anim.lock_scanning_filled
Amin Shaikh5877c022019-05-24 10:26:05 -0400488 },
489 {
490 R.anim.lock_to_error_rounded,
491 R.anim.lock_unlock_rounded,
492 R.anim.lock_lock_rounded,
Lucas Dupinad2577e2019-06-25 19:52:26 -0700493 R.anim.lock_scanning_rounded
Amin Shaikh5877c022019-05-24 10:26:05 -0400494 },
495 };
496
497 private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
498 final String setting = TextUtils.emptyIfNull(
499 Settings.Secure.getString(getContext().getContentResolver(),
500 Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
501 if (setting.contains("com.android.theme.icon_pack.circular.android")) {
502 return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
503 } else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
504 return LOCK_ANIM_RES_IDS[2][lockAnimIndex];
505 } else if (setting.contains("com.android.theme.icon_pack.rounded.android")) {
506 return LOCK_ANIM_RES_IDS[3][lockAnimIndex];
507 }
508 return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
509 }
510
Jorim Jaggi27267d62015-04-28 13:27:12 -0700511 private int getState() {
Selim Cinek1fcafc42015-07-20 14:39:25 -0700512 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Lucas Dupine78794c2019-06-18 11:55:37 -0700513 if ((mUnlockMethodCache.canSkipBouncer() || !mKeyguardShowing
514 || mKeyguardMonitor.isKeyguardGoingAway()) && !mSimLocked) {
Selim Cinekc3841982015-08-25 18:34:29 -0700515 return STATE_LOCK_OPEN;
Kevin Chynce135e62019-06-17 17:13:13 -0700516 } else if (mTransientBiometricsError) {
517 return STATE_BIOMETRICS_ERROR;
Lucas Dupinad2577e2019-06-25 19:52:26 -0700518 } else if (updateMonitor.isFaceDetectionRunning() && !mPulsing) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800519 return STATE_SCANNING_FACE;
Jorim Jaggi27267d62015-04-28 13:27:12 -0700520 } else {
521 return STATE_LOCKED;
522 }
523 }
Lucas Dupinc90a6bf2018-10-10 13:53:20 -0700524
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700525 @Override
526 public void onDozeAmountChanged(float linear, float eased) {
527 mDozeAmount = eased;
Lucas Dupinc90a6bf2018-10-10 13:53:20 -0700528 updateDarkTint();
529 }
530
Lucas Dupinf22194f2018-12-26 11:43:57 -0800531 /**
532 * When keyguard is in pulsing (AOD2) state.
533 * @param pulsing {@code true} when pulsing.
Lucas Dupinf22194f2018-12-26 11:43:57 -0800534 */
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700535 public void setPulsing(boolean pulsing) {
Lucas Dupinf22194f2018-12-26 11:43:57 -0800536 mPulsing = pulsing;
537 update();
538 }
539
540 /**
541 * Sets the dozing state of the keyguard.
542 */
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700543 @Override
544 public void onDozingChanged(boolean dozing) {
Lucas Dupinf22194f2018-12-26 11:43:57 -0800545 mDozing = dozing;
546 update();
547 }
548
Lucas Dupinc90a6bf2018-10-10 13:53:20 -0700549 private void updateDarkTint() {
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700550 int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
551 setImageTintList(ColorStateList.valueOf(color));
Lucas Dupinc90a6bf2018-10-10 13:53:20 -0700552 }
Lucas Dupin05904652019-04-09 16:16:15 -0700553
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700554 @Override
555 public void onDensityOrFontScaleChanged() {
556 ViewGroup.LayoutParams lp = getLayoutParams();
557 if (lp == null) {
558 return;
559 }
560 lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_lock_width);
561 lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_lock_height);
562 setLayoutParams(lp);
563 update(true /* force */);
564 }
565
566 @Override
567 public void onLocaleListChanged() {
568 setContentDescription(getContext().getText(R.string.accessibility_unlock_button));
569 update(true /* force */);
570 }
571
572 @Override
573 public void onUnlockMethodStateChanged() {
574 update();
575 }
Lucas Dupin71f38042019-05-10 16:23:04 -0700576
577 /**
578 * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
579 * icon on top of the black front scrim.
Selim Cinek390f1b92019-06-28 18:07:28 -0700580 * @param wakeAndUnlock are we wake and unlocking
581 * @param isUnlock are we currently unlocking
Lucas Dupin71f38042019-05-10 16:23:04 -0700582 */
Selim Cinek390f1b92019-06-28 18:07:28 -0700583 public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
Lucas Dupin71f38042019-05-10 16:23:04 -0700584 if (wakeAndUnlock) {
585 mWakeAndUnlockRunning = true;
586 }
Selim Cinek390f1b92019-06-28 18:07:28 -0700587 if (isUnlock && mBypassController.getBypassEnabled() && canBlockUpdates()) {
588 // We don't want the icon to change while we are unlocking
589 mBlockUpdates = true;
590 }
Lucas Dupin71f38042019-05-10 16:23:04 -0700591 update();
592 }
593
594 /**
Lucas Dupin23964c72019-05-21 16:12:45 -0700595 * When we're launching an affordance, like double pressing power to open camera.
596 */
597 public void onShowingLaunchAffordanceChanged(boolean showing) {
598 mShowingLaunchAffordance = showing;
599 update();
600 }
601
602 /**
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700603 * Called whenever the scrims become opaque, transparent or semi-transparent.
Lucas Dupin71f38042019-05-10 16:23:04 -0700604 */
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700605 public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
606 if (mWakeAndUnlockRunning
Lyn Hanbde48202019-05-29 19:18:29 -0700607 && scrimsVisible == ScrimController.TRANSPARENT) {
Lucas Dupincdbb1cb2019-05-16 19:48:30 -0700608 mWakeAndUnlockRunning = false;
609 update();
610 }
Lucas Dupin71f38042019-05-10 16:23:04 -0700611 }
Jorim Jaggi27267d62015-04-28 13:27:12 -0700612}