blob: 158430f9ff92e1e0f537d1d7df73bddbbd5b39f5 [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;
Evan Laird878c8532018-10-15 15:54:29 -040050import com.android.systemui.statusbar.StatusBarStateController.StateListener;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070051import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
52import com.android.systemui.statusbar.phone.LockIcon;
53import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Zachary Iqbalf50284c2017-01-22 18:54:46 -080054import com.android.systemui.statusbar.policy.UserInfoController;
Adrian Roosc1b50322017-02-27 21:07:58 +010055import com.android.systemui.util.wakelock.SettableWakeLock;
56import com.android.systemui.util.wakelock.WakeLock;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070057
Lucas Dupin3fcdd472018-01-19 19:06:45 -080058import java.io.FileDescriptor;
59import java.io.PrintWriter;
Lucas Dupin4272f442018-01-13 22:00:35 -080060import java.text.NumberFormat;
Lucas Dupin8d595d22018-03-08 10:34:58 -080061import java.util.IllegalFormatConversionException;
Lucas Dupin4272f442018-01-13 22:00:35 -080062
Adrian Roos12c1ef52014-06-04 13:54:08 +020063/**
Selim Cinekcfafe4e2015-08-11 14:58:44 -070064 * Controls the indications and error messages shown on the Keyguard
Adrian Roos12c1ef52014-06-04 13:54:08 +020065 */
Evan Laird878c8532018-10-15 15:54:29 -040066public class KeyguardIndicationController implements StateListener {
Adrian Roos12c1ef52014-06-04 13:54:08 +020067
Adrian Roos0c859ae2015-11-23 16:47:50 -080068 private static final String TAG = "KeyguardIndication";
69 private static final boolean DEBUG_CHARGING_SPEED = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +020070
71 private static final int MSG_HIDE_TRANSIENT = 1;
Gilad Brettercb51b8b2018-03-22 17:04:51 +020072 private static final int MSG_CLEAR_BIOMETRIC_MSG = 2;
73 private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
Adrian Roos12c1ef52014-06-04 13:54:08 +020074
75 private final Context mContext;
Lucas Dupin987f1932017-05-13 21:02:52 -070076 private ViewGroup mIndicationArea;
77 private KeyguardIndicationTextView mTextView;
78 private KeyguardIndicationTextView mDisclosure;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060079 private final UserManager mUserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020080 private final IBatteryStats mBatteryInfo;
Adrian Roosc1b50322017-02-27 21:07:58 +010081 private final SettableWakeLock mWakeLock;
Adrian Roos12c1ef52014-06-04 13:54:08 +020082
Adrian Roos7b043112015-07-10 13:00:33 -070083 private final int mSlowThreshold;
84 private final int mFastThreshold;
Lucas Dupin987f1932017-05-13 21:02:52 -070085 private LockIcon mLockIcon;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070086 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Adrian Roos7b043112015-07-10 13:00:33 -070087
Adrian Roos12c1ef52014-06-04 13:54:08 +020088 private String mRestingIndication;
Lucas Dupinef886542018-01-03 16:03:07 -080089 private CharSequence mTransientIndication;
Jason Chang2386a372018-04-24 16:05:30 +080090 private ColorStateList mTransientTextColorState;
91 private ColorStateList mInitialTextColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +020092 private boolean mVisible;
93
94 private boolean mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -040095 private boolean mPowerPluggedInWired;
Adrian Roos12c1ef52014-06-04 13:54:08 +020096 private boolean mPowerCharged;
Adrian Roos7b043112015-07-10 13:00:33 -070097 private int mChargingSpeed;
Adrian Roos0c859ae2015-11-23 16:47:50 -080098 private int mChargingWattage;
Lucas Dupin4272f442018-01-13 22:00:35 -080099 private int mBatteryLevel;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700100 private String mMessageToShowOnScreenOn;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200101
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700102 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800103
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100104 private final DevicePolicyManager mDevicePolicyManager;
Adrian Roos91ba3072017-02-14 16:50:46 +0100105 private boolean mDozing;
Lucas Dupinff6628d2018-10-15 10:12:37 -0700106 private float mDarkAmount;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100107
Adrian Roosaf45b602017-03-14 13:10:25 -0700108 /**
109 * Creates a new KeyguardIndicationController and registers callbacks.
110 */
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100111 public KeyguardIndicationController(Context context, ViewGroup indicationArea,
112 LockIcon lockIcon) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100113 this(context, indicationArea, lockIcon,
114 WakeLock.createPartial(context, "Doze:KeyguardIndication"));
Adrian Roosaf45b602017-03-14 13:10:25 -0700115
116 registerCallbacks(KeyguardUpdateMonitor.getInstance(context));
Adrian Roosc1b50322017-02-27 21:07:58 +0100117 }
118
Adrian Roosaf45b602017-03-14 13:10:25 -0700119 /**
120 * Creates a new KeyguardIndicationController for testing. Does *not* register callbacks.
121 */
Adrian Roosc1b50322017-02-27 21:07:58 +0100122 @VisibleForTesting
123 KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
124 WakeLock wakeLock) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200125 mContext = context;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100126 mIndicationArea = indicationArea;
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800127 mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
Jason Chang2386a372018-04-24 16:05:30 +0800128 mInitialTextColorState = mTextView != null ?
129 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800130 mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700131 mLockIcon = lockIcon;
Adrian Roosc1b50322017-02-27 21:07:58 +0100132 mWakeLock = new SettableWakeLock(wakeLock);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200133
Adrian Roos7b043112015-07-10 13:00:33 -0700134 Resources res = context.getResources();
135 mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
136 mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
137
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600138 mUserManager = context.getSystemService(UserManager.class);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200139 mBatteryInfo = IBatteryStats.Stub.asInterface(
140 ServiceManager.getService(BatteryStats.SERVICE_NAME));
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600141
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100142 mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
143 Context.DEVICE_POLICY_SERVICE);
144
Adrian Roosaf45b602017-03-14 13:10:25 -0700145 updateDisclosure();
146 }
147
148 private void registerCallbacks(KeyguardUpdateMonitor monitor) {
149 monitor.registerCallback(getKeyguardCallback());
150
Lucas Dupin7e171e22018-12-20 11:29:35 -0800151 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mTickReceiver);
Jason Monkaf08c152018-12-04 11:12:39 -0500152 Dependency.get(StatusBarStateController.class).addCallback(this);
Evan Laird878c8532018-10-15 15:54:29 -0400153 }
154
155 /**
156 * Used by {@link com.android.systemui.statusbar.phone.StatusBar} to give the indication
157 * controller a chance to unregister itself as a receiver.
158 *
159 * //TODO: This can probably be converted to a fragment and not have to be manually recreated
160 */
161 public void destroy() {
Lucas Dupin7e171e22018-12-20 11:29:35 -0800162 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mTickReceiver);
Jason Monkaf08c152018-12-04 11:12:39 -0500163 Dependency.get(StatusBarStateController.class).removeCallback(this);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100164 }
165
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800166 /**
167 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
168 * {@link KeyguardIndicationController}.
169 *
170 * <p>Subclasses may override this method to extend or change the callback behavior by extending
171 * the {@link BaseKeyguardCallback}.
172 *
173 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
174 * same instance.
175 */
176 protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700177 if (mUpdateMonitorCallback == null) {
178 mUpdateMonitorCallback = new BaseKeyguardCallback();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800179 }
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700180 return mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800181 }
182
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100183 private void updateDisclosure() {
184 if (mDevicePolicyManager == null) {
185 return;
186 }
187
Adrian Roos91ba3072017-02-14 16:50:46 +0100188 if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100189 final CharSequence organizationName =
190 mDevicePolicyManager.getDeviceOwnerOrganizationName();
191 if (organizationName != null) {
192 mDisclosure.switchIndication(mContext.getResources().getString(
193 R.string.do_disclosure_with_name, organizationName));
194 } else {
195 mDisclosure.switchIndication(R.string.do_disclosure_generic);
196 }
197 mDisclosure.setVisibility(View.VISIBLE);
198 } else {
199 mDisclosure.setVisibility(View.GONE);
200 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200201 }
202
203 public void setVisible(boolean visible) {
204 mVisible = visible;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100205 mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200206 if (visible) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700207 // If this is called after an error message was already shown, we should not clear it.
208 // Otherwise the error message won't be shown
209 if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
210 hideTransientIndication();
211 }
Beverly8c785892018-01-31 17:25:52 -0500212 updateIndication(false);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700213 } else if (!visible) {
214 // If we unlock and return to keyguard quickly, previous error should not be shown
215 hideTransientIndication();
Adrian Roos12c1ef52014-06-04 13:54:08 +0200216 }
217 }
218
219 /**
220 * Sets the indication that is shown if nothing else is showing.
221 */
222 public void setRestingIndication(String restingIndication) {
223 mRestingIndication = restingIndication;
Beverly8c785892018-01-31 17:25:52 -0500224 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200225 }
226
227 /**
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800228 * Sets the active controller managing changes and callbacks to user information.
229 */
230 public void setUserInfoController(UserInfoController userInfoController) {
231 }
232
233 /**
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700234 * Returns the indication text indicating that trust has been granted.
235 *
236 * @return {@code null} or an empty string if a trust indication text should not be shown.
237 */
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700238 protected String getTrustGrantedIndication() {
239 return null;
240 }
241
242 /**
243 * Returns the indication text indicating that trust is currently being managed.
244 *
245 * @return {@code null} or an empty string if a trust managed text should not be shown.
246 */
247 protected String getTrustManagedIndication() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700248 return null;
249 }
250
251 /**
Adrian Roos12c1ef52014-06-04 13:54:08 +0200252 * Hides transient indication in {@param delayMs}.
253 */
254 public void hideTransientIndicationDelayed(long delayMs) {
255 mHandler.sendMessageDelayed(
256 mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
257 }
258
259 /**
260 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
261 */
262 public void showTransientIndication(int transientIndication) {
263 showTransientIndication(mContext.getResources().getString(transientIndication));
264 }
265
266 /**
267 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
268 */
Lucas Dupinef886542018-01-03 16:03:07 -0800269 public void showTransientIndication(CharSequence transientIndication) {
Jason Chang2386a372018-04-24 16:05:30 +0800270 showTransientIndication(transientIndication, mInitialTextColorState);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700271 }
272
273 /**
274 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
275 */
Jason Chang2386a372018-04-24 16:05:30 +0800276 public void showTransientIndication(CharSequence transientIndication,
277 ColorStateList textColorState) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200278 mTransientIndication = transientIndication;
Jason Chang2386a372018-04-24 16:05:30 +0800279 mTransientTextColorState = textColorState;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200280 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Adrian Roosc1b50322017-02-27 21:07:58 +0100281 if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
282 // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
283 mWakeLock.setAcquired(true);
284 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
285 }
Beverly8c785892018-01-31 17:25:52 -0500286
287 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200288 }
289
290 /**
291 * Hides transient indication.
292 */
293 public void hideTransientIndication() {
294 if (mTransientIndication != null) {
295 mTransientIndication = null;
296 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Beverly8c785892018-01-31 17:25:52 -0500297 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200298 }
299 }
300
Beverly8c785892018-01-31 17:25:52 -0500301 protected final void updateIndication(boolean animate) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100302 if (TextUtils.isEmpty(mTransientIndication)) {
303 mWakeLock.setAcquired(false);
304 }
305
Adrian Roos12c1ef52014-06-04 13:54:08 +0200306 if (mVisible) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700307 // Walk down a precedence-ordered list of what indication
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600308 // should be shown based on user or device state
Lucas Dupinff6628d2018-10-15 10:12:37 -0700309 if (mDozing) {
310 if (!TextUtils.isEmpty(mTransientIndication)) {
311 mTextView.setTextColor(Color.WHITE);
312 mTextView.switchIndication(mTransientIndication);
313 }
314 updateAlphas();
315 return;
316 }
317
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700318 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200319 int userId = KeyguardUpdateMonitor.getCurrentUser();
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700320 String trustGrantedIndication = getTrustGrantedIndication();
321 String trustManagedIndication = getTrustManagedIndication();
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700322 if (!mUserManager.isUserUnlocked(userId)) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600323 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
Jason Chang2386a372018-04-24 16:05:30 +0800324 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600325 } else if (!TextUtils.isEmpty(mTransientIndication)) {
326 mTextView.switchIndication(mTransientIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800327 mTextView.setTextColor(mTransientTextColorState);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700328 } else if (!TextUtils.isEmpty(trustGrantedIndication)
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700329 && updateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700330 mTextView.switchIndication(trustGrantedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800331 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600332 } else if (mPowerPluggedIn) {
333 String indication = computePowerIndication();
334 if (DEBUG_CHARGING_SPEED) {
335 indication += ", " + (mChargingWattage / 1000) + " mW";
336 }
Jason Chang2386a372018-04-24 16:05:30 +0800337 mTextView.setTextColor(mInitialTextColorState);
Beverly85499d92018-02-14 15:55:16 -0500338 if (animate) {
339 animateText(mTextView, indication);
340 } else {
341 mTextView.switchIndication(indication);
342 }
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700343 } else if (!TextUtils.isEmpty(trustManagedIndication)
344 && updateMonitor.getUserTrustIsManaged(userId)
345 && !updateMonitor.getUserHasTrust(userId)) {
346 mTextView.switchIndication(trustManagedIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800347 mTextView.setTextColor(mInitialTextColorState);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600348 } else {
349 mTextView.switchIndication(mRestingIndication);
Jason Chang2386a372018-04-24 16:05:30 +0800350 mTextView.setTextColor(mInitialTextColorState);
Adrian Roos7b043112015-07-10 13:00:33 -0700351 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200352 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200353 }
354
Lucas Dupinff6628d2018-10-15 10:12:37 -0700355 private void updateAlphas() {
356 if (!TextUtils.isEmpty(mTransientIndication)) {
357 mTextView.setAlpha(1f);
358 } else {
359 mTextView.setAlpha(1f - mDarkAmount);
360 }
361 }
362
Beverly85499d92018-02-14 15:55:16 -0500363 // animates textView - textView moves up and bounces down
364 private void animateText(KeyguardIndicationTextView textView, String indication) {
365 int yTranslation = mContext.getResources().getInteger(
366 R.integer.wired_charging_keyguard_text_animation_distance);
367 int animateUpDuration = mContext.getResources().getInteger(
368 R.integer.wired_charging_keyguard_text_animation_duration_up);
369 int animateDownDuration = mContext.getResources().getInteger(
370 R.integer.wired_charging_keyguard_text_animation_duration_down);
Lucas Dupindef43692018-07-02 15:22:58 -0700371 textView.animate().cancel();
372 float translation = textView.getTranslationY();
Beverly85499d92018-02-14 15:55:16 -0500373 textView.animate()
374 .translationYBy(yTranslation)
375 .setInterpolator(Interpolators.LINEAR)
376 .setDuration(animateUpDuration)
377 .setListener(new AnimatorListenerAdapter() {
Lucas Dupindef43692018-07-02 15:22:58 -0700378 private boolean mCancelled;
379
Beverly85499d92018-02-14 15:55:16 -0500380 @Override
381 public void onAnimationStart(Animator animation) {
382 textView.switchIndication(indication);
383 }
Lucas Dupindef43692018-07-02 15:22:58 -0700384
385 @Override
386 public void onAnimationCancel(Animator animation) {
387 textView.setTranslationY(translation);
388 mCancelled = true;
389 }
390
Beverly85499d92018-02-14 15:55:16 -0500391 @Override
392 public void onAnimationEnd(Animator animation) {
Lucas Dupindef43692018-07-02 15:22:58 -0700393 if (mCancelled) {
394 return;
395 }
Beverly85499d92018-02-14 15:55:16 -0500396 textView.animate()
397 .setDuration(animateDownDuration)
398 .setInterpolator(Interpolators.BOUNCE)
Lucas Dupindef43692018-07-02 15:22:58 -0700399 .translationY(translation)
400 .setListener(new AnimatorListenerAdapter() {
401 @Override
402 public void onAnimationCancel(Animator animation) {
403 textView.setTranslationY(translation);
404 }
405 });
Beverly85499d92018-02-14 15:55:16 -0500406 }
407 });
408 }
409
Adrian Roos12c1ef52014-06-04 13:54:08 +0200410 private String computePowerIndication() {
411 if (mPowerCharged) {
412 return mContext.getResources().getString(R.string.keyguard_charged);
413 }
414
415 // Try fetching charging time from battery stats.
Adrian Roos7e39e592015-09-23 17:03:47 -0700416 long chargingTimeRemaining = 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200417 try {
Adrian Roos7e39e592015-09-23 17:03:47 -0700418 chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
419
Adrian Roos12c1ef52014-06-04 13:54:08 +0200420 } catch (RemoteException e) {
421 Log.e(TAG, "Error calling IBatteryStats: ", e);
422 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700423 final boolean hasChargingTime = chargingTimeRemaining > 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200424
Adrian Roos7b043112015-07-10 13:00:33 -0700425 int chargingId;
426 switch (mChargingSpeed) {
427 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
Adrian Roos7e39e592015-09-23 17:03:47 -0700428 chargingId = hasChargingTime
Adrian Roosf142cac2015-09-25 15:15:17 -0700429 ? R.string.keyguard_indication_charging_time_fast
Adrian Roos7e39e592015-09-23 17:03:47 -0700430 : R.string.keyguard_plugged_in_charging_fast;
Adrian Roos7b043112015-07-10 13:00:33 -0700431 break;
432 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
Adrian Roos7e39e592015-09-23 17:03:47 -0700433 chargingId = hasChargingTime
Adrian Roosf142cac2015-09-25 15:15:17 -0700434 ? R.string.keyguard_indication_charging_time_slowly
Adrian Roos7e39e592015-09-23 17:03:47 -0700435 : R.string.keyguard_plugged_in_charging_slowly;
Adrian Roos7b043112015-07-10 13:00:33 -0700436 break;
437 default:
Adrian Roos7e39e592015-09-23 17:03:47 -0700438 chargingId = hasChargingTime
439 ? R.string.keyguard_indication_charging_time
440 : R.string.keyguard_plugged_in;
Adrian Roos7b043112015-07-10 13:00:33 -0700441 break;
442 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700443
Lucas Dupin8d595d22018-03-08 10:34:58 -0800444 String percentage = NumberFormat.getPercentInstance()
445 .format(mBatteryLevel / 100f);
Adrian Roos7e39e592015-09-23 17:03:47 -0700446 if (hasChargingTime) {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800447 // We now have battery percentage in these strings and it's expected that all
448 // locales will also have it in the future. For now, we still have to support the old
449 // format until all languages get the new translations.
Adrian Roos7e39e592015-09-23 17:03:47 -0700450 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
451 mContext, chargingTimeRemaining);
Lucas Dupin8d595d22018-03-08 10:34:58 -0800452 try {
453 return mContext.getResources().getString(chargingId, chargingTimeFormatted,
454 percentage);
455 } catch (IllegalFormatConversionException e) {
456 return mContext.getResources().getString(chargingId, chargingTimeFormatted);
457 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700458 } else {
Lucas Dupin8d595d22018-03-08 10:34:58 -0800459 // Same as above
460 try {
461 return mContext.getResources().getString(chargingId, percentage);
462 } catch (IllegalFormatConversionException e) {
463 return mContext.getResources().getString(chargingId);
464 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700465 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200466 }
467
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800468 public void setStatusBarKeyguardViewManager(
469 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
470 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
471 }
472
Lucas Dupin7e171e22018-12-20 11:29:35 -0800473 private final KeyguardUpdateMonitorCallback mTickReceiver =
474 new KeyguardUpdateMonitorCallback() {
475 @Override
476 public void onTimeChanged() {
477 if (mVisible) {
478 updateIndication(false /* animate */);
479 }
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800480 }
Lucas Dupin7e171e22018-12-20 11:29:35 -0800481 };
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800482
483 private final Handler mHandler = new Handler() {
484 @Override
485 public void handleMessage(Message msg) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100486 if (msg.what == MSG_HIDE_TRANSIENT) {
487 hideTransientIndication();
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200488 } else if (msg.what == MSG_CLEAR_BIOMETRIC_MSG) {
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800489 mLockIcon.setTransientFpError(false);
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800490 }
491 }
492 };
493
Adrian Roos91ba3072017-02-14 16:50:46 +0100494 public void setDozing(boolean dozing) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200495 if (mDozing == dozing) {
496 return;
497 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100498 mDozing = dozing;
Beverly8c785892018-01-31 17:25:52 -0500499 updateIndication(false);
Adrian Roos91ba3072017-02-14 16:50:46 +0100500 updateDisclosure();
501 }
502
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800503 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
504 pw.println("KeyguardIndicationController:");
Jason Chang2386a372018-04-24 16:05:30 +0800505 pw.println(" mTransientTextColorState: " + mTransientTextColorState);
506 pw.println(" mInitialTextColorState: " + mInitialTextColorState);
Beverly2034c832018-03-19 11:18:51 -0400507 pw.println(" mPowerPluggedInWired: " + mPowerPluggedInWired);
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800508 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
509 pw.println(" mPowerCharged: " + mPowerCharged);
510 pw.println(" mChargingSpeed: " + mChargingSpeed);
511 pw.println(" mChargingWattage: " + mChargingWattage);
512 pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
513 pw.println(" mDozing: " + mDozing);
514 pw.println(" mBatteryLevel: " + mBatteryLevel);
515 pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
516 pw.println(" computePowerIndication(): " + computePowerIndication());
517 }
518
Lucas Dupinff6628d2018-10-15 10:12:37 -0700519 public void setDarkAmount(float darkAmount) {
520 if (mDarkAmount == darkAmount) {
521 return;
522 }
523 mDarkAmount = darkAmount;
524 updateAlphas();
525 }
526
Evan Laird878c8532018-10-15 15:54:29 -0400527 @Override
528 public void onStateChanged(int newState) {
529 // don't care
530 }
531
532 @Override
533 public void onDozingChanged(boolean isDozing) {
534 setDozing(isDozing);
535 }
536
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800537 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
Adrian Roos56021892017-02-27 20:25:09 +0100538 public static final int HIDE_DELAY_MS = 5000;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800539 private int mLastSuccessiveErrorMessage = -1;
Selim Cinek3e451942016-07-14 18:07:53 -0700540
Adrian Roos12c1ef52014-06-04 13:54:08 +0200541 @Override
542 public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100543 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
Adrian Roos12c1ef52014-06-04 13:54:08 +0200544 || status.status == BatteryManager.BATTERY_STATUS_FULL;
Adrian Roos56021892017-02-27 20:25:09 +0100545 boolean wasPluggedIn = mPowerPluggedIn;
Beverly2034c832018-03-19 11:18:51 -0400546 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100547 mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200548 mPowerCharged = status.isCharged();
Adrian Roos0c859ae2015-11-23 16:47:50 -0800549 mChargingWattage = status.maxChargingWattage;
Adrian Roos7b043112015-07-10 13:00:33 -0700550 mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
Lucas Dupin4272f442018-01-13 22:00:35 -0800551 mBatteryLevel = status.level;
Beverly2034c832018-03-19 11:18:51 -0400552 updateIndication(!wasPluggedIn && mPowerPluggedInWired);
Adrian Roosc1b50322017-02-27 21:07:58 +0100553 if (mDozing) {
554 if (!wasPluggedIn && mPowerPluggedIn) {
555 showTransientIndication(computePowerIndication());
556 hideTransientIndicationDelayed(HIDE_DELAY_MS);
557 } else if (wasPluggedIn && !mPowerPluggedIn) {
558 hideTransientIndication();
559 }
Adrian Roos56021892017-02-27 20:25:09 +0100560 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200561 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700562
563 @Override
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100564 public void onKeyguardVisibilityChanged(boolean showing) {
565 if (showing) {
566 updateDisclosure();
567 }
568 }
569
570 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200571 public void onBiometricHelp(int msgId, String helpString,
572 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700573 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200574 if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700575 return;
576 }
Jason Chang2386a372018-04-24 16:05:30 +0800577 ColorStateList errorColorState = Utils.getColorError(mContext);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700578 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Jason Chang2386a372018-04-24 16:05:30 +0800579 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800580 errorColorState);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700581 } else if (updateMonitor.isScreenOn()) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700582 mLockIcon.setTransientFpError(true);
Jason Chang2386a372018-04-24 16:05:30 +0800583 showTransientIndication(helpString, errorColorState);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200584 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
585 mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
586 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
587 TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700588 }
Selim Cinek3e451942016-07-14 18:07:53 -0700589 // Help messages indicate that there was actually a try since the last error, so those
590 // are not two successive error messages anymore.
591 mLastSuccessiveErrorMessage = -1;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700592 }
593
594 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200595 public void onBiometricError(int msgId, String errString,
596 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700597 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200598 if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700599 return;
600 }
Jason Chang2386a372018-04-24 16:05:30 +0800601 ColorStateList errorColorState = Utils.getColorError(mContext);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700602 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200603 // When swiping up right after receiving a biometric error, the bouncer calls
Selim Cinek3e451942016-07-14 18:07:53 -0700604 // authenticate leading to the same message being shown again on the bouncer.
605 // We want to avoid this, as it may confuse the user when the message is too
606 // generic.
607 if (mLastSuccessiveErrorMessage != msgId) {
Jason Chang2386a372018-04-24 16:05:30 +0800608 mStatusBarKeyguardViewManager.showBouncerMessage(errString,
Jason Chang1e4a4bd2018-05-22 17:30:19 +0800609 errorColorState);
Selim Cinek3e451942016-07-14 18:07:53 -0700610 }
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700611 } else if (updateMonitor.isScreenOn()) {
Jason Chang2386a372018-04-24 16:05:30 +0800612 showTransientIndication(errString, errorColorState);
Selim Cinek3e451942016-07-14 18:07:53 -0700613 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100614 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinek3e451942016-07-14 18:07:53 -0700615 } else {
616 mMessageToShowOnScreenOn = errString;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700617 }
Selim Cinek3e451942016-07-14 18:07:53 -0700618 mLastSuccessiveErrorMessage = msgId;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700619 }
620
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200621 private boolean shouldSuppressBiometricError(int msgId,
622 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
623 if (biometricSourceType == BiometricSourceType.FINGERPRINT)
624 return shouldSuppressFingerprintError(msgId, updateMonitor);
625 if (biometricSourceType == BiometricSourceType.FACE)
626 return shouldSuppressFaceError(msgId, updateMonitor);
627 return false;
628 }
629
630 private boolean shouldSuppressFingerprintError(int msgId,
631 KeyguardUpdateMonitor updateMonitor) {
632 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
633 && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
634 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED);
635 }
636
637 private boolean shouldSuppressFaceError(int msgId, KeyguardUpdateMonitor updateMonitor) {
638 return ((!updateMonitor.isUnlockingWithBiometricAllowed()
639 && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
640 || msgId == FaceManager.FACE_ERROR_CANCELED);
641 }
642
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700643 @Override
Lucas Dupinef886542018-01-03 16:03:07 -0800644 public void onTrustAgentErrorMessage(CharSequence message) {
Jason Chang2386a372018-04-24 16:05:30 +0800645 showTransientIndication(message, Utils.getColorError(mContext));
Lucas Dupinef886542018-01-03 16:03:07 -0800646 }
647
648 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700649 public void onScreenTurnedOn() {
650 if (mMessageToShowOnScreenOn != null) {
Jason Chang2386a372018-04-24 16:05:30 +0800651 showTransientIndication(mMessageToShowOnScreenOn, Utils.getColorError(mContext));
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700652 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100653 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700654 mMessageToShowOnScreenOn = null;
655 }
656 }
657
658 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200659 public void onBiometricRunningStateChanged(boolean running,
660 BiometricSourceType biometricSourceType) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700661 if (running) {
662 mMessageToShowOnScreenOn = null;
663 }
664 }
Selim Cinek3e451942016-07-14 18:07:53 -0700665
666 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200667 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
668 super.onBiometricAuthenticated(userId, biometricSourceType);
Selim Cinek3e451942016-07-14 18:07:53 -0700669 mLastSuccessiveErrorMessage = -1;
670 }
671
672 @Override
Gilad Brettercb51b8b2018-03-22 17:04:51 +0200673 public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
674 super.onBiometricAuthFailed(biometricSourceType);
Selim Cinek3e451942016-07-14 18:07:53 -0700675 mLastSuccessiveErrorMessage = -1;
676 }
Jorim Jaggidadafd42016-09-30 07:20:25 -0700677
678 @Override
679 public void onUserUnlocked() {
680 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500681 updateIndication(false);
Jorim Jaggidadafd42016-09-30 07:20:25 -0700682 }
683 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200684 };
Adrian Roos12c1ef52014-06-04 13:54:08 +0200685}