blob: dfbb32e451d60d2dfc73f6aea63161ae415aeb6f [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;
44import com.android.keyguard.KeyguardUpdateMonitor;
45import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jason Monk58be7a62017-02-01 20:17:51 -050046import com.android.settingslib.Utils;
Jason Monk9c7844c2017-01-18 15:21:53 -050047import com.android.systemui.Dependency;
Beverly8c785892018-01-31 17:25:52 -050048import com.android.systemui.Interpolators;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070049import com.android.systemui.R;
Beverly8fdb5332019-02-04 14:29:49 -050050import com.android.systemui.plugins.statusbar.StatusBarStateController;
51import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070052import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
53import com.android.systemui.statusbar.phone.LockIcon;
54import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Zachary Iqbalf50284c2017-01-22 18:54:46 -080055import com.android.systemui.statusbar.policy.UserInfoController;
Adrian Roosc1b50322017-02-27 21:07:58 +010056import com.android.systemui.util.wakelock.SettableWakeLock;
57import com.android.systemui.util.wakelock.WakeLock;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070058
Lucas Dupin3fcdd472018-01-19 19:06:45 -080059import java.io.FileDescriptor;
60import java.io.PrintWriter;
Lucas Dupin4272f442018-01-13 22:00:35 -080061import java.text.NumberFormat;
Lucas Dupin8d595d22018-03-08 10:34:58 -080062import java.util.IllegalFormatConversionException;
Lucas Dupin4272f442018-01-13 22:00:35 -080063
Adrian Roos12c1ef52014-06-04 13:54:08 +020064/**
Selim Cinekcfafe4e2015-08-11 14:58:44 -070065 * Controls the indications and error messages shown on the Keyguard
Adrian Roos12c1ef52014-06-04 13:54:08 +020066 */
Evan Laird878c8532018-10-15 15:54:29 -040067public class KeyguardIndicationController implements StateListener {
Adrian Roos12c1ef52014-06-04 13:54:08 +020068
Adrian Roos0c859ae2015-11-23 16:47:50 -080069 private static final String TAG = "KeyguardIndication";
70 private static final boolean DEBUG_CHARGING_SPEED = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +020071
72 private static final int MSG_HIDE_TRANSIENT = 1;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020073 private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
74 private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
Adrian Roos12c1ef52014-06-04 13:54:08 +020075
76 private final Context mContext;
Lucas Dupin987f1932017-05-13 21:02:52 -070077 private ViewGroup mIndicationArea;
78 private KeyguardIndicationTextView mTextView;
79 private KeyguardIndicationTextView mDisclosure;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060080 private final UserManager mUserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020081 private final IBatteryStats mBatteryInfo;
Adrian Roosc1b50322017-02-27 21:07:58 +010082 private final SettableWakeLock mWakeLock;
Adrian Roos12c1ef52014-06-04 13:54:08 +020083
Adrian Roos7b043112015-07-10 13:00:33 -070084 private final int mSlowThreshold;
85 private final int mFastThreshold;
Lucas Dupin987f1932017-05-13 21:02:52 -070086 private LockIcon mLockIcon;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070087 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Adrian Roos7b043112015-07-10 13:00:33 -070088
Adrian Roos12c1ef52014-06-04 13:54:08 +020089 private String mRestingIndication;
Lucas Dupinef886542018-01-03 16:03:07 -080090 private CharSequence mTransientIndication;
Jason Chang2386a372018-04-24 16:05:30 +080091 private ColorStateList mTransientTextColorState;
92 private ColorStateList mInitialTextColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +020093 private boolean mVisible;
94
95 private boolean mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -040096 private boolean mPowerPluggedInWired;
Adrian Roos12c1ef52014-06-04 13:54:08 +020097 private boolean mPowerCharged;
Adrian Roos7b043112015-07-10 13:00:33 -070098 private int mChargingSpeed;
Adrian Roos0c859ae2015-11-23 16:47:50 -080099 private int mChargingWattage;
Lucas Dupin4272f442018-01-13 22:00:35 -0800100 private int mBatteryLevel;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700101 private String mMessageToShowOnScreenOn;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200102
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700103 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800104
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100105 private final DevicePolicyManager mDevicePolicyManager;
Adrian Roos91ba3072017-02-14 16:50:46 +0100106 private boolean mDozing;
Lucas Dupinff6628d2018-10-15 10:12:37 -0700107 private float mDarkAmount;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100108
Adrian Roosaf45b602017-03-14 13:10:25 -0700109 /**
110 * Creates a new KeyguardIndicationController and registers callbacks.
111 */
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100112 public KeyguardIndicationController(Context context, ViewGroup indicationArea,
113 LockIcon lockIcon) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100114 this(context, indicationArea, lockIcon,
115 WakeLock.createPartial(context, "Doze:KeyguardIndication"));
Adrian Roosaf45b602017-03-14 13:10:25 -0700116
117 registerCallbacks(KeyguardUpdateMonitor.getInstance(context));
Adrian Roosc1b50322017-02-27 21:07:58 +0100118 }
119
Adrian Roosaf45b602017-03-14 13:10:25 -0700120 /**
121 * Creates a new KeyguardIndicationController for testing. Does *not* register callbacks.
122 */
Adrian Roosc1b50322017-02-27 21:07:58 +0100123 @VisibleForTesting
124 KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
125 WakeLock wakeLock) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200126 mContext = context;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100127 mIndicationArea = indicationArea;
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800128 mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
Jason Chang2386a372018-04-24 16:05:30 +0800129 mInitialTextColorState = mTextView != null ?
130 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800131 mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700132 mLockIcon = lockIcon;
Lucas Dupinee4c9b72019-02-18 17:04:58 -0800133 mWakeLock = new SettableWakeLock(wakeLock, TAG);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200134
Adrian Roos7b043112015-07-10 13:00:33 -0700135 Resources res = context.getResources();
136 mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
137 mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
138
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600139 mUserManager = context.getSystemService(UserManager.class);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200140 mBatteryInfo = IBatteryStats.Stub.asInterface(
141 ServiceManager.getService(BatteryStats.SERVICE_NAME));
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600142
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100143 mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
144 Context.DEVICE_POLICY_SERVICE);
145
Adrian Roosaf45b602017-03-14 13:10:25 -0700146 updateDisclosure();
147 }
148
149 private void registerCallbacks(KeyguardUpdateMonitor monitor) {
150 monitor.registerCallback(getKeyguardCallback());
151
Lucas Dupin7e171e22018-12-20 11:29:35 -0800152 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mTickReceiver);
Jason Monkaf08c152018-12-04 11:12:39 -0500153 Dependency.get(StatusBarStateController.class).addCallback(this);
Evan Laird878c8532018-10-15 15:54:29 -0400154 }
155
156 /**
157 * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
158 * controller a chance to unregister itself as a receiver.
159 *
160 * //TODO: This can probably be converted to a fragment and not have to be manually recreated
161 */
162 public void destroy() {
Lucas Dupin7e171e22018-12-20 11:29:35 -0800163 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mTickReceiver);
Jason Monkaf08c152018-12-04 11:12:39 -0500164 Dependency.get(StatusBarStateController.class).removeCallback(this);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100165 }
166
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800167 /**
168 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
169 * {@link KeyguardIndicationController}.
170 *
171 * <p>Subclasses may override this method to extend or change the callback behavior by extending
172 * the {@link BaseKeyguardCallback}.
173 *
174 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
175 * same instance.
176 */
177 protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700178 if (mUpdateMonitorCallback == null) {
179 mUpdateMonitorCallback = new BaseKeyguardCallback();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800180 }
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700181 return mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800182 }
183
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100184 private void updateDisclosure() {
185 if (mDevicePolicyManager == null) {
186 return;
187 }
188
Adrian Roos91ba3072017-02-14 16:50:46 +0100189 if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100190 final CharSequence organizationName =
191 mDevicePolicyManager.getDeviceOwnerOrganizationName();
192 if (organizationName != null) {
193 mDisclosure.switchIndication(mContext.getResources().getString(
194 R.string.do_disclosure_with_name, organizationName));
195 } else {
196 mDisclosure.switchIndication(R.string.do_disclosure_generic);
197 }
198 mDisclosure.setVisibility(View.VISIBLE);
199 } else {
200 mDisclosure.setVisibility(View.GONE);
201 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200202 }
203
204 public void setVisible(boolean visible) {
205 mVisible = visible;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100206 mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200207 if (visible) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700208 // If this is called after an error message was already shown, we should not clear it.
209 // Otherwise the error message won't be shown
210 if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
211 hideTransientIndication();
212 }
Beverly8c785892018-01-31 17:25:52 -0500213 updateIndication(false);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700214 } else if (!visible) {
215 // If we unlock and return to keyguard quickly, previous error should not be shown
216 hideTransientIndication();
Adrian Roos12c1ef52014-06-04 13:54:08 +0200217 }
218 }
219
220 /**
221 * Sets the indication that is shown if nothing else is showing.
222 */
223 public void setRestingIndication(String restingIndication) {
224 mRestingIndication = restingIndication;
Beverly8c785892018-01-31 17:25:52 -0500225 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200226 }
227
228 /**
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800229 * Sets the active controller managing changes and callbacks to user information.
230 */
231 public void setUserInfoController(UserInfoController userInfoController) {
232 }
233
234 /**
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700235 * Returns the indication text indicating that trust has been granted.
236 *
237 * @return {@code null} or an empty string if a trust indication text should not be shown.
238 */
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700239 protected String getTrustGrantedIndication() {
240 return null;
241 }
242
243 /**
244 * Returns the indication text indicating that trust is currently being managed.
245 *
246 * @return {@code null} or an empty string if a trust managed text should not be shown.
247 */
248 protected String getTrustManagedIndication() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700249 return null;
250 }
251
252 /**
Adrian Roos12c1ef52014-06-04 13:54:08 +0200253 * Hides transient indication in {@param delayMs}.
254 */
255 public void hideTransientIndicationDelayed(long delayMs) {
256 mHandler.sendMessageDelayed(
257 mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
258 }
259
260 /**
261 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
262 */
263 public void showTransientIndication(int transientIndication) {
264 showTransientIndication(mContext.getResources().getString(transientIndication));
265 }
266
267 /**
268 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
269 */
Lucas Dupinef886542018-01-03 16:03:07 -0800270 public void showTransientIndication(CharSequence transientIndication) {
Jason Chang2386a372018-04-24 16:05:30 +0800271 showTransientIndication(transientIndication, mInitialTextColorState);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700272 }
273
274 /**
275 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
276 */
Jason Chang2386a372018-04-24 16:05:30 +0800277 public void showTransientIndication(CharSequence transientIndication,
278 ColorStateList textColorState) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200279 mTransientIndication = transientIndication;
Jason Chang2386a372018-04-24 16:05:30 +0800280 mTransientTextColorState = textColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200281 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Adrian Roosc1b50322017-02-27 21:07:58 +0100282 if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
283 // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
284 mWakeLock.setAcquired(true);
285 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
286 }
Beverly8c785892018-01-31 17:25:52 -0500287
288 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200289 }
290
291 /**
292 * Hides transient indication.
293 */
294 public void hideTransientIndication() {
295 if (mTransientIndication != null) {
296 mTransientIndication = null;
297 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Beverly8c785892018-01-31 17:25:52 -0500298 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200299 }
300 }
301
Beverly8c785892018-01-31 17:25:52 -0500302 protected final void updateIndication(boolean animate) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100303 if (TextUtils.isEmpty(mTransientIndication)) {
304 mWakeLock.setAcquired(false);
305 }
306
Adrian Roos12c1ef52014-06-04 13:54:08 +0200307 if (mVisible) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700308 // Walk down a precedence-ordered list of what indication
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600309 // should be shown based on user or device state
Lucas Dupinff6628d2018-10-15 10:12:37 -0700310 if (mDozing) {
311 if (!TextUtils.isEmpty(mTransientIndication)) {
312 mTextView.setTextColor(Color.WHITE);
313 mTextView.switchIndication(mTransientIndication);
314 }
315 updateAlphas();
316 return;
317 }
318
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700319 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200320 int userId = KeyguardUpdateMonitor.getCurrentUser();
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700321 String trustGrantedIndication = getTrustGrantedIndication();
322 String trustManagedIndication = getTrustManagedIndication();
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700323 if (!mUserManager.isUserUnlocked(userId)) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600324 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
Jason Chang2386a372018-04-24 16:05:30 +0800325 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600326 } else if (!TextUtils.isEmpty(mTransientIndication)) {
327 mTextView.switchIndication(mTransientIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800328 mTextView.setTextColor(mTransientTextColorState);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700329 } else if (!TextUtils.isEmpty(trustGrantedIndication)
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700330 && updateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700331 mTextView.switchIndication(trustGrantedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800332 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600333 } else if (mPowerPluggedIn) {
334 String indication = computePowerIndication();
335 if (DEBUG_CHARGING_SPEED) {
336 indication += ", " + (mChargingWattage / 1000) + " mW";
337 }
Jason Chang2386a372018-04-24 16:05:30 +0800338 mTextView.setTextColor(mInitialTextColorState);
Beverly85499d92018-02-14 15:55:16 -0500339 if (animate) {
340 animateText(mTextView, indication);
341 } else {
342 mTextView.switchIndication(indication);
343 }
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700344 } else if (!TextUtils.isEmpty(trustManagedIndication)
345 && updateMonitor.getUserTrustIsManaged(userId)
346 && !updateMonitor.getUserHasTrust(userId)) {
347 mTextView.switchIndication(trustManagedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800348 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600349 } else {
350 mTextView.switchIndication(mRestingIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800351 mTextView.setTextColor(mInitialTextColorState);
Adrian Roos7b043112015-07-10 13:00:33 -0700352 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200353 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200354 }
355
Lucas Dupinff6628d2018-10-15 10:12:37 -0700356 private void updateAlphas() {
357 if (!TextUtils.isEmpty(mTransientIndication)) {
358 mTextView.setAlpha(1f);
359 } else {
360 mTextView.setAlpha(1f - mDarkAmount);
361 }
362 }
363
Beverly85499d92018-02-14 15:55:16 -0500364 // animates textView - textView moves up and bounces down
365 private void animateText(KeyguardIndicationTextView textView, String indication) {
366 int yTranslation = mContext.getResources().getInteger(
367 R.integer.wired_charging_keyguard_text_animation_distance);
368 int animateUpDuration = mContext.getResources().getInteger(
369 R.integer.wired_charging_keyguard_text_animation_duration_up);
370 int animateDownDuration = mContext.getResources().getInteger(
371 R.integer.wired_charging_keyguard_text_animation_duration_down);
Lucas Dupindef43692018-07-02 15:22:58 -0700372 textView.animate().cancel();
373 float translation = textView.getTranslationY();
Beverly85499d92018-02-14 15:55:16 -0500374 textView.animate()
375 .translationYBy(yTranslation)
376 .setInterpolator(Interpolators.LINEAR)
377 .setDuration(animateUpDuration)
378 .setListener(new AnimatorListenerAdapter() {
Lucas Dupindef43692018-07-02 15:22:58 -0700379 private boolean mCancelled;
380
Beverly85499d92018-02-14 15:55:16 -0500381 @Override
382 public void onAnimationStart(Animator animation) {
383 textView.switchIndication(indication);
384 }
Lucas Dupindef43692018-07-02 15:22:58 -0700385
386 @Override
387 public void onAnimationCancel(Animator animation) {
388 textView.setTranslationY(translation);
389 mCancelled = true;
390 }
391
Beverly85499d92018-02-14 15:55:16 -0500392 @Override
393 public void onAnimationEnd(Animator animation) {
Lucas Dupindef43692018-07-02 15:22:58 -0700394 if (mCancelled) {
395 return;
396 }
Beverly85499d92018-02-14 15:55:16 -0500397 textView.animate()
398 .setDuration(animateDownDuration)
399 .setInterpolator(Interpolators.BOUNCE)
Lucas Dupindef43692018-07-02 15:22:58 -0700400 .translationY(translation)
401 .setListener(new AnimatorListenerAdapter() {
402 @Override
403 public void onAnimationCancel(Animator animation) {
404 textView.setTranslationY(translation);
405 }
406 });
Beverly85499d92018-02-14 15:55:16 -0500407 }
408 });
409 }
410
Adrian Roos12c1ef52014-06-04 13:54:08 +0200411 private String computePowerIndication() {
412 if (mPowerCharged) {
413 return mContext.getResources().getString(R.string.keyguard_charged);
414 }
415
416 // Try fetching charging time from battery stats.
Adrian Roos7e39e592015-09-23 17:03:47 -0700417 long chargingTimeRemaining = 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200418 try {
Adrian Roos7e39e592015-09-23 17:03:47 -0700419 chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
420
Adrian Roos12c1ef52014-06-04 13:54:08 +0200421 } catch (RemoteException e) {
422 Log.e(TAG, "Error calling IBatteryStats: ", e);
423 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700424 final boolean hasChargingTime = chargingTimeRemaining > 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200425
Adrian Roos7b043112015-07-10 13:00:33 -0700426 int chargingId;
Beverly7d7f6992019-02-11 13:58:27 -0500427 if (mPowerPluggedInWired) {
428 switch (mChargingSpeed) {
429 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
430 chargingId = hasChargingTime
431 ? R.string.keyguard_indication_charging_time_fast
432 : R.string.keyguard_plugged_in_charging_fast;
433 break;
434 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
435 chargingId = hasChargingTime
436 ? R.string.keyguard_indication_charging_time_slowly
437 : R.string.keyguard_plugged_in_charging_slowly;
438 break;
439 default:
440 chargingId = hasChargingTime
441 ? R.string.keyguard_indication_charging_time
442 : R.string.keyguard_plugged_in;
443 break;
444 }
445 } else {
446 chargingId = hasChargingTime
447 ? R.string.keyguard_indication_charging_time_wireless
448 : R.string.keyguard_plugged_in_wireless;
Adrian Roos7b043112015-07-10 13:00:33 -0700449 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700450
Lucas Dupin8d595d22018-03-08 10:34:58 -0800451 String percentage = NumberFormat.getPercentInstance()
452 .format(mBatteryLevel / 100f);
Adrian Roos7e39e592015-09-23 17:03:47 -0700453 if (hasChargingTime) {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800454 // We now have battery percentage in these strings and it's expected that all
455 // locales will also have it in the future. For now, we still have to support the old
456 // format until all languages get the new translations.
Adrian Roos7e39e592015-09-23 17:03:47 -0700457 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
458 mContext, chargingTimeRemaining);
Lucas Dupin8d595d22018-03-08 10:34:58 -0800459 try {
460 return mContext.getResources().getString(chargingId, chargingTimeFormatted,
461 percentage);
462 } catch (IllegalFormatConversionException e) {
463 return mContext.getResources().getString(chargingId, chargingTimeFormatted);
464 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700465 } else {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800466 // Same as above
467 try {
468 return mContext.getResources().getString(chargingId, percentage);
469 } catch (IllegalFormatConversionException e) {
470 return mContext.getResources().getString(chargingId);
471 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700472 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200473 }
474
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800475 public void setStatusBarKeyguardViewManager(
476 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
477 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
478 }
479
Lucas Dupin7e171e22018-12-20 11:29:35 -0800480 private final KeyguardUpdateMonitorCallback mTickReceiver =
481 new KeyguardUpdateMonitorCallback() {
482 @Override
483 public void onTimeChanged() {
484 if (mVisible) {
485 updateIndication(false /* animate */);
486 }
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800487 }
Lucas Dupin7e171e22018-12-20 11:29:35 -0800488 };
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800489
490 private final Handler mHandler = new Handler() {
491 @Override
492 public void handleMessage(Message msg) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100493 if (msg.what == MSG_HIDE_TRANSIENT) {
494 hideTransientIndication();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200495 } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800496 mLockIcon.setTransientBiometricsError(false);
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800497 }
498 }
499 };
500
Adrian Roos91ba3072017-02-14 16:50:46 +0100501 public void setDozing(boolean dozing) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200502 if (mDozing == dozing) {
503 return;
504 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100505 mDozing = dozing;
Beverly8c785892018-01-31 17:25:52 -0500506 updateIndication(false);
Adrian Roos91ba3072017-02-14 16:50:46 +0100507 updateDisclosure();
508 }
509
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800510 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
511 pw.println("KeyguardIndicationController:");
Jason Chang2386a372018-04-24 16:05:30 +0800512 pw.println(" mTransientTextColorState: " + mTransientTextColorState);
513 pw.println(" mInitialTextColorState: " + mInitialTextColorState);
Beverly2034c832018-03-19 11:18:51 -0400514 pw.println(" mPowerPluggedInWired: " + mPowerPluggedInWired);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800515 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
516 pw.println(" mPowerCharged: " + mPowerCharged);
517 pw.println(" mChargingSpeed: " + mChargingSpeed);
518 pw.println(" mChargingWattage: " + mChargingWattage);
519 pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
520 pw.println(" mDozing: " + mDozing);
521 pw.println(" mBatteryLevel: " + mBatteryLevel);
522 pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
523 pw.println(" computePowerIndication(): " + computePowerIndication());
524 }
525
Lucas Dupinff6628d2018-10-15 10:12:37 -0700526 public void setDarkAmount(float darkAmount) {
527 if (mDarkAmount == darkAmount) {
528 return;
529 }
530 mDarkAmount = darkAmount;
531 updateAlphas();
532 }
533
Evan Laird878c8532018-10-15 15:54:29 -0400534 @Override
535 public void onStateChanged(int newState) {
536 // don't care
537 }
538
539 @Override
540 public void onDozingChanged(boolean isDozing) {
541 setDozing(isDozing);
542 }
543
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800544 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
Adrian Roos56021892017-02-27 20:25:09 +0100545 public static final int HIDE_DELAY_MS = 5000;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800546 private int mLastSuccessiveErrorMessage = -1;
Selim Cinek3e451942016-07-14 18:07:53 -0700547
Adrian Roos12c1ef52014-06-04 13:54:08 +0200548 @Override
549 public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100550 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
Adrian Roos12c1ef52014-06-04 13:54:08 +0200551 || status.status == BatteryManager.BATTERY_STATUS_FULL;
Adrian Roos56021892017-02-27 20:25:09 +0100552 boolean wasPluggedIn = mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400553 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100554 mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200555 mPowerCharged = status.isCharged();
Adrian Roos0c859ae2015-11-23 16:47:50 -0800556 mChargingWattage = status.maxChargingWattage;
Adrian Roos7b043112015-07-10 13:00:33 -0700557 mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
Lucas Dupin4272f442018-01-13 22:00:35 -0800558 mBatteryLevel = status.level;
Beverly2034c832018-03-19 11:18:51 -0400559 updateIndication(!wasPluggedIn && mPowerPluggedInWired);
Adrian Roosc1b50322017-02-27 21:07:58 +0100560 if (mDozing) {
561 if (!wasPluggedIn && mPowerPluggedIn) {
562 showTransientIndication(computePowerIndication());
563 hideTransientIndicationDelayed(HIDE_DELAY_MS);
564 } else if (wasPluggedIn && !mPowerPluggedIn) {
565 hideTransientIndication();
566 }
Adrian Roos56021892017-02-27 20:25:09 +0100567 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200568 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700569
570 @Override
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100571 public void onKeyguardVisibilityChanged(boolean showing) {
572 if (showing) {
573 updateDisclosure();
574 }
575 }
576
577 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200578 public void onBiometricHelp(int msgId, String helpString,
579 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700580 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200581 if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700582 return;
583 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700584 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Jason Chang2386a372018-04-24 16:05:30 +0800585 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800586 mInitialTextColorState);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700587 } else if (updateMonitor.isScreenOn()) {
Lucas Dupinc9e5d762019-01-28 09:34:30 -0800588 mLockIcon.setTransientBiometricsError(true);
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800589 showTransientIndication(helpString);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200590 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
591 mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
592 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
593 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700594 }
Selim Cinek3e451942016-07-14 18:07:53 -0700595 // Help messages indicate that there was actually a try since the last error, so those
596 // are not two successive error messages anymore.
597 mLastSuccessiveErrorMessage = -1;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700598 }
599
600 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200601 public void onBiometricError(int msgId, String errString,
602 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700603 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200604 if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700605 return;
606 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700607 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200608 // When swiping up right after receiving a biometric error, the bouncer calls
Selim Cinek3e451942016-07-14 18:07:53 -0700609 // authenticate leading to the same message being shown again on the bouncer.
610 // We want to avoid this, as it may confuse the user when the message is too
611 // generic.
612 if (mLastSuccessiveErrorMessage != msgId) {
Jason Chang2386a372018-04-24 16:05:30 +0800613 mStatusBarKeyguardViewManager.showBouncerMessage(errString,
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800614 mInitialTextColorState);
Selim Cinek3e451942016-07-14 18:07:53 -0700615 }
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700616 } else if (updateMonitor.isScreenOn()) {
Lucas Dupinc2d11b32019-03-06 16:02:18 -0800617 showTransientIndication(errString);
Selim Cinek3e451942016-07-14 18:07:53 -0700618 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100619 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinek3e451942016-07-14 18:07:53 -0700620 } else {
621 mMessageToShowOnScreenOn = errString;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700622 }
Selim Cinek3e451942016-07-14 18:07:53 -0700623 mLastSuccessiveErrorMessage = msgId;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700624 }
625
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200626 private boolean shouldSuppressBiometricError(int msgId,
627 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
628 if (biometricSourceType == BiometricSourceType.FINGERPRINT)
629 return shouldSuppressFingerprintError(msgId, updateMonitor);
630 if (biometricSourceType == BiometricSourceType.FACE)
631 return shouldSuppressFaceError(msgId, updateMonitor);
632 return false;
633 }
634
635 private boolean shouldSuppressFingerprintError(int msgId,
636 KeyguardUpdateMonitor updateMonitor) {
637 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
638 && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
639 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
640 }
641
642 private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
643 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
644 && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
645 || msgId == FaceManager.FACE_ERROR_CANCELED);
646 }
647
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700648 @Override
Lucas Dupinef886542018-01-03 16:03:07 -0800649 public void onTrustAgentErrorMessage(CharSequence message) {
Jason Chang2386a372018-04-24 16:05:30 +0800650 showTransientIndication(message, Utils.getColorError(mContext));
Lucas Dupinef886542018-01-03 16:03:07 -0800651 }
652
653 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700654 public void onScreenTurnedOn() {
655 if (mMessageToShowOnScreenOn != null) {
Jason Chang2386a372018-04-24 16:05:30 +0800656 showTransientIndication(mMessageToShowOnScreenOn, Utils.getColorError(mContext));
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700657 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100658 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700659 mMessageToShowOnScreenOn = null;
660 }
661 }
662
663 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200664 public void onBiometricRunningStateChanged(boolean running,
665 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700666 if (running) {
667 mMessageToShowOnScreenOn = null;
668 }
669 }
Selim Cinek3e451942016-07-14 18:07:53 -0700670
671 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200672 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
673 super.onBiometricAuthenticated(userId, biometricSourceType);
Selim Cinek3e451942016-07-14 18:07:53 -0700674 mLastSuccessiveErrorMessage = -1;
675 }
676
677 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200678 public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
679 super.onBiometricAuthFailed(biometricSourceType);
Selim Cinek3e451942016-07-14 18:07:53 -0700680 mLastSuccessiveErrorMessage = -1;
681 }
Jorim Jaggidadafd42016-09-30 07:20:25 -0700682
683 @Override
684 public void onUserUnlocked() {
685 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500686 updateIndication(false);
Jorim Jaggidadafd42016-09-30 07:20:25 -0700687 }
688 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200689 };
Adrian Roos12c1ef52014-06-04 13:54:08 +0200690}