blob: 21f0c1e4eeb49cb5e716a81dc894e1f62833de6c [file] [log] [blame]
Adrian Roos12c1ef52014-06-04 13:54:08 +02001/*
2 * Copyright (C) 2014 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;
18
Beverly8c785892018-01-31 17:25:52 -050019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010021import android.app.admin.DevicePolicyManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020022import android.content.Context;
Jason Chang2386a372018-04-24 16:05:30 +080023import android.content.res.ColorStateList;
Lucas Dupinff6628d2018-10-15 10:12:37 -070024import android.content.res.Resources;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070025import android.graphics.Color;
Lucas Dupinff6628d2018-10-15 10:12:37 -070026import android.hardware.biometrics.BiometricSourceType;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020027import android.hardware.face.FaceManager;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070028import android.hardware.fingerprint.FingerprintManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020029import android.os.BatteryManager;
30import android.os.BatteryStats;
31import android.os.Handler;
32import android.os.Message;
33import android.os.RemoteException;
34import android.os.ServiceManager;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060035import android.os.UserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020036import android.text.TextUtils;
37import android.text.format.Formatter;
38import android.util.Log;
39import android.view.View;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010040import android.view.ViewGroup;
Adrian Roos12c1ef52014-06-04 13:54:08 +020041
Adrian Roosc1b50322017-02-27 21:07:58 +010042import com.android.internal.annotations.VisibleForTesting;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070043import com.android.internal.app.IBatteryStats;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070044import com.android.internal.logging.nano.MetricsProto;
45import com.android.internal.widget.LockPatternUtils;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070046import com.android.keyguard.KeyguardUpdateMonitor;
47import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jason Monk58be7a62017-02-01 20:17:51 -050048import com.android.settingslib.Utils;
Jason Monk9c7844c2017-01-18 15:21:53 -050049import com.android.systemui.Dependency;
Beverly8c785892018-01-31 17:25:52 -050050import com.android.systemui.Interpolators;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070051import com.android.systemui.R;
Beverly8fdb5332019-02-04 14:29:49 -050052import com.android.systemui.plugins.statusbar.StatusBarStateController;
53import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070054import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
55import com.android.systemui.statusbar.phone.LockIcon;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070056import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070057import com.android.systemui.statusbar.phone.ShadeController;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070058import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070059import com.android.systemui.statusbar.phone.UnlockMethodCache;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070060import com.android.systemui.statusbar.policy.AccessibilityController;
Zachary Iqbalf50284c2017-01-22 18:54:46 -080061import com.android.systemui.statusbar.policy.UserInfoController;
Adrian Roosc1b50322017-02-27 21:07:58 +010062import com.android.systemui.util.wakelock.SettableWakeLock;
63import com.android.systemui.util.wakelock.WakeLock;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070064
Lucas Dupin3fcdd472018-01-19 19:06:45 -080065import java.io.FileDescriptor;
66import java.io.PrintWriter;
Lucas Dupin4272f442018-01-13 22:00:35 -080067import java.text.NumberFormat;
Lucas Dupin8d595d22018-03-08 10:34:58 -080068import java.util.IllegalFormatConversionException;
Lucas Dupin4272f442018-01-13 22:00:35 -080069
Adrian Roos12c1ef52014-06-04 13:54:08 +020070/**
Selim Cinekcfafe4e2015-08-11 14:58:44 -070071 * Controls the indications and error messages shown on the Keyguard
Adrian Roos12c1ef52014-06-04 13:54:08 +020072 */
Lucas Dupin8e2fd012019-04-25 16:40:54 -070073public class KeyguardIndicationController implements StateListener,
74 UnlockMethodCache.OnUnlockMethodChangedListener {
Adrian Roos12c1ef52014-06-04 13:54:08 +020075
Adrian Roos0c859ae2015-11-23 16:47:50 -080076 private static final String TAG = "KeyguardIndication";
77 private static final boolean DEBUG_CHARGING_SPEED = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +020078
79 private static final int MSG_HIDE_TRANSIENT = 1;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020080 private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
81 private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
Adrian Roos12c1ef52014-06-04 13:54:08 +020082
83 private final Context mContext;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070084 private final ShadeController mShadeController;
85 private final AccessibilityController mAccessibilityController;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070086 private final UnlockMethodCache mUnlockMethodCache;
87 private final StatusBarStateController mStatusBarStateController;
88 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin987f1932017-05-13 21:02:52 -070089 private ViewGroup mIndicationArea;
90 private KeyguardIndicationTextView mTextView;
91 private KeyguardIndicationTextView mDisclosure;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060092 private final UserManager mUserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020093 private final IBatteryStats mBatteryInfo;
Adrian Roosc1b50322017-02-27 21:07:58 +010094 private final SettableWakeLock mWakeLock;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070095 private final LockPatternUtils mLockPatternUtils;
Adrian Roos12c1ef52014-06-04 13:54:08 +020096
Adrian Roos7b043112015-07-10 13:00:33 -070097 private final int mSlowThreshold;
98 private final int mFastThreshold;
Lucas Dupin05904652019-04-09 16:16:15 -070099 private final LockIcon mLockIcon;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700100 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700101 private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
Adrian Roos7b043112015-07-10 13:00:33 -0700102
Adrian Roos12c1ef52014-06-04 13:54:08 +0200103 private String mRestingIndication;
Lucas Dupinef886542018-01-03 16:03:07 -0800104 private CharSequence mTransientIndication;
Jason Chang2386a372018-04-24 16:05:30 +0800105 private ColorStateList mTransientTextColorState;
106 private ColorStateList mInitialTextColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200107 private boolean mVisible;
108
109 private boolean mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400110 private boolean mPowerPluggedInWired;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200111 private boolean mPowerCharged;
Adrian Roos7b043112015-07-10 13:00:33 -0700112 private int mChargingSpeed;
Adrian Roos0c859ae2015-11-23 16:47:50 -0800113 private int mChargingWattage;
Lucas Dupin4272f442018-01-13 22:00:35 -0800114 private int mBatteryLevel;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700115 private String mMessageToShowOnScreenOn;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200116
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700117 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800118
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100119 private final DevicePolicyManager mDevicePolicyManager;
Adrian Roos91ba3072017-02-14 16:50:46 +0100120 private boolean mDozing;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100121
Adrian Roosaf45b602017-03-14 13:10:25 -0700122 /**
123 * Creates a new KeyguardIndicationController and registers callbacks.
124 */
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100125 public KeyguardIndicationController(Context context, ViewGroup indicationArea,
126 LockIcon lockIcon) {
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700127 this(context, indicationArea, lockIcon, new LockPatternUtils(context),
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700128 WakeLock.createPartial(context, "Doze:KeyguardIndication"),
129 Dependency.get(ShadeController.class),
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700130 Dependency.get(AccessibilityController.class),
131 UnlockMethodCache.getInstance(context),
132 Dependency.get(StatusBarStateController.class),
133 KeyguardUpdateMonitor.getInstance(context));
Adrian Roosc1b50322017-02-27 21:07:58 +0100134 }
135
Adrian Roosaf45b602017-03-14 13:10:25 -0700136 /**
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700137 * Creates a new KeyguardIndicationController for testing.
Adrian Roosaf45b602017-03-14 13:10:25 -0700138 */
Adrian Roosc1b50322017-02-27 21:07:58 +0100139 @VisibleForTesting
140 KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700141 LockPatternUtils lockPatternUtils, WakeLock wakeLock, ShadeController shadeController,
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700142 AccessibilityController accessibilityController, UnlockMethodCache unlockMethodCache,
143 StatusBarStateController statusBarStateController,
144 KeyguardUpdateMonitor keyguardUpdateMonitor) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200145 mContext = context;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100146 mIndicationArea = indicationArea;
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800147 mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
Jason Chang2386a372018-04-24 16:05:30 +0800148 mInitialTextColorState = mTextView != null ?
149 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800150 mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700151 mLockIcon = lockIcon;
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700152 mShadeController = shadeController;
153 mAccessibilityController = accessibilityController;
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700154 mUnlockMethodCache = unlockMethodCache;
155 mStatusBarStateController = statusBarStateController;
156 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Brad Stenning691c2742019-04-19 11:48:00 -0700157 // lock icon is not used on all form factors.
158 if (mLockIcon != null) {
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700159 mLockIcon.setOnLongClickListener(this::handleLockLongClick);
160 mLockIcon.setOnClickListener(this::handleLockClick);
Brad Stenning691c2742019-04-19 11:48:00 -0700161 }
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800162 mWakeLock = new SettableWakeLock(wakeLock, TAG);
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700163 mLockPatternUtils = lockPatternUtils;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200164
Adrian Roos7b043112015-07-10 13:00:33 -0700165 Resources res = context.getResources();
166 mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
167 mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
168
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600169 mUserManager = context.getSystemService(UserManager.class);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200170 mBatteryInfo = IBatteryStats.Stub.asInterface(
171 ServiceManager.getService(BatteryStats.SERVICE_NAME));
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600172
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100173 mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
174 Context.DEVICE_POLICY_SERVICE);
Adrian Roosaf45b602017-03-14 13:10:25 -0700175 updateDisclosure();
Adrian Roosaf45b602017-03-14 13:10:25 -0700176
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700177 mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
178 mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
179 mStatusBarStateController.addCallback(this);
180 mUnlockMethodCache.addListener(this);
Evan Laird878c8532018-10-15 15:54:29 -0400181 }
182
183 /**
184 * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
185 * controller a chance to unregister itself as a receiver.
186 *
187 * //TODO: This can probably be converted to a fragment and not have to be manually recreated
188 */
189 public void destroy() {
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700190 mKeyguardUpdateMonitor.removeCallback(mTickReceiver);
191 mKeyguardUpdateMonitor.removeCallback(getKeyguardCallback());
192 mStatusBarStateController.removeCallback(this);
193 mUnlockMethodCache.removeListener(this);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100194 }
195
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700196 private boolean handleLockLongClick(View view) {
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700197 mLockscreenGestureLogger.write(MetricsProto.MetricsEvent.ACTION_LS_LOCK,
198 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
199 showTransientIndication(R.string.keyguard_indication_trust_disabled);
200 mLockPatternUtils.requireCredentialEntry(KeyguardUpdateMonitor.getCurrentUser());
201
202 return true;
203 }
204
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700205 private void handleLockClick(View view) {
206 if (!mAccessibilityController.isAccessibilityEnabled()) {
207 return;
208 }
209 mShadeController.showBouncer(false /* scrimmed */);
210 }
211
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800212 /**
213 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
214 * {@link KeyguardIndicationController}.
215 *
216 * <p>Subclasses may override this method to extend or change the callback behavior by extending
217 * the {@link BaseKeyguardCallback}.
218 *
219 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
220 * same instance.
221 */
222 protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700223 if (mUpdateMonitorCallback == null) {
224 mUpdateMonitorCallback = new BaseKeyguardCallback();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800225 }
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700226 return mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800227 }
228
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100229 private void updateDisclosure() {
230 if (mDevicePolicyManager == null) {
231 return;
232 }
233
Adrian Roos91ba3072017-02-14 16:50:46 +0100234 if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100235 final CharSequence organizationName =
236 mDevicePolicyManager.getDeviceOwnerOrganizationName();
237 if (organizationName != null) {
238 mDisclosure.switchIndication(mContext.getResources().getString(
239 R.string.do_disclosure_with_name, organizationName));
240 } else {
241 mDisclosure.switchIndication(R.string.do_disclosure_generic);
242 }
243 mDisclosure.setVisibility(View.VISIBLE);
244 } else {
245 mDisclosure.setVisibility(View.GONE);
246 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200247 }
248
249 public void setVisible(boolean visible) {
250 mVisible = visible;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100251 mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200252 if (visible) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700253 // If this is called after an error message was already shown, we should not clear it.
254 // Otherwise the error message won't be shown
255 if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
256 hideTransientIndication();
257 }
Beverly8c785892018-01-31 17:25:52 -0500258 updateIndication(false);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700259 } else if (!visible) {
260 // If we unlock and return to keyguard quickly, previous error should not be shown
261 hideTransientIndication();
Adrian Roos12c1ef52014-06-04 13:54:08 +0200262 }
263 }
264
265 /**
266 * Sets the indication that is shown if nothing else is showing.
267 */
268 public void setRestingIndication(String restingIndication) {
269 mRestingIndication = restingIndication;
Beverly8c785892018-01-31 17:25:52 -0500270 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200271 }
272
273 /**
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800274 * Sets the active controller managing changes and callbacks to user information.
275 */
276 public void setUserInfoController(UserInfoController userInfoController) {
277 }
278
279 /**
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700280 * Returns the indication text indicating that trust has been granted.
281 *
282 * @return {@code null} or an empty string if a trust indication text should not be shown.
283 */
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700284 @VisibleForTesting
285 String getTrustGrantedIndication() {
Lucas Dupin859f2c82019-04-17 18:30:00 -0700286 return mContext.getString(R.string.keyguard_indication_trust_unlocked);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700287 }
288
289 /**
290 * Returns the indication text indicating that trust is currently being managed.
291 *
292 * @return {@code null} or an empty string if a trust managed text should not be shown.
293 */
Lucas Dupin859f2c82019-04-17 18:30:00 -0700294 private String getTrustManagedIndication() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700295 return null;
296 }
297
298 /**
Adrian Roos12c1ef52014-06-04 13:54:08 +0200299 * Hides transient indication in {@param delayMs}.
300 */
301 public void hideTransientIndicationDelayed(long delayMs) {
302 mHandler.sendMessageDelayed(
303 mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
304 }
305
306 /**
307 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
308 */
309 public void showTransientIndication(int transientIndication) {
310 showTransientIndication(mContext.getResources().getString(transientIndication));
311 }
312
313 /**
314 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
315 */
Lucas Dupinef886542018-01-03 16:03:07 -0800316 public void showTransientIndication(CharSequence transientIndication) {
Jason Chang2386a372018-04-24 16:05:30 +0800317 showTransientIndication(transientIndication, mInitialTextColorState);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700318 }
319
320 /**
321 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
322 */
Jason Chang2386a372018-04-24 16:05:30 +0800323 public void showTransientIndication(CharSequence transientIndication,
324 ColorStateList textColorState) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200325 mTransientIndication = transientIndication;
Jason Chang2386a372018-04-24 16:05:30 +0800326 mTransientTextColorState = textColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200327 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Adrian Roosc1b50322017-02-27 21:07:58 +0100328 if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
329 // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
330 mWakeLock.setAcquired(true);
331 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
332 }
Beverly8c785892018-01-31 17:25:52 -0500333
334 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200335 }
336
337 /**
338 * Hides transient indication.
339 */
340 public void hideTransientIndication() {
341 if (mTransientIndication != null) {
342 mTransientIndication = null;
343 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Beverly8c785892018-01-31 17:25:52 -0500344 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200345 }
346 }
347
Beverly8c785892018-01-31 17:25:52 -0500348 protected final void updateIndication(boolean animate) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100349 if (TextUtils.isEmpty(mTransientIndication)) {
350 mWakeLock.setAcquired(false);
351 }
352
Adrian Roos12c1ef52014-06-04 13:54:08 +0200353 if (mVisible) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700354 // Walk down a precedence-ordered list of what indication
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600355 // should be shown based on user or device state
Lucas Dupinff6628d2018-10-15 10:12:37 -0700356 if (mDozing) {
Lucas Dupin07ed3df2019-03-26 21:23:59 -0700357 // When dozing we ignore any text color and use white instead, because
358 // colors can be hard to read in low brightness.
359 mTextView.setTextColor(Color.WHITE);
Lucas Dupinff6628d2018-10-15 10:12:37 -0700360 if (!TextUtils.isEmpty(mTransientIndication)) {
Lucas Dupinff6628d2018-10-15 10:12:37 -0700361 mTextView.switchIndication(mTransientIndication);
Lucas Dupin07ed3df2019-03-26 21:23:59 -0700362 } else if (mPowerPluggedIn) {
363 String indication = computePowerIndication();
364 if (animate) {
365 animateText(mTextView, indication);
366 } else {
367 mTextView.switchIndication(indication);
368 }
369 } else {
370 String percentage = NumberFormat.getPercentInstance()
371 .format(mBatteryLevel / 100f);
372 mTextView.switchIndication(percentage);
Lucas Dupinff6628d2018-10-15 10:12:37 -0700373 }
Lucas Dupinff6628d2018-10-15 10:12:37 -0700374 return;
375 }
376
Jorim Jaggifabc7432017-05-15 02:40:05 +0200377 int userId = KeyguardUpdateMonitor.getCurrentUser();
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700378 String trustGrantedIndication = getTrustGrantedIndication();
379 String trustManagedIndication = getTrustManagedIndication();
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700380 if (!mUserManager.isUserUnlocked(userId)) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600381 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
Jason Chang2386a372018-04-24 16:05:30 +0800382 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600383 } else if (!TextUtils.isEmpty(mTransientIndication)) {
384 mTextView.switchIndication(mTransientIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800385 mTextView.setTextColor(mTransientTextColorState);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700386 } else if (!TextUtils.isEmpty(trustGrantedIndication)
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700387 && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700388 mTextView.switchIndication(trustGrantedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800389 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600390 } else if (mPowerPluggedIn) {
391 String indication = computePowerIndication();
392 if (DEBUG_CHARGING_SPEED) {
393 indication += ", " + (mChargingWattage / 1000) + " mW";
394 }
Jason Chang2386a372018-04-24 16:05:30 +0800395 mTextView.setTextColor(mInitialTextColorState);
Beverly85499d92018-02-14 15:55:16 -0500396 if (animate) {
397 animateText(mTextView, indication);
398 } else {
399 mTextView.switchIndication(indication);
400 }
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700401 } else if (!TextUtils.isEmpty(trustManagedIndication)
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700402 && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
403 && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700404 mTextView.switchIndication(trustManagedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800405 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600406 } else {
407 mTextView.switchIndication(mRestingIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800408 mTextView.setTextColor(mInitialTextColorState);
Adrian Roos7b043112015-07-10 13:00:33 -0700409 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200410 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200411 }
412
Beverly85499d92018-02-14 15:55:16 -0500413 // animates textView - textView moves up and bounces down
414 private void animateText(KeyguardIndicationTextView textView, String indication) {
415 int yTranslation = mContext.getResources().getInteger(
416 R.integer.wired_charging_keyguard_text_animation_distance);
417 int animateUpDuration = mContext.getResources().getInteger(
418 R.integer.wired_charging_keyguard_text_animation_duration_up);
419 int animateDownDuration = mContext.getResources().getInteger(
420 R.integer.wired_charging_keyguard_text_animation_duration_down);
Lucas Dupindef43692018-07-02 15:22:58 -0700421 textView.animate().cancel();
422 float translation = textView.getTranslationY();
Beverly85499d92018-02-14 15:55:16 -0500423 textView.animate()
424 .translationYBy(yTranslation)
425 .setInterpolator(Interpolators.LINEAR)
426 .setDuration(animateUpDuration)
427 .setListener(new AnimatorListenerAdapter() {
Lucas Dupindef43692018-07-02 15:22:58 -0700428 private boolean mCancelled;
429
Beverly85499d92018-02-14 15:55:16 -0500430 @Override
431 public void onAnimationStart(Animator animation) {
432 textView.switchIndication(indication);
433 }
Lucas Dupindef43692018-07-02 15:22:58 -0700434
435 @Override
436 public void onAnimationCancel(Animator animation) {
437 textView.setTranslationY(translation);
438 mCancelled = true;
439 }
440
Beverly85499d92018-02-14 15:55:16 -0500441 @Override
442 public void onAnimationEnd(Animator animation) {
Lucas Dupindef43692018-07-02 15:22:58 -0700443 if (mCancelled) {
444 return;
445 }
Beverly85499d92018-02-14 15:55:16 -0500446 textView.animate()
447 .setDuration(animateDownDuration)
448 .setInterpolator(Interpolators.BOUNCE)
Lucas Dupindef43692018-07-02 15:22:58 -0700449 .translationY(translation)
450 .setListener(new AnimatorListenerAdapter() {
451 @Override
452 public void onAnimationCancel(Animator animation) {
453 textView.setTranslationY(translation);
454 }
455 });
Beverly85499d92018-02-14 15:55:16 -0500456 }
457 });
458 }
459
Adrian Roos12c1ef52014-06-04 13:54:08 +0200460 private String computePowerIndication() {
461 if (mPowerCharged) {
462 return mContext.getResources().getString(R.string.keyguard_charged);
463 }
464
465 // Try fetching charging time from battery stats.
Adrian Roos7e39e592015-09-23 17:03:47 -0700466 long chargingTimeRemaining = 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200467 try {
Adrian Roos7e39e592015-09-23 17:03:47 -0700468 chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
469
Adrian Roos12c1ef52014-06-04 13:54:08 +0200470 } catch (RemoteException e) {
471 Log.e(TAG, "Error calling IBatteryStats: ", e);
472 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700473 final boolean hasChargingTime = chargingTimeRemaining > 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200474
Adrian Roos7b043112015-07-10 13:00:33 -0700475 int chargingId;
Beverly7d7f6992019-02-11 13:58:27 -0500476 if (mPowerPluggedInWired) {
477 switch (mChargingSpeed) {
478 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
479 chargingId = hasChargingTime
480 ? R.string.keyguard_indication_charging_time_fast
481 : R.string.keyguard_plugged_in_charging_fast;
482 break;
483 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
484 chargingId = hasChargingTime
485 ? R.string.keyguard_indication_charging_time_slowly
486 : R.string.keyguard_plugged_in_charging_slowly;
487 break;
488 default:
489 chargingId = hasChargingTime
490 ? R.string.keyguard_indication_charging_time
491 : R.string.keyguard_plugged_in;
492 break;
493 }
494 } else {
495 chargingId = hasChargingTime
496 ? R.string.keyguard_indication_charging_time_wireless
497 : R.string.keyguard_plugged_in_wireless;
Adrian Roos7b043112015-07-10 13:00:33 -0700498 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700499
Lucas Dupin8d595d22018-03-08 10:34:58 -0800500 String percentage = NumberFormat.getPercentInstance()
501 .format(mBatteryLevel / 100f);
Adrian Roos7e39e592015-09-23 17:03:47 -0700502 if (hasChargingTime) {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800503 // We now have battery percentage in these strings and it's expected that all
504 // locales will also have it in the future. For now, we still have to support the old
505 // format until all languages get the new translations.
Adrian Roos7e39e592015-09-23 17:03:47 -0700506 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
507 mContext, chargingTimeRemaining);
Lucas Dupin8d595d22018-03-08 10:34:58 -0800508 try {
509 return mContext.getResources().getString(chargingId, chargingTimeFormatted,
510 percentage);
511 } catch (IllegalFormatConversionException e) {
512 return mContext.getResources().getString(chargingId, chargingTimeFormatted);
513 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700514 } else {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800515 // Same as above
516 try {
517 return mContext.getResources().getString(chargingId, percentage);
518 } catch (IllegalFormatConversionException e) {
519 return mContext.getResources().getString(chargingId);
520 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700521 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200522 }
523
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800524 public void setStatusBarKeyguardViewManager(
525 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
526 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
527 }
528
Lucas Dupin7e171e22018-12-20 11:29:35 -0800529 private final KeyguardUpdateMonitorCallback mTickReceiver =
530 new KeyguardUpdateMonitorCallback() {
531 @Override
532 public void onTimeChanged() {
533 if (mVisible) {
534 updateIndication(false /* animate */);
535 }
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800536 }
Lucas Dupin7e171e22018-12-20 11:29:35 -0800537 };
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800538
539 private final Handler mHandler = new Handler() {
540 @Override
541 public void handleMessage(Message msg) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100542 if (msg.what == MSG_HIDE_TRANSIENT) {
543 hideTransientIndication();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200544 } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800545 mLockIcon.setTransientBiometricsError(false);
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800546 }
547 }
548 };
549
Adrian Roos91ba3072017-02-14 16:50:46 +0100550 public void setDozing(boolean dozing) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200551 if (mDozing == dozing) {
552 return;
553 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100554 mDozing = dozing;
Beverly8c785892018-01-31 17:25:52 -0500555 updateIndication(false);
Adrian Roos91ba3072017-02-14 16:50:46 +0100556 updateDisclosure();
557 }
558
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800559 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
560 pw.println("KeyguardIndicationController:");
Jason Chang2386a372018-04-24 16:05:30 +0800561 pw.println(" mTransientTextColorState: " + mTransientTextColorState);
562 pw.println(" mInitialTextColorState: " + mInitialTextColorState);
Beverly2034c832018-03-19 11:18:51 -0400563 pw.println(" mPowerPluggedInWired: " + mPowerPluggedInWired);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800564 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
565 pw.println(" mPowerCharged: " + mPowerCharged);
566 pw.println(" mChargingSpeed: " + mChargingSpeed);
567 pw.println(" mChargingWattage: " + mChargingWattage);
568 pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
569 pw.println(" mDozing: " + mDozing);
570 pw.println(" mBatteryLevel: " + mBatteryLevel);
571 pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
572 pw.println(" computePowerIndication(): " + computePowerIndication());
573 }
574
Evan Laird878c8532018-10-15 15:54:29 -0400575 @Override
576 public void onStateChanged(int newState) {
577 // don't care
578 }
579
580 @Override
581 public void onDozingChanged(boolean isDozing) {
582 setDozing(isDozing);
583 }
584
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700585 @Override
586 public void onUnlockMethodStateChanged() {
587 updateIndication(!mDozing);
588 }
589
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800590 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
Adrian Roos56021892017-02-27 20:25:09 +0100591 public static final int HIDE_DELAY_MS = 5000;
Selim Cinek3e451942016-07-14 18:07:53 -0700592
Adrian Roos12c1ef52014-06-04 13:54:08 +0200593 @Override
594 public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100595 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
Adrian Roos12c1ef52014-06-04 13:54:08 +0200596 || status.status == BatteryManager.BATTERY_STATUS_FULL;
Adrian Roos56021892017-02-27 20:25:09 +0100597 boolean wasPluggedIn = mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400598 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100599 mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200600 mPowerCharged = status.isCharged();
Adrian Roos0c859ae2015-11-23 16:47:50 -0800601 mChargingWattage = status.maxChargingWattage;
Adrian Roos7b043112015-07-10 13:00:33 -0700602 mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
Lucas Dupin4272f442018-01-13 22:00:35 -0800603 mBatteryLevel = status.level;
Beverly2034c832018-03-19 11:18:51 -0400604 updateIndication(!wasPluggedIn && mPowerPluggedInWired);
Adrian Roosc1b50322017-02-27 21:07:58 +0100605 if (mDozing) {
606 if (!wasPluggedIn && mPowerPluggedIn) {
607 showTransientIndication(computePowerIndication());
608 hideTransientIndicationDelayed(HIDE_DELAY_MS);
609 } else if (wasPluggedIn && !mPowerPluggedIn) {
610 hideTransientIndication();
611 }
Adrian Roos56021892017-02-27 20:25:09 +0100612 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200613 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700614
615 @Override
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100616 public void onKeyguardVisibilityChanged(boolean showing) {
617 if (showing) {
618 updateDisclosure();
619 }
620 }
621
622 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200623 public void onBiometricHelp(int msgId, String helpString,
624 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700625 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200626 if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700627 return;
628 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700629 animatePadlockError();
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700630 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Jason Chang2386a372018-04-24 16:05:30 +0800631 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800632 mInitialTextColorState);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700633 } else if (updateMonitor.isScreenOn()) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800634 showTransientIndication(helpString);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200635 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700636 }
637 }
638
639 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200640 public void onBiometricError(int msgId, String errString,
641 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700642 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200643 if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700644 return;
645 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700646 animatePadlockError();
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700647 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700648 mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700649 } else if (updateMonitor.isScreenOn()) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800650 showTransientIndication(errString);
Selim Cinek3e451942016-07-14 18:07:53 -0700651 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100652 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinek3e451942016-07-14 18:07:53 -0700653 } else {
654 mMessageToShowOnScreenOn = errString;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700655 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700656 }
657
658 private void animatePadlockError() {
659 mLockIcon.setTransientBiometricsError(true);
660 mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
661 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
662 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700663 }
664
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200665 private boolean shouldSuppressBiometricError(int msgId,
666 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
667 if (biometricSourceType == BiometricSourceType.FINGERPRINT)
668 return shouldSuppressFingerprintError(msgId, updateMonitor);
669 if (biometricSourceType == BiometricSourceType.FACE)
670 return shouldSuppressFaceError(msgId, updateMonitor);
671 return false;
672 }
673
674 private boolean shouldSuppressFingerprintError(int msgId,
675 KeyguardUpdateMonitor updateMonitor) {
676 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
677 && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
678 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
679 }
680
681 private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
682 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
683 && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
684 || msgId == FaceManager.FACE_ERROR_CANCELED);
685 }
686
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700687 @Override
Lucas Dupinef886542018-01-03 16:03:07 -0800688 public void onTrustAgentErrorMessage(CharSequence message) {
Jason Chang2386a372018-04-24 16:05:30 +0800689 showTransientIndication(message, Utils.getColorError(mContext));
Lucas Dupinef886542018-01-03 16:03:07 -0800690 }
691
692 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700693 public void onScreenTurnedOn() {
694 if (mMessageToShowOnScreenOn != null) {
Jason Chang2386a372018-04-24 16:05:30 +0800695 showTransientIndication(mMessageToShowOnScreenOn, Utils.getColorError(mContext));
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700696 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100697 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700698 mMessageToShowOnScreenOn = null;
699 }
700 }
701
702 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200703 public void onBiometricRunningStateChanged(boolean running,
704 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700705 if (running) {
Lucas Dupin8f3faac2019-03-12 15:28:49 -0700706 // Let's hide any previous messages when authentication starts, otherwise
707 // multiple auth attempts would overlap.
708 hideTransientIndication();
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700709 mMessageToShowOnScreenOn = null;
710 }
711 }
Selim Cinek3e451942016-07-14 18:07:53 -0700712
713 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200714 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
715 super.onBiometricAuthenticated(userId, biometricSourceType);
Kevin Chyn6d793bd2019-03-27 15:36:13 -0700716 mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
Selim Cinek3e451942016-07-14 18:07:53 -0700717 }
718
719 @Override
Jorim Jaggidadafd42016-09-30 07:20:25 -0700720 public void onUserUnlocked() {
721 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500722 updateIndication(false);
Jorim Jaggidadafd42016-09-30 07:20:25 -0700723 }
724 }
Lucas Dupin05904652019-04-09 16:16:15 -0700725
726 @Override
727 public void onKeyguardBouncerChanged(boolean bouncer) {
Brad Stenning8fcd8b42019-04-22 09:30:20 -0700728 if (mLockIcon == null) {
729 return;
730 }
Lucas Dupin05904652019-04-09 16:16:15 -0700731 mLockIcon.setBouncerVisible(bouncer);
732 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200733 };
Adrian Roos12c1ef52014-06-04 13:54:08 +0200734}