blob: a1444532bd5e00b3d2a562459a4cab8d9af3d2c6 [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
Jeff DeCewa87cddb2020-06-12 12:13:52 -040019import static com.android.systemui.DejankUtils.whitelistIpcs;
20
Beverly8c785892018-01-31 17:25:52 -050021import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
Jeff DeCewa87cddb2020-06-12 12:13:52 -040023import android.app.admin.DevicePolicyManager;
24import android.content.BroadcastReceiver;
Adrian Roos12c1ef52014-06-04 13:54:08 +020025import android.content.Context;
Jeff DeCewa87cddb2020-06-12 12:13:52 -040026import android.content.Intent;
27import android.content.IntentFilter;
arangelovc00bd0c2020-06-19 17:13:59 +010028import android.content.pm.UserInfo;
Jason Chang2386a372018-04-24 16:05:30 +080029import android.content.res.ColorStateList;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070030import android.graphics.Color;
Lucas Dupinff6628d2018-10-15 10:12:37 -070031import android.hardware.biometrics.BiometricSourceType;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020032import android.hardware.face.FaceManager;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070033import android.hardware.fingerprint.FingerprintManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020034import android.os.BatteryManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020035import android.os.Handler;
36import android.os.Message;
37import android.os.RemoteException;
arangelovc00bd0c2020-06-19 17:13:59 +010038import android.os.UserHandle;
39import android.os.UserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020040import android.text.TextUtils;
41import android.text.format.Formatter;
42import android.util.Log;
43import android.view.View;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010044import android.view.ViewGroup;
Adrian Roos12c1ef52014-06-04 13:54:08 +020045
arangelovc00bd0c2020-06-19 17:13:59 +010046import androidx.annotation.Nullable;
47
Adrian Roosc1b50322017-02-27 21:07:58 +010048import com.android.internal.annotations.VisibleForTesting;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070049import com.android.internal.app.IBatteryStats;
Lucas Dupineff8ef02019-06-06 11:14:01 -070050import com.android.internal.widget.ViewClippingUtil;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070051import com.android.keyguard.KeyguardUpdateMonitor;
52import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jason Monk58be7a62017-02-01 20:17:51 -050053import com.android.settingslib.Utils;
Raff Tsaif4ea5622019-06-26 16:15:21 +080054import com.android.settingslib.fuelgauge.BatteryStatus;
Beverly8c785892018-01-31 17:25:52 -050055import com.android.systemui.Interpolators;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070056import com.android.systemui.R;
Jeff DeCewa87cddb2020-06-12 12:13:52 -040057import com.android.systemui.broadcast.BroadcastDispatcher;
Jerry Chang6a8fb022019-11-15 06:52:54 +080058import com.android.systemui.dock.DockManager;
Beverly8fdb5332019-02-04 14:29:49 -050059import com.android.systemui.plugins.statusbar.StatusBarStateController;
60import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070061import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -050062import com.android.systemui.statusbar.phone.LockscreenLockIconController;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070063import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040064import com.android.systemui.statusbar.policy.KeyguardStateController;
Adrian Roosc1b50322017-02-27 21:07:58 +010065import com.android.systemui.util.wakelock.SettableWakeLock;
66import com.android.systemui.util.wakelock.WakeLock;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070067
Lucas Dupin3fcdd472018-01-19 19:06:45 -080068import java.io.FileDescriptor;
69import java.io.PrintWriter;
Lucas Dupin4272f442018-01-13 22:00:35 -080070import java.text.NumberFormat;
Lucas Dupin8d595d22018-03-08 10:34:58 -080071import java.util.IllegalFormatConversionException;
Lucas Dupin4272f442018-01-13 22:00:35 -080072
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -050073import javax.inject.Inject;
74import javax.inject.Singleton;
75
Adrian Roos12c1ef52014-06-04 13:54:08 +020076/**
Selim Cinekcfafe4e2015-08-11 14:58:44 -070077 * Controls the indications and error messages shown on the Keyguard
Adrian Roos12c1ef52014-06-04 13:54:08 +020078 */
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -050079@Singleton
Lucas Dupin8e2fd012019-04-25 16:40:54 -070080public class KeyguardIndicationController implements StateListener,
Lucas Dupinc8f16e82019-09-17 18:24:50 -040081 KeyguardStateController.Callback {
Adrian Roos12c1ef52014-06-04 13:54:08 +020082
Adrian Roos0c859ae2015-11-23 16:47:50 -080083 private static final String TAG = "KeyguardIndication";
84 private static final boolean DEBUG_CHARGING_SPEED = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +020085
86 private static final int MSG_HIDE_TRANSIENT = 1;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020087 private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
Lucas Dupin51996bb2019-05-16 17:56:43 -070088 private static final int MSG_SWIPE_UP_TO_UNLOCK = 3;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020089 private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
Robert Snoebergerddfb0652019-06-21 16:41:46 -040090 private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
Adrian Roos12c1ef52014-06-04 13:54:08 +020091
92 private final Context mContext;
Jeff DeCewa87cddb2020-06-12 12:13:52 -040093 private final BroadcastDispatcher mBroadcastDispatcher;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040094 private final KeyguardStateController mKeyguardStateController;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070095 private final StatusBarStateController mStatusBarStateController;
96 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupin987f1932017-05-13 21:02:52 -070097 private ViewGroup mIndicationArea;
98 private KeyguardIndicationTextView mTextView;
Jeff DeCewa87cddb2020-06-12 12:13:52 -040099 private KeyguardIndicationTextView mDisclosure;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200100 private final IBatteryStats mBatteryInfo;
Adrian Roosc1b50322017-02-27 21:07:58 +0100101 private final SettableWakeLock mWakeLock;
Jerry Chang6a8fb022019-11-15 06:52:54 +0800102 private final DockManager mDockManager;
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400103 private final DevicePolicyManager mDevicePolicyManager;
arangelovc00bd0c2020-06-19 17:13:59 +0100104 private final UserManager mUserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200105
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400106 private BroadcastReceiver mBroadcastReceiver;
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500107 private LockscreenLockIconController mLockIconController;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700108 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Adrian Roos7b043112015-07-10 13:00:33 -0700109
Adrian Roos12c1ef52014-06-04 13:54:08 +0200110 private String mRestingIndication;
Jerry Chang6a8fb022019-11-15 06:52:54 +0800111 private String mAlignmentIndication;
Lucas Dupinef886542018-01-03 16:03:07 -0800112 private CharSequence mTransientIndication;
Lucas Dupinaff42362020-03-27 16:28:20 -0700113 private boolean mTransientTextIsError;
Jason Chang2386a372018-04-24 16:05:30 +0800114 private ColorStateList mInitialTextColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200115 private boolean mVisible;
Lucas Dupin85ea4202019-11-04 16:01:51 -0800116 private boolean mHideTransientMessageOnScreenOff;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200117
118 private boolean mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400119 private boolean mPowerPluggedInWired;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200120 private boolean mPowerCharged;
Adrian Roos7b043112015-07-10 13:00:33 -0700121 private int mChargingSpeed;
Adrian Roos0c859ae2015-11-23 16:47:50 -0800122 private int mChargingWattage;
Lucas Dupin4272f442018-01-13 22:00:35 -0800123 private int mBatteryLevel;
Lucas Dupin9131b282019-11-19 16:25:03 -0800124 private long mChargingTimeRemaining;
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400125 private float mDisclosureMaxAlpha;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700126 private String mMessageToShowOnScreenOn;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200127
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700128 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800129
Adrian Roos91ba3072017-02-14 16:50:46 +0100130 private boolean mDozing;
Lucas Dupineff8ef02019-06-06 11:14:01 -0700131 private final ViewClippingUtil.ClippingParameters mClippingParams =
132 new ViewClippingUtil.ClippingParameters() {
133 @Override
134 public boolean shouldFinish(View view) {
135 return view == mIndicationArea;
136 }
137 };
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100138
Adrian Roosaf45b602017-03-14 13:10:25 -0700139 /**
140 * Creates a new KeyguardIndicationController and registers callbacks.
141 */
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500142 @Inject
143 KeyguardIndicationController(Context context,
144 WakeLock.Builder wakeLockBuilder,
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400145 KeyguardStateController keyguardStateController,
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700146 StatusBarStateController statusBarStateController,
Jerry Chang6a8fb022019-11-15 06:52:54 +0800147 KeyguardUpdateMonitor keyguardUpdateMonitor,
Lucas Dupin9131b282019-11-19 16:25:03 -0800148 DockManager dockManager,
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400149 BroadcastDispatcher broadcastDispatcher,
150 DevicePolicyManager devicePolicyManager,
arangelovc00bd0c2020-06-19 17:13:59 +0100151 IBatteryStats iBatteryStats,
152 UserManager userManager) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200153 mContext = context;
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400154 mBroadcastDispatcher = broadcastDispatcher;
155 mDevicePolicyManager = devicePolicyManager;
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400156 mKeyguardStateController = keyguardStateController;
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700157 mStatusBarStateController = statusBarStateController;
158 mKeyguardUpdateMonitor = keyguardUpdateMonitor;
Jerry Chang6a8fb022019-11-15 06:52:54 +0800159 mDockManager = dockManager;
Wilson Wu0e727132019-12-26 16:17:56 +0800160 mDockManager.addAlignmentStateListener(
161 alignState -> mHandler.post(() -> handleAlignStateChanged(alignState)));
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500162 mWakeLock = new SettableWakeLock(
163 wakeLockBuilder.setTag("Doze:KeyguardIndication").build(), TAG);
Lucas Dupin9131b282019-11-19 16:25:03 -0800164 mBatteryInfo = iBatteryStats;
arangelovc00bd0c2020-06-19 17:13:59 +0100165 mUserManager = userManager;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600166
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700167 mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
168 mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
169 mStatusBarStateController.addCallback(this);
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400170 mKeyguardStateController.addCallback(this);
Evan Laird878c8532018-10-15 15:54:29 -0400171 }
172
Lucas Dupin00ebe132019-04-26 16:17:56 -0700173 public void setIndicationArea(ViewGroup indicationArea) {
174 mIndicationArea = indicationArea;
175 mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
176 mInitialTextColorState = mTextView != null ?
177 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400178 mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
179 mDisclosureMaxAlpha = mDisclosure.getAlpha();
Lucas Dupin00ebe132019-04-26 16:17:56 -0700180 updateIndication(false /* animate */);
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400181 updateDisclosure();
182
183 if (mBroadcastReceiver == null) {
184 // Update the disclosure proactively to avoid IPC on the critical path.
185 mBroadcastReceiver = new BroadcastReceiver() {
186 @Override
187 public void onReceive(Context context, Intent intent) {
188 updateDisclosure();
189 }
190 };
arangelovc00bd0c2020-06-19 17:13:59 +0100191 IntentFilter intentFilter = new IntentFilter();
192 intentFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
193 intentFilter.addAction(Intent.ACTION_USER_REMOVED);
194 mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter);
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400195 }
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100196 }
197
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500198 public void setLockIconController(LockscreenLockIconController lockIconController) {
199 mLockIconController = lockIconController;
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700200 }
201
Jerry Chang6a8fb022019-11-15 06:52:54 +0800202 private void handleAlignStateChanged(int alignState) {
203 String alignmentIndication = "";
204 if (alignState == DockManager.ALIGN_STATE_POOR) {
205 alignmentIndication =
206 mContext.getResources().getString(R.string.dock_alignment_slow_charging);
207 } else if (alignState == DockManager.ALIGN_STATE_TERRIBLE) {
208 alignmentIndication =
209 mContext.getResources().getString(R.string.dock_alignment_not_charging);
210 }
211 if (!alignmentIndication.equals(mAlignmentIndication)) {
212 mAlignmentIndication = alignmentIndication;
213 updateIndication(false);
214 }
215 }
216
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800217 /**
218 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
219 * {@link KeyguardIndicationController}.
220 *
221 * <p>Subclasses may override this method to extend or change the callback behavior by extending
222 * the {@link BaseKeyguardCallback}.
223 *
224 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
225 * same instance.
226 */
227 protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700228 if (mUpdateMonitorCallback == null) {
229 mUpdateMonitorCallback = new BaseKeyguardCallback();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800230 }
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700231 return mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800232 }
233
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400234 private void updateDisclosure() {
235 // NOTE: Because this uses IPC, avoid calling updateDisclosure() on a critical path.
arangelovc00bd0c2020-06-19 17:13:59 +0100236 if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
237 CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400238 if (organizationName != null) {
239 mDisclosure.switchIndication(mContext.getResources().getString(
240 R.string.do_disclosure_with_name, organizationName));
241 } else {
242 mDisclosure.switchIndication(R.string.do_disclosure_generic);
243 }
244 mDisclosure.setVisibility(View.VISIBLE);
245 } else {
246 mDisclosure.setVisibility(View.GONE);
247 }
248 }
249
arangelovc00bd0c2020-06-19 17:13:59 +0100250 private boolean isOrganizationOwnedDevice() {
251 return mDevicePolicyManager.isDeviceManaged()
252 || mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
253 }
254
255 @Nullable
256 private CharSequence getOrganizationOwnedDeviceOrganizationName() {
257 if (mDevicePolicyManager.isDeviceManaged()) {
258 return mDevicePolicyManager.getDeviceOwnerOrganizationName();
259 } else if (mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()) {
260 return getWorkProfileOrganizationName();
261 }
262 return null;
263 }
264
265 private CharSequence getWorkProfileOrganizationName() {
266 final int profileId = getWorkProfileUserId(UserHandle.myUserId());
267 if (profileId == UserHandle.USER_NULL) {
268 return null;
269 }
270 return mDevicePolicyManager.getOrganizationNameForUser(profileId);
271 }
272
273 private int getWorkProfileUserId(int userId) {
274 for (final UserInfo userInfo : mUserManager.getProfiles(userId)) {
275 if (userInfo.isManagedProfile()) {
276 return userInfo.id;
277 }
278 }
279 return UserHandle.USER_NULL;
280 }
281
Adrian Roos12c1ef52014-06-04 13:54:08 +0200282 public void setVisible(boolean visible) {
283 mVisible = visible;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100284 mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200285 if (visible) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700286 // If this is called after an error message was already shown, we should not clear it.
287 // Otherwise the error message won't be shown
Jerry Chang6a8fb022019-11-15 06:52:54 +0800288 if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700289 hideTransientIndication();
290 }
Beverly8c785892018-01-31 17:25:52 -0500291 updateIndication(false);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700292 } else if (!visible) {
293 // If we unlock and return to keyguard quickly, previous error should not be shown
294 hideTransientIndication();
Adrian Roos12c1ef52014-06-04 13:54:08 +0200295 }
296 }
297
298 /**
299 * Sets the indication that is shown if nothing else is showing.
300 */
301 public void setRestingIndication(String restingIndication) {
302 mRestingIndication = restingIndication;
Beverly8c785892018-01-31 17:25:52 -0500303 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200304 }
305
306 /**
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700307 * Returns the indication text indicating that trust has been granted.
308 *
309 * @return {@code null} or an empty string if a trust indication text should not be shown.
310 */
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700311 @VisibleForTesting
312 String getTrustGrantedIndication() {
Lucas Dupin859f2c82019-04-17 18:30:00 -0700313 return mContext.getString(R.string.keyguard_indication_trust_unlocked);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700314 }
315
316 /**
Scott Warner778db332020-01-21 09:45:56 -0500317 * Sets if the device is plugged in
318 */
319 @VisibleForTesting
320 void setPowerPluggedIn(boolean plugged) {
321 mPowerPluggedIn = plugged;
322 }
323
324 /**
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700325 * Returns the indication text indicating that trust is currently being managed.
326 *
327 * @return {@code null} or an empty string if a trust managed text should not be shown.
328 */
Lucas Dupin859f2c82019-04-17 18:30:00 -0700329 private String getTrustManagedIndication() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700330 return null;
331 }
332
333 /**
Adrian Roos12c1ef52014-06-04 13:54:08 +0200334 * Hides transient indication in {@param delayMs}.
335 */
336 public void hideTransientIndicationDelayed(long delayMs) {
337 mHandler.sendMessageDelayed(
338 mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
339 }
340
341 /**
342 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
343 */
344 public void showTransientIndication(int transientIndication) {
345 showTransientIndication(mContext.getResources().getString(transientIndication));
346 }
347
348 /**
349 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
350 */
Lucas Dupinef886542018-01-03 16:03:07 -0800351 public void showTransientIndication(CharSequence transientIndication) {
Lucas Dupinaff42362020-03-27 16:28:20 -0700352 showTransientIndication(transientIndication, false /* isError */,
Lucas Dupin85ea4202019-11-04 16:01:51 -0800353 false /* hideOnScreenOff */);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700354 }
355
356 /**
357 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
358 */
Lucas Dupin85ea4202019-11-04 16:01:51 -0800359 private void showTransientIndication(CharSequence transientIndication,
Lucas Dupinaff42362020-03-27 16:28:20 -0700360 boolean isError, boolean hideOnScreenOff) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200361 mTransientIndication = transientIndication;
Lucas Dupin85ea4202019-11-04 16:01:51 -0800362 mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null;
Lucas Dupinaff42362020-03-27 16:28:20 -0700363 mTransientTextIsError = isError;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200364 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Lucas Dupin51996bb2019-05-16 17:56:43 -0700365 mHandler.removeMessages(MSG_SWIPE_UP_TO_UNLOCK);
Adrian Roosc1b50322017-02-27 21:07:58 +0100366 if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
367 // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
368 mWakeLock.setAcquired(true);
369 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
370 }
Beverly8c785892018-01-31 17:25:52 -0500371
372 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200373 }
374
375 /**
376 * Hides transient indication.
377 */
378 public void hideTransientIndication() {
379 if (mTransientIndication != null) {
380 mTransientIndication = null;
Lucas Dupin85ea4202019-11-04 16:01:51 -0800381 mHideTransientMessageOnScreenOff = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200382 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Beverly8c785892018-01-31 17:25:52 -0500383 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200384 }
385 }
386
Beverly8c785892018-01-31 17:25:52 -0500387 protected final void updateIndication(boolean animate) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100388 if (TextUtils.isEmpty(mTransientIndication)) {
389 mWakeLock.setAcquired(false);
390 }
391
Adrian Roos12c1ef52014-06-04 13:54:08 +0200392 if (mVisible) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700393 // Walk down a precedence-ordered list of what indication
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600394 // should be shown based on user or device state
Lucas Dupinff6628d2018-10-15 10:12:37 -0700395 if (mDozing) {
Lucas Dupin07ed3df2019-03-26 21:23:59 -0700396 // When dozing we ignore any text color and use white instead, because
397 // colors can be hard to read in low brightness.
398 mTextView.setTextColor(Color.WHITE);
Lucas Dupinff6628d2018-10-15 10:12:37 -0700399 if (!TextUtils.isEmpty(mTransientIndication)) {
Lucas Dupinff6628d2018-10-15 10:12:37 -0700400 mTextView.switchIndication(mTransientIndication);
Jerry Chang6a8fb022019-11-15 06:52:54 +0800401 } else if (!TextUtils.isEmpty(mAlignmentIndication)) {
402 mTextView.switchIndication(mAlignmentIndication);
Wilson Wubb51d092020-04-21 16:00:59 +0800403 mTextView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
Lucas Dupin07ed3df2019-03-26 21:23:59 -0700404 } else if (mPowerPluggedIn) {
405 String indication = computePowerIndication();
406 if (animate) {
407 animateText(mTextView, indication);
408 } else {
409 mTextView.switchIndication(indication);
410 }
411 } else {
412 String percentage = NumberFormat.getPercentInstance()
413 .format(mBatteryLevel / 100f);
414 mTextView.switchIndication(percentage);
Lucas Dupinff6628d2018-10-15 10:12:37 -0700415 }
Lucas Dupinff6628d2018-10-15 10:12:37 -0700416 return;
417 }
418
Jorim Jaggifabc7432017-05-15 02:40:05 +0200419 int userId = KeyguardUpdateMonitor.getCurrentUser();
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700420 String trustGrantedIndication = getTrustGrantedIndication();
421 String trustManagedIndication = getTrustManagedIndication();
Scott Warner778db332020-01-21 09:45:56 -0500422
423 String powerIndication = null;
424 if (mPowerPluggedIn) {
425 powerIndication = computePowerIndication();
426 }
427
Lucas Dupinaff42362020-03-27 16:28:20 -0700428 boolean isError = false;
Lucas Dupin6c6d5732019-08-27 17:36:05 -0700429 if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600430 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600431 } else if (!TextUtils.isEmpty(mTransientIndication)) {
Lucas Dupind9af6312020-03-23 17:30:15 -0700432 if (powerIndication != null && !mTransientIndication.equals(powerIndication)) {
Scott Warner778db332020-01-21 09:45:56 -0500433 String indication = mContext.getResources().getString(
434 R.string.keyguard_indication_trust_unlocked_plugged_in,
435 mTransientIndication, powerIndication);
436 mTextView.switchIndication(indication);
437 } else {
438 mTextView.switchIndication(mTransientIndication);
439 }
Lucas Dupinaff42362020-03-27 16:28:20 -0700440 isError = mTransientTextIsError;
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700441 } else if (!TextUtils.isEmpty(trustGrantedIndication)
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700442 && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
Scott Warner778db332020-01-21 09:45:56 -0500443 if (powerIndication != null) {
444 String indication = mContext.getResources().getString(
445 R.string.keyguard_indication_trust_unlocked_plugged_in,
446 trustGrantedIndication, powerIndication);
447 mTextView.switchIndication(indication);
448 } else {
449 mTextView.switchIndication(trustGrantedIndication);
450 }
Jerry Chang6a8fb022019-11-15 06:52:54 +0800451 } else if (!TextUtils.isEmpty(mAlignmentIndication)) {
452 mTextView.switchIndication(mAlignmentIndication);
Lucas Dupinaff42362020-03-27 16:28:20 -0700453 isError = true;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600454 } else if (mPowerPluggedIn) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600455 if (DEBUG_CHARGING_SPEED) {
Scott Warner778db332020-01-21 09:45:56 -0500456 powerIndication += ", " + (mChargingWattage / 1000) + " mW";
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600457 }
Beverly85499d92018-02-14 15:55:16 -0500458 if (animate) {
Scott Warner778db332020-01-21 09:45:56 -0500459 animateText(mTextView, powerIndication);
Beverly85499d92018-02-14 15:55:16 -0500460 } else {
Scott Warner778db332020-01-21 09:45:56 -0500461 mTextView.switchIndication(powerIndication);
Beverly85499d92018-02-14 15:55:16 -0500462 }
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700463 } else if (!TextUtils.isEmpty(trustManagedIndication)
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700464 && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
465 && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700466 mTextView.switchIndication(trustManagedIndication);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600467 } else {
468 mTextView.switchIndication(mRestingIndication);
Adrian Roos7b043112015-07-10 13:00:33 -0700469 }
Lucas Dupinaff42362020-03-27 16:28:20 -0700470 mTextView.setTextColor(isError ? Utils.getColorError(mContext)
471 : mInitialTextColorState);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200472 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200473 }
474
Beverly85499d92018-02-14 15:55:16 -0500475 // animates textView - textView moves up and bounces down
476 private void animateText(KeyguardIndicationTextView textView, String indication) {
477 int yTranslation = mContext.getResources().getInteger(
478 R.integer.wired_charging_keyguard_text_animation_distance);
479 int animateUpDuration = mContext.getResources().getInteger(
480 R.integer.wired_charging_keyguard_text_animation_duration_up);
481 int animateDownDuration = mContext.getResources().getInteger(
482 R.integer.wired_charging_keyguard_text_animation_duration_down);
Lucas Dupindef43692018-07-02 15:22:58 -0700483 textView.animate().cancel();
Lucas Dupineff8ef02019-06-06 11:14:01 -0700484 ViewClippingUtil.setClippingDeactivated(textView, true, mClippingParams);
Beverly85499d92018-02-14 15:55:16 -0500485 textView.animate()
486 .translationYBy(yTranslation)
487 .setInterpolator(Interpolators.LINEAR)
488 .setDuration(animateUpDuration)
489 .setListener(new AnimatorListenerAdapter() {
Lucas Dupindef43692018-07-02 15:22:58 -0700490 private boolean mCancelled;
491
Beverly85499d92018-02-14 15:55:16 -0500492 @Override
493 public void onAnimationStart(Animator animation) {
494 textView.switchIndication(indication);
495 }
Lucas Dupindef43692018-07-02 15:22:58 -0700496
497 @Override
498 public void onAnimationCancel(Animator animation) {
Robert Snoebergerddfb0652019-06-21 16:41:46 -0400499 textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
Lucas Dupindef43692018-07-02 15:22:58 -0700500 mCancelled = true;
501 }
502
Beverly85499d92018-02-14 15:55:16 -0500503 @Override
504 public void onAnimationEnd(Animator animation) {
Lucas Dupindef43692018-07-02 15:22:58 -0700505 if (mCancelled) {
Lucas Dupineff8ef02019-06-06 11:14:01 -0700506 ViewClippingUtil.setClippingDeactivated(textView, false,
507 mClippingParams);
Lucas Dupindef43692018-07-02 15:22:58 -0700508 return;
509 }
Beverly85499d92018-02-14 15:55:16 -0500510 textView.animate()
511 .setDuration(animateDownDuration)
512 .setInterpolator(Interpolators.BOUNCE)
Robert Snoebergerddfb0652019-06-21 16:41:46 -0400513 .translationY(BOUNCE_ANIMATION_FINAL_Y)
Lucas Dupindef43692018-07-02 15:22:58 -0700514 .setListener(new AnimatorListenerAdapter() {
515 @Override
Lucas Dupineff8ef02019-06-06 11:14:01 -0700516 public void onAnimationEnd(Animator animation) {
Robert Snoebergerddfb0652019-06-21 16:41:46 -0400517 textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
Lucas Dupineff8ef02019-06-06 11:14:01 -0700518 ViewClippingUtil.setClippingDeactivated(textView, false,
519 mClippingParams);
520 }
Lucas Dupindef43692018-07-02 15:22:58 -0700521 });
Beverly85499d92018-02-14 15:55:16 -0500522 }
523 });
524 }
525
Scott Warner778db332020-01-21 09:45:56 -0500526 @VisibleForTesting
527 String computePowerIndication() {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200528 if (mPowerCharged) {
529 return mContext.getResources().getString(R.string.keyguard_charged);
530 }
531
Lucas Dupin9131b282019-11-19 16:25:03 -0800532 final boolean hasChargingTime = mChargingTimeRemaining > 0;
Adrian Roos7b043112015-07-10 13:00:33 -0700533 int chargingId;
Beverly7d7f6992019-02-11 13:58:27 -0500534 if (mPowerPluggedInWired) {
535 switch (mChargingSpeed) {
Raff Tsaif4ea5622019-06-26 16:15:21 +0800536 case BatteryStatus.CHARGING_FAST:
Beverly7d7f6992019-02-11 13:58:27 -0500537 chargingId = hasChargingTime
538 ? R.string.keyguard_indication_charging_time_fast
539 : R.string.keyguard_plugged_in_charging_fast;
540 break;
Raff Tsaif4ea5622019-06-26 16:15:21 +0800541 case BatteryStatus.CHARGING_SLOWLY:
Beverly7d7f6992019-02-11 13:58:27 -0500542 chargingId = hasChargingTime
543 ? R.string.keyguard_indication_charging_time_slowly
544 : R.string.keyguard_plugged_in_charging_slowly;
545 break;
546 default:
547 chargingId = hasChargingTime
548 ? R.string.keyguard_indication_charging_time
549 : R.string.keyguard_plugged_in;
550 break;
551 }
552 } else {
553 chargingId = hasChargingTime
554 ? R.string.keyguard_indication_charging_time_wireless
555 : R.string.keyguard_plugged_in_wireless;
Adrian Roos7b043112015-07-10 13:00:33 -0700556 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700557
Lucas Dupin8d595d22018-03-08 10:34:58 -0800558 String percentage = NumberFormat.getPercentInstance()
559 .format(mBatteryLevel / 100f);
Adrian Roos7e39e592015-09-23 17:03:47 -0700560 if (hasChargingTime) {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800561 // We now have battery percentage in these strings and it's expected that all
562 // locales will also have it in the future. For now, we still have to support the old
563 // format until all languages get the new translations.
Adrian Roos7e39e592015-09-23 17:03:47 -0700564 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
Lucas Dupin9131b282019-11-19 16:25:03 -0800565 mContext, mChargingTimeRemaining);
Lucas Dupin8d595d22018-03-08 10:34:58 -0800566 try {
567 return mContext.getResources().getString(chargingId, chargingTimeFormatted,
568 percentage);
569 } catch (IllegalFormatConversionException e) {
570 return mContext.getResources().getString(chargingId, chargingTimeFormatted);
571 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700572 } else {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800573 // Same as above
574 try {
575 return mContext.getResources().getString(chargingId, percentage);
576 } catch (IllegalFormatConversionException e) {
577 return mContext.getResources().getString(chargingId);
578 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700579 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200580 }
581
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800582 public void setStatusBarKeyguardViewManager(
583 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
584 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
585 }
586
Lucas Dupin7e171e22018-12-20 11:29:35 -0800587 private final KeyguardUpdateMonitorCallback mTickReceiver =
588 new KeyguardUpdateMonitorCallback() {
589 @Override
590 public void onTimeChanged() {
591 if (mVisible) {
592 updateIndication(false /* animate */);
593 }
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800594 }
Lucas Dupin7e171e22018-12-20 11:29:35 -0800595 };
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800596
597 private final Handler mHandler = new Handler() {
598 @Override
599 public void handleMessage(Message msg) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100600 if (msg.what == MSG_HIDE_TRANSIENT) {
601 hideTransientIndication();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200602 } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500603 if (mLockIconController != null) {
604 mLockIconController.setTransientBiometricsError(false);
605 }
Lucas Dupin51996bb2019-05-16 17:56:43 -0700606 } else if (msg.what == MSG_SWIPE_UP_TO_UNLOCK) {
607 showSwipeUpToUnlock();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800608 }
609 }
610 };
611
Lucas Dupin51996bb2019-05-16 17:56:43 -0700612 private void showSwipeUpToUnlock() {
613 if (mDozing) {
614 return;
615 }
616
Lucas Dupin51996bb2019-05-16 17:56:43 -0700617 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Lucas Dupinadce3532019-08-02 11:17:39 -0700618 String message = mContext.getString(R.string.keyguard_retry);
Lucas Dupin51996bb2019-05-16 17:56:43 -0700619 mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
620 } else if (mKeyguardUpdateMonitor.isScreenOn()) {
Lucas Dupin85ea4202019-11-04 16:01:51 -0800621 showTransientIndication(mContext.getString(R.string.keyguard_unlock),
Lucas Dupinaff42362020-03-27 16:28:20 -0700622 false /* isError */, true /* hideOnScreenOff */);
Lucas Dupin51996bb2019-05-16 17:56:43 -0700623 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
624 }
625 }
626
Adrian Roos91ba3072017-02-14 16:50:46 +0100627 public void setDozing(boolean dozing) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200628 if (mDozing == dozing) {
629 return;
630 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100631 mDozing = dozing;
Lucas Dupin85ea4202019-11-04 16:01:51 -0800632 if (mHideTransientMessageOnScreenOff && mDozing) {
633 hideTransientIndication();
634 } else {
635 updateIndication(false);
636 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100637 }
638
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800639 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
640 pw.println("KeyguardIndicationController:");
Lucas Dupinaff42362020-03-27 16:28:20 -0700641 pw.println(" mTransientTextIsError: " + mTransientTextIsError);
Jason Chang2386a372018-04-24 16:05:30 +0800642 pw.println(" mInitialTextColorState: " + mInitialTextColorState);
Beverly2034c832018-03-19 11:18:51 -0400643 pw.println(" mPowerPluggedInWired: " + mPowerPluggedInWired);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800644 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
645 pw.println(" mPowerCharged: " + mPowerCharged);
646 pw.println(" mChargingSpeed: " + mChargingSpeed);
647 pw.println(" mChargingWattage: " + mChargingWattage);
648 pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
649 pw.println(" mDozing: " + mDozing);
650 pw.println(" mBatteryLevel: " + mBatteryLevel);
651 pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
652 pw.println(" computePowerIndication(): " + computePowerIndication());
653 }
654
Evan Laird878c8532018-10-15 15:54:29 -0400655 @Override
656 public void onStateChanged(int newState) {
657 // don't care
658 }
659
660 @Override
661 public void onDozingChanged(boolean isDozing) {
662 setDozing(isDozing);
663 }
664
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700665 @Override
Jeff DeCewa87cddb2020-06-12 12:13:52 -0400666 public void onDozeAmountChanged(float linear, float eased) {
667 mDisclosure.setAlpha((1 - linear) * mDisclosureMaxAlpha);
668 }
669
670 @Override
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400671 public void onUnlockedChanged() {
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700672 updateIndication(!mDozing);
673 }
674
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800675 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
Adrian Roos56021892017-02-27 20:25:09 +0100676 public static final int HIDE_DELAY_MS = 5000;
Selim Cinek3e451942016-07-14 18:07:53 -0700677
Adrian Roos12c1ef52014-06-04 13:54:08 +0200678 @Override
Raff Tsaif4ea5622019-06-26 16:15:21 +0800679 public void onRefreshBatteryInfo(BatteryStatus status) {
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100680 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
Adrian Roos12c1ef52014-06-04 13:54:08 +0200681 || status.status == BatteryManager.BATTERY_STATUS_FULL;
Adrian Roos56021892017-02-27 20:25:09 +0100682 boolean wasPluggedIn = mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400683 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100684 mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200685 mPowerCharged = status.isCharged();
Adrian Roos0c859ae2015-11-23 16:47:50 -0800686 mChargingWattage = status.maxChargingWattage;
Raff Tsaif4ea5622019-06-26 16:15:21 +0800687 mChargingSpeed = status.getChargingSpeed(mContext);
Lucas Dupin4272f442018-01-13 22:00:35 -0800688 mBatteryLevel = status.level;
Lucas Dupin9131b282019-11-19 16:25:03 -0800689 try {
690 mChargingTimeRemaining = mPowerPluggedIn
691 ? mBatteryInfo.computeChargeTimeRemaining() : -1;
692 } catch (RemoteException e) {
693 Log.e(TAG, "Error calling IBatteryStats: ", e);
694 mChargingTimeRemaining = -1;
695 }
Beverly2034c832018-03-19 11:18:51 -0400696 updateIndication(!wasPluggedIn && mPowerPluggedInWired);
Adrian Roosc1b50322017-02-27 21:07:58 +0100697 if (mDozing) {
698 if (!wasPluggedIn && mPowerPluggedIn) {
699 showTransientIndication(computePowerIndication());
700 hideTransientIndicationDelayed(HIDE_DELAY_MS);
701 } else if (wasPluggedIn && !mPowerPluggedIn) {
702 hideTransientIndication();
703 }
Adrian Roos56021892017-02-27 20:25:09 +0100704 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200705 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700706
707 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200708 public void onBiometricHelp(int msgId, String helpString,
709 BiometricSourceType biometricSourceType) {
Haining Chenc06c4812020-01-13 20:38:53 -0800710 // TODO(b/141025588): refactor to reduce repetition of code/comments
711 // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
712 // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
713 // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
714 // check of whether non-strong biometric is allowed
715 if (!mKeyguardUpdateMonitor
716 .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700717 return;
718 }
Lucas Dupin51996bb2019-05-16 17:56:43 -0700719 boolean showSwipeToUnlock =
720 msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700721 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Jason Chang2386a372018-04-24 16:05:30 +0800722 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800723 mInitialTextColorState);
Lucas Dupin85ea4202019-11-04 16:01:51 -0800724 } else if (mKeyguardUpdateMonitor.isScreenOn()) {
Lucas Dupinaff42362020-03-27 16:28:20 -0700725 showTransientIndication(helpString, false /* isError */, showSwipeToUnlock);
Lucas Dupin51996bb2019-05-16 17:56:43 -0700726 if (!showSwipeToUnlock) {
727 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
728 }
729 }
730 if (showSwipeToUnlock) {
731 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SWIPE_UP_TO_UNLOCK),
732 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700733 }
734 }
735
736 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200737 public void onBiometricError(int msgId, String errString,
738 BiometricSourceType biometricSourceType) {
Lucas Dupin85ea4202019-11-04 16:01:51 -0800739 if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700740 return;
741 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700742 animatePadlockError();
Lucas Dupinadce3532019-08-02 11:17:39 -0700743 if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
744 // The face timeout message is not very actionable, let's ask the user to
745 // manually retry.
746 showSwipeUpToUnlock();
747 } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700748 mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
Lucas Dupin85ea4202019-11-04 16:01:51 -0800749 } else if (mKeyguardUpdateMonitor.isScreenOn()) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800750 showTransientIndication(errString);
Selim Cinek3e451942016-07-14 18:07:53 -0700751 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100752 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinek3e451942016-07-14 18:07:53 -0700753 } else {
754 mMessageToShowOnScreenOn = errString;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700755 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700756 }
757
758 private void animatePadlockError() {
Dave Mankoffc0d9a7d2020-02-27 17:15:52 -0500759 if (mLockIconController != null) {
760 mLockIconController.setTransientBiometricsError(true);
761 }
Lucas Dupine54ad1d2019-04-09 17:08:46 -0700762 mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
763 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
764 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700765 }
766
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200767 private boolean shouldSuppressBiometricError(int msgId,
768 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
769 if (biometricSourceType == BiometricSourceType.FINGERPRINT)
770 return shouldSuppressFingerprintError(msgId, updateMonitor);
771 if (biometricSourceType == BiometricSourceType.FACE)
772 return shouldSuppressFaceError(msgId, updateMonitor);
773 return false;
774 }
775
776 private boolean shouldSuppressFingerprintError(int msgId,
777 KeyguardUpdateMonitor updateMonitor) {
Haining Chenc06c4812020-01-13 20:38:53 -0800778 // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
779 // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
780 // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
781 // check of whether non-strong biometric is allowed
782 return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200783 && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
784 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
785 }
786
787 private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
Haining Chenc06c4812020-01-13 20:38:53 -0800788 // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
789 // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
790 // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
791 // check of whether non-strong biometric is allowed
792 return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200793 && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
794 || msgId == FaceManager.FACE_ERROR_CANCELED);
795 }
796
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700797 @Override
Lucas Dupinef886542018-01-03 16:03:07 -0800798 public void onTrustAgentErrorMessage(CharSequence message) {
Lucas Dupinaff42362020-03-27 16:28:20 -0700799 showTransientIndication(message, true /* isError */, false /* hideOnScreenOff */);
Lucas Dupinef886542018-01-03 16:03:07 -0800800 }
801
802 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700803 public void onScreenTurnedOn() {
804 if (mMessageToShowOnScreenOn != null) {
Lucas Dupinaff42362020-03-27 16:28:20 -0700805 showTransientIndication(mMessageToShowOnScreenOn, true /* isError */,
Lucas Dupin85ea4202019-11-04 16:01:51 -0800806 false /* hideOnScreenOff */);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700807 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100808 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700809 mMessageToShowOnScreenOn = null;
810 }
811 }
812
813 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200814 public void onBiometricRunningStateChanged(boolean running,
815 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700816 if (running) {
Lucas Dupin8f3faac2019-03-12 15:28:49 -0700817 // Let's hide any previous messages when authentication starts, otherwise
818 // multiple auth attempts would overlap.
819 hideTransientIndication();
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700820 mMessageToShowOnScreenOn = null;
821 }
822 }
Selim Cinek3e451942016-07-14 18:07:53 -0700823
824 @Override
Haining Chenc06c4812020-01-13 20:38:53 -0800825 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
826 boolean isStrongBiometric) {
827 super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
Kevin Chyn6d793bd2019-03-27 15:36:13 -0700828 mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
Selim Cinek3e451942016-07-14 18:07:53 -0700829 }
830
831 @Override
Lucas Dupin6c6d5732019-08-27 17:36:05 -0700832 public void onUserSwitchComplete(int userId) {
833 if (mVisible) {
834 updateIndication(false);
835 }
836 }
837
838 @Override
Jorim Jaggidadafd42016-09-30 07:20:25 -0700839 public void onUserUnlocked() {
840 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500841 updateIndication(false);
Jorim Jaggidadafd42016-09-30 07:20:25 -0700842 }
843 }
Lucas Dupin71d2fb22019-05-30 18:26:54 -0700844 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200845}