blob: 22e8909b4812658d4d2a3a7b567970e09a118147 [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.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
Adrian Roos7b043112015-07-10 13:00:33 -070026import android.content.res.Resources;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070027import android.graphics.Color;
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;
35import android.os.UserHandle;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060036import android.os.UserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020037import android.text.TextUtils;
38import android.text.format.Formatter;
39import android.util.Log;
40import android.view.View;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010041import android.view.ViewGroup;
Adrian Roos12c1ef52014-06-04 13:54:08 +020042
Adrian Roosc1b50322017-02-27 21:07:58 +010043import com.android.internal.annotations.VisibleForTesting;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070044import com.android.internal.app.IBatteryStats;
45import com.android.keyguard.KeyguardUpdateMonitor;
46import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jason Monk58be7a62017-02-01 20:17:51 -050047import com.android.settingslib.Utils;
Jason Monk9c7844c2017-01-18 15:21:53 -050048import com.android.systemui.Dependency;
Beverly8c785892018-01-31 17:25:52 -050049import com.android.systemui.Interpolators;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070050import com.android.systemui.R;
51import 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;
61
Adrian Roos12c1ef52014-06-04 13:54:08 +020062/**
Selim Cinekcfafe4e2015-08-11 14:58:44 -070063 * Controls the indications and error messages shown on the Keyguard
Adrian Roos12c1ef52014-06-04 13:54:08 +020064 */
65public class KeyguardIndicationController {
66
Adrian Roos0c859ae2015-11-23 16:47:50 -080067 private static final String TAG = "KeyguardIndication";
68 private static final boolean DEBUG_CHARGING_SPEED = false;
Adrian Roos12c1ef52014-06-04 13:54:08 +020069
70 private static final int MSG_HIDE_TRANSIENT = 1;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070071 private static final int MSG_CLEAR_FP_MSG = 2;
72 private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
Adrian Roos12c1ef52014-06-04 13:54:08 +020073
74 private final Context mContext;
Lucas Dupin987f1932017-05-13 21:02:52 -070075 private ViewGroup mIndicationArea;
76 private KeyguardIndicationTextView mTextView;
77 private KeyguardIndicationTextView mDisclosure;
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -060078 private final UserManager mUserManager;
Adrian Roos12c1ef52014-06-04 13:54:08 +020079 private final IBatteryStats mBatteryInfo;
Adrian Roosc1b50322017-02-27 21:07:58 +010080 private final SettableWakeLock mWakeLock;
Adrian Roos12c1ef52014-06-04 13:54:08 +020081
Adrian Roos7b043112015-07-10 13:00:33 -070082 private final int mSlowThreshold;
83 private final int mFastThreshold;
Lucas Dupin987f1932017-05-13 21:02:52 -070084 private LockIcon mLockIcon;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070085 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
Adrian Roos7b043112015-07-10 13:00:33 -070086
Adrian Roos12c1ef52014-06-04 13:54:08 +020087 private String mRestingIndication;
Lucas Dupinef886542018-01-03 16:03:07 -080088 private CharSequence mTransientIndication;
Jorim Jaggi27c9b742015-04-09 10:34:49 -070089 private int mTransientTextColor;
Lucas Dupin53d50622017-05-13 15:54:14 -070090 private int mInitialTextColor;
Adrian Roos12c1ef52014-06-04 13:54:08 +020091 private boolean mVisible;
92
93 private boolean mPowerPluggedIn;
94 private boolean mPowerCharged;
Adrian Roos7b043112015-07-10 13:00:33 -070095 private int mChargingSpeed;
Adrian Roos0c859ae2015-11-23 16:47:50 -080096 private int mChargingWattage;
Lucas Dupin4272f442018-01-13 22:00:35 -080097 private int mBatteryLevel;
Selim Cinekcfafe4e2015-08-11 14:58:44 -070098 private String mMessageToShowOnScreenOn;
Adrian Roos12c1ef52014-06-04 13:54:08 +020099
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700100 private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800101
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100102 private final DevicePolicyManager mDevicePolicyManager;
Adrian Roos91ba3072017-02-14 16:50:46 +0100103 private boolean mDozing;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100104
Adrian Roosaf45b602017-03-14 13:10:25 -0700105 /**
106 * Creates a new KeyguardIndicationController and registers callbacks.
107 */
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100108 public KeyguardIndicationController(Context context, ViewGroup indicationArea,
109 LockIcon lockIcon) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100110 this(context, indicationArea, lockIcon,
111 WakeLock.createPartial(context, "Doze:KeyguardIndication"));
Adrian Roosaf45b602017-03-14 13:10:25 -0700112
113 registerCallbacks(KeyguardUpdateMonitor.getInstance(context));
Adrian Roosc1b50322017-02-27 21:07:58 +0100114 }
115
Adrian Roosaf45b602017-03-14 13:10:25 -0700116 /**
117 * Creates a new KeyguardIndicationController for testing. Does *not* register callbacks.
118 */
Adrian Roosc1b50322017-02-27 21:07:58 +0100119 @VisibleForTesting
120 KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
121 WakeLock wakeLock) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200122 mContext = context;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100123 mIndicationArea = indicationArea;
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800124 mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
Lucas Dupin987f1932017-05-13 21:02:52 -0700125 mInitialTextColor = mTextView != null ? mTextView.getCurrentTextColor() : Color.WHITE;
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800126 mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700127 mLockIcon = lockIcon;
Adrian Roosc1b50322017-02-27 21:07:58 +0100128 mWakeLock = new SettableWakeLock(wakeLock);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200129
Adrian Roos7b043112015-07-10 13:00:33 -0700130 Resources res = context.getResources();
131 mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
132 mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
133
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600134 mUserManager = context.getSystemService(UserManager.class);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200135 mBatteryInfo = IBatteryStats.Stub.asInterface(
136 ServiceManager.getService(BatteryStats.SERVICE_NAME));
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600137
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100138 mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
139 Context.DEVICE_POLICY_SERVICE);
140
Adrian Roosaf45b602017-03-14 13:10:25 -0700141 updateDisclosure();
142 }
143
144 private void registerCallbacks(KeyguardUpdateMonitor monitor) {
145 monitor.registerCallback(getKeyguardCallback());
146
147 mContext.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
Jason Monkcd26af72017-01-11 14:32:58 -0500148 new IntentFilter(Intent.ACTION_TIME_TICK), null,
Jason Monk9c7844c2017-01-18 15:21:53 -0500149 Dependency.get(Dependency.TIME_TICK_HANDLER));
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100150 }
151
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800152 /**
153 * Gets the {@link KeyguardUpdateMonitorCallback} instance associated with this
154 * {@link KeyguardIndicationController}.
155 *
156 * <p>Subclasses may override this method to extend or change the callback behavior by extending
157 * the {@link BaseKeyguardCallback}.
158 *
159 * @return A KeyguardUpdateMonitorCallback. Multiple calls to this method <b>must</b> return the
160 * same instance.
161 */
162 protected KeyguardUpdateMonitorCallback getKeyguardCallback() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700163 if (mUpdateMonitorCallback == null) {
164 mUpdateMonitorCallback = new BaseKeyguardCallback();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800165 }
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700166 return mUpdateMonitorCallback;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800167 }
168
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100169 private void updateDisclosure() {
170 if (mDevicePolicyManager == null) {
171 return;
172 }
173
Adrian Roos91ba3072017-02-14 16:50:46 +0100174 if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100175 final CharSequence organizationName =
176 mDevicePolicyManager.getDeviceOwnerOrganizationName();
177 if (organizationName != null) {
178 mDisclosure.switchIndication(mContext.getResources().getString(
179 R.string.do_disclosure_with_name, organizationName));
180 } else {
181 mDisclosure.switchIndication(R.string.do_disclosure_generic);
182 }
183 mDisclosure.setVisibility(View.VISIBLE);
184 } else {
185 mDisclosure.setVisibility(View.GONE);
186 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200187 }
188
189 public void setVisible(boolean visible) {
190 mVisible = visible;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100191 mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200192 if (visible) {
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700193 // If this is called after an error message was already shown, we should not clear it.
194 // Otherwise the error message won't be shown
195 if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
196 hideTransientIndication();
197 }
Beverly8c785892018-01-31 17:25:52 -0500198 updateIndication(false);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700199 } else if (!visible) {
200 // If we unlock and return to keyguard quickly, previous error should not be shown
201 hideTransientIndication();
Adrian Roos12c1ef52014-06-04 13:54:08 +0200202 }
203 }
204
205 /**
206 * Sets the indication that is shown if nothing else is showing.
207 */
208 public void setRestingIndication(String restingIndication) {
209 mRestingIndication = restingIndication;
Beverly8c785892018-01-31 17:25:52 -0500210 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200211 }
212
213 /**
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800214 * Sets the active controller managing changes and callbacks to user information.
215 */
216 public void setUserInfoController(UserInfoController userInfoController) {
217 }
218
219 /**
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700220 * Returns the indication text indicating that trust has been granted.
221 *
222 * @return {@code null} or an empty string if a trust indication text should not be shown.
223 */
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700224 protected String getTrustGrantedIndication() {
225 return null;
226 }
227
228 /**
229 * Returns the indication text indicating that trust is currently being managed.
230 *
231 * @return {@code null} or an empty string if a trust managed text should not be shown.
232 */
233 protected String getTrustManagedIndication() {
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700234 return null;
235 }
236
237 /**
Adrian Roos12c1ef52014-06-04 13:54:08 +0200238 * Hides transient indication in {@param delayMs}.
239 */
240 public void hideTransientIndicationDelayed(long delayMs) {
241 mHandler.sendMessageDelayed(
242 mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
243 }
244
245 /**
246 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
247 */
248 public void showTransientIndication(int transientIndication) {
249 showTransientIndication(mContext.getResources().getString(transientIndication));
250 }
251
252 /**
253 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
254 */
Lucas Dupinef886542018-01-03 16:03:07 -0800255 public void showTransientIndication(CharSequence transientIndication) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700256 showTransientIndication(transientIndication, mInitialTextColor);
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700257 }
258
259 /**
260 * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
261 */
Lucas Dupinef886542018-01-03 16:03:07 -0800262 public void showTransientIndication(CharSequence transientIndication, int textColor) {
Adrian Roos12c1ef52014-06-04 13:54:08 +0200263 mTransientIndication = transientIndication;
Jorim Jaggi27c9b742015-04-09 10:34:49 -0700264 mTransientTextColor = textColor;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200265 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Adrian Roosc1b50322017-02-27 21:07:58 +0100266 if (mDozing && !TextUtils.isEmpty(mTransientIndication)) {
267 // Make sure this doesn't get stuck and burns in. Acquire wakelock until its cleared.
268 mWakeLock.setAcquired(true);
269 hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
270 }
Beverly8c785892018-01-31 17:25:52 -0500271
272 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200273 }
274
275 /**
276 * Hides transient indication.
277 */
278 public void hideTransientIndication() {
279 if (mTransientIndication != null) {
280 mTransientIndication = null;
281 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
Beverly8c785892018-01-31 17:25:52 -0500282 updateIndication(false);
Adrian Roos12c1ef52014-06-04 13:54:08 +0200283 }
284 }
285
Beverly8c785892018-01-31 17:25:52 -0500286 protected final void updateIndication(boolean animate) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100287 if (TextUtils.isEmpty(mTransientIndication)) {
288 mWakeLock.setAcquired(false);
289 }
290
Adrian Roos12c1ef52014-06-04 13:54:08 +0200291 if (mVisible) {
Lucas Dupin53d50622017-05-13 15:54:14 -0700292 // Walk down a precedence-ordered list of what indication
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600293 // should be shown based on user or device state
Adrian Roos91ba3072017-02-14 16:50:46 +0100294 if (mDozing) {
Lucas Dupin4272f442018-01-13 22:00:35 -0800295 mTextView.setTextColor(Color.WHITE);
Adrian Roos91ba3072017-02-14 16:50:46 +0100296 if (!TextUtils.isEmpty(mTransientIndication)) {
Adrian Roos12e112d2017-07-25 16:46:23 +0200297 // When dozing we ignore any text color and use white instead, because
298 // colors can be hard to read in low brightness.
Adrian Roos91ba3072017-02-14 16:50:46 +0100299 mTextView.switchIndication(mTransientIndication);
Lucas Dupin4272f442018-01-13 22:00:35 -0800300 } else if (mPowerPluggedIn) {
301 String indication = computePowerIndication();
Beverly8c785892018-01-31 17:25:52 -0500302 if (animate) {
Beverly85499d92018-02-14 15:55:16 -0500303 animateText(mTextView, indication);
Beverly8c785892018-01-31 17:25:52 -0500304 } else {
305 mTextView.switchIndication(indication);
306 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100307 } else {
Lucas Dupin4272f442018-01-13 22:00:35 -0800308 String percentage = NumberFormat.getPercentInstance()
309 .format(mBatteryLevel / 100f);
310 mTextView.switchIndication(percentage);
Adrian Roos91ba3072017-02-14 16:50:46 +0100311 }
312 return;
313 }
314
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700315 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Jorim Jaggifabc7432017-05-15 02:40:05 +0200316 int userId = KeyguardUpdateMonitor.getCurrentUser();
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700317 String trustGrantedIndication = getTrustGrantedIndication();
318 String trustManagedIndication = getTrustManagedIndication();
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700319 if (!mUserManager.isUserUnlocked(userId)) {
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600320 mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
Lucas Dupin53d50622017-05-13 15:54:14 -0700321 mTextView.setTextColor(mInitialTextColor);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600322 } else if (!TextUtils.isEmpty(mTransientIndication)) {
323 mTextView.switchIndication(mTransientIndication);
324 mTextView.setTextColor(mTransientTextColor);
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700325 } else if (!TextUtils.isEmpty(trustGrantedIndication)
Zachary Iqbal8f4c2422017-04-20 17:56:42 -0700326 && updateMonitor.getUserHasTrust(userId)) {
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700327 mTextView.switchIndication(trustGrantedIndication);
Lucas Dupin53d50622017-05-13 15:54:14 -0700328 mTextView.setTextColor(mInitialTextColor);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600329 } else if (mPowerPluggedIn) {
330 String indication = computePowerIndication();
331 if (DEBUG_CHARGING_SPEED) {
332 indication += ", " + (mChargingWattage / 1000) + " mW";
333 }
Lucas Dupin53d50622017-05-13 15:54:14 -0700334 mTextView.setTextColor(mInitialTextColor);
Beverly85499d92018-02-14 15:55:16 -0500335 if (animate) {
336 animateText(mTextView, indication);
337 } else {
338 mTextView.switchIndication(indication);
339 }
Zachary Iqbaldc05aa02017-05-17 18:52:49 -0700340 } else if (!TextUtils.isEmpty(trustManagedIndication)
341 && updateMonitor.getUserTrustIsManaged(userId)
342 && !updateMonitor.getUserHasTrust(userId)) {
343 mTextView.switchIndication(trustManagedIndication);
Lucas Dupin53d50622017-05-13 15:54:14 -0700344 mTextView.setTextColor(mInitialTextColor);
Jeff Sharkeyb6edaa92016-07-27 15:51:31 -0600345 } else {
346 mTextView.switchIndication(mRestingIndication);
Lucas Dupin53d50622017-05-13 15:54:14 -0700347 mTextView.setTextColor(mInitialTextColor);
Adrian Roos7b043112015-07-10 13:00:33 -0700348 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200349 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200350 }
351
Beverly85499d92018-02-14 15:55:16 -0500352 // animates textView - textView moves up and bounces down
353 private void animateText(KeyguardIndicationTextView textView, String indication) {
354 int yTranslation = mContext.getResources().getInteger(
355 R.integer.wired_charging_keyguard_text_animation_distance);
356 int animateUpDuration = mContext.getResources().getInteger(
357 R.integer.wired_charging_keyguard_text_animation_duration_up);
358 int animateDownDuration = mContext.getResources().getInteger(
359 R.integer.wired_charging_keyguard_text_animation_duration_down);
360 textView.animate()
361 .translationYBy(yTranslation)
362 .setInterpolator(Interpolators.LINEAR)
363 .setDuration(animateUpDuration)
364 .setListener(new AnimatorListenerAdapter() {
365 @Override
366 public void onAnimationStart(Animator animation) {
367 textView.switchIndication(indication);
368 }
369 @Override
370 public void onAnimationEnd(Animator animation) {
371 textView.animate()
372 .setDuration(animateDownDuration)
373 .setInterpolator(Interpolators.BOUNCE)
374 .translationYBy(-1 * yTranslation)
375 .setListener(null);
376 }
377 });
378 }
379
Adrian Roos12c1ef52014-06-04 13:54:08 +0200380 private String computePowerIndication() {
381 if (mPowerCharged) {
382 return mContext.getResources().getString(R.string.keyguard_charged);
383 }
384
385 // Try fetching charging time from battery stats.
Adrian Roos7e39e592015-09-23 17:03:47 -0700386 long chargingTimeRemaining = 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200387 try {
Adrian Roos7e39e592015-09-23 17:03:47 -0700388 chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
389
Adrian Roos12c1ef52014-06-04 13:54:08 +0200390 } catch (RemoteException e) {
391 Log.e(TAG, "Error calling IBatteryStats: ", e);
392 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700393 final boolean hasChargingTime = chargingTimeRemaining > 0;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200394
Adrian Roos7b043112015-07-10 13:00:33 -0700395 int chargingId;
396 switch (mChargingSpeed) {
397 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
Adrian Roos7e39e592015-09-23 17:03:47 -0700398 chargingId = hasChargingTime
Adrian Roosf142cac2015-09-25 15:15:17 -0700399 ? R.string.keyguard_indication_charging_time_fast
Adrian Roos7e39e592015-09-23 17:03:47 -0700400 : R.string.keyguard_plugged_in_charging_fast;
Adrian Roos7b043112015-07-10 13:00:33 -0700401 break;
402 case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
Adrian Roos7e39e592015-09-23 17:03:47 -0700403 chargingId = hasChargingTime
Adrian Roosf142cac2015-09-25 15:15:17 -0700404 ? R.string.keyguard_indication_charging_time_slowly
Adrian Roos7e39e592015-09-23 17:03:47 -0700405 : R.string.keyguard_plugged_in_charging_slowly;
Adrian Roos7b043112015-07-10 13:00:33 -0700406 break;
407 default:
Adrian Roos7e39e592015-09-23 17:03:47 -0700408 chargingId = hasChargingTime
409 ? R.string.keyguard_indication_charging_time
410 : R.string.keyguard_plugged_in;
Adrian Roos7b043112015-07-10 13:00:33 -0700411 break;
412 }
Adrian Roos7e39e592015-09-23 17:03:47 -0700413
414 if (hasChargingTime) {
415 String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
416 mContext, chargingTimeRemaining);
417 return mContext.getResources().getString(chargingId, chargingTimeFormatted);
418 } else {
419 return mContext.getResources().getString(chargingId);
420 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200421 }
422
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800423 public void setStatusBarKeyguardViewManager(
424 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
425 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
426 }
427
Adrian Roosaf45b602017-03-14 13:10:25 -0700428 private final BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800429 @Override
430 public void onReceive(Context context, Intent intent) {
431 mHandler.post(() -> {
432 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500433 updateIndication(false);
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800434 }
435 });
436 }
437 };
438
439 private final Handler mHandler = new Handler() {
440 @Override
441 public void handleMessage(Message msg) {
Adrian Roosc1b50322017-02-27 21:07:58 +0100442 if (msg.what == MSG_HIDE_TRANSIENT) {
443 hideTransientIndication();
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800444 } else if (msg.what == MSG_CLEAR_FP_MSG) {
445 mLockIcon.setTransientFpError(false);
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800446 }
447 }
448 };
449
Adrian Roos91ba3072017-02-14 16:50:46 +0100450 public void setDozing(boolean dozing) {
Jorim Jaggifabc7432017-05-15 02:40:05 +0200451 if (mDozing == dozing) {
452 return;
453 }
Adrian Roos91ba3072017-02-14 16:50:46 +0100454 mDozing = dozing;
Beverly8c785892018-01-31 17:25:52 -0500455 updateIndication(false);
Adrian Roos91ba3072017-02-14 16:50:46 +0100456 updateDisclosure();
457 }
458
Lucas Dupin3fcdd472018-01-19 19:06:45 -0800459 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
460 pw.println("KeyguardIndicationController:");
461 pw.println(" mTransientTextColor: " + Integer.toHexString(mTransientTextColor));
462 pw.println(" mInitialTextColor: " + Integer.toHexString(mInitialTextColor));
463 pw.println(" mPowerPluggedIn: " + mPowerPluggedIn);
464 pw.println(" mPowerCharged: " + mPowerCharged);
465 pw.println(" mChargingSpeed: " + mChargingSpeed);
466 pw.println(" mChargingWattage: " + mChargingWattage);
467 pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
468 pw.println(" mDozing: " + mDozing);
469 pw.println(" mBatteryLevel: " + mBatteryLevel);
470 pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
471 pw.println(" computePowerIndication(): " + computePowerIndication());
472 }
473
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800474 protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
Adrian Roos56021892017-02-27 20:25:09 +0100475 public static final int HIDE_DELAY_MS = 5000;
Zachary Iqbalf50284c2017-01-22 18:54:46 -0800476 private int mLastSuccessiveErrorMessage = -1;
Selim Cinek3e451942016-07-14 18:07:53 -0700477
Adrian Roos12c1ef52014-06-04 13:54:08 +0200478 @Override
479 public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100480 boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
Adrian Roos12c1ef52014-06-04 13:54:08 +0200481 || status.status == BatteryManager.BATTERY_STATUS_FULL;
Adrian Roos56021892017-02-27 20:25:09 +0100482 boolean wasPluggedIn = mPowerPluggedIn;
Adrian Roosad3bc7f2014-10-30 18:29:38 +0100483 mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
Adrian Roos12c1ef52014-06-04 13:54:08 +0200484 mPowerCharged = status.isCharged();
Adrian Roos0c859ae2015-11-23 16:47:50 -0800485 mChargingWattage = status.maxChargingWattage;
Adrian Roos7b043112015-07-10 13:00:33 -0700486 mChargingSpeed = status.getChargingSpeed(mSlowThreshold, mFastThreshold);
Lucas Dupin4272f442018-01-13 22:00:35 -0800487 mBatteryLevel = status.level;
Beverly8c785892018-01-31 17:25:52 -0500488 updateIndication(!wasPluggedIn && mPowerPluggedIn);
Adrian Roosc1b50322017-02-27 21:07:58 +0100489 if (mDozing) {
490 if (!wasPluggedIn && mPowerPluggedIn) {
491 showTransientIndication(computePowerIndication());
492 hideTransientIndicationDelayed(HIDE_DELAY_MS);
493 } else if (wasPluggedIn && !mPowerPluggedIn) {
494 hideTransientIndication();
495 }
Adrian Roos56021892017-02-27 20:25:09 +0100496 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200497 }
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700498
499 @Override
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100500 public void onKeyguardVisibilityChanged(boolean showing) {
501 if (showing) {
502 updateDisclosure();
503 }
504 }
505
506 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700507 public void onFingerprintHelp(int msgId, String helpString) {
508 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
509 if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
510 return;
511 }
Jason Monk58be7a62017-02-01 20:17:51 -0500512 int errorColor = Utils.getColorError(mContext);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700513 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
514 mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700515 } else if (updateMonitor.isScreenOn()) {
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700516 mLockIcon.setTransientFpError(true);
517 showTransientIndication(helpString, errorColor);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700518 hideTransientIndicationDelayed(TRANSIENT_FP_ERROR_TIMEOUT);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700519 mHandler.removeMessages(MSG_CLEAR_FP_MSG);
520 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_FP_MSG),
521 TRANSIENT_FP_ERROR_TIMEOUT);
522 }
Selim Cinek3e451942016-07-14 18:07:53 -0700523 // Help messages indicate that there was actually a try since the last error, so those
524 // are not two successive error messages anymore.
525 mLastSuccessiveErrorMessage = -1;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700526 }
527
528 @Override
529 public void onFingerprintError(int msgId, String errString) {
530 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700531 if ((!updateMonitor.isUnlockingWithFingerprintAllowed()
532 && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700533 || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
534 return;
535 }
Jason Monk58be7a62017-02-01 20:17:51 -0500536 int errorColor = Utils.getColorError(mContext);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700537 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
Selim Cinek3e451942016-07-14 18:07:53 -0700538 // When swiping up right after receiving a fingerprint error, the bouncer calls
539 // authenticate leading to the same message being shown again on the bouncer.
540 // We want to avoid this, as it may confuse the user when the message is too
541 // generic.
542 if (mLastSuccessiveErrorMessage != msgId) {
543 mStatusBarKeyguardViewManager.showBouncerMessage(errString, errorColor);
544 }
Kevin Chyn4c4001c2017-08-25 14:23:36 -0700545 } else if (updateMonitor.isScreenOn()) {
Selim Cinek3e451942016-07-14 18:07:53 -0700546 showTransientIndication(errString, errorColor);
547 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100548 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinek3e451942016-07-14 18:07:53 -0700549 } else {
550 mMessageToShowOnScreenOn = errString;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700551 }
Selim Cinek3e451942016-07-14 18:07:53 -0700552 mLastSuccessiveErrorMessage = msgId;
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700553 }
554
555 @Override
Lucas Dupinef886542018-01-03 16:03:07 -0800556 public void onTrustAgentErrorMessage(CharSequence message) {
557 int errorColor = Utils.getColorError(mContext);
558 showTransientIndication(message, errorColor);
559 }
560
561 @Override
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700562 public void onScreenTurnedOn() {
563 if (mMessageToShowOnScreenOn != null) {
Jason Monk58be7a62017-02-01 20:17:51 -0500564 int errorColor = Utils.getColorError(mContext);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700565 showTransientIndication(mMessageToShowOnScreenOn, errorColor);
566 // We want to keep this message around in case the screen was off
Adrian Roos56021892017-02-27 20:25:09 +0100567 hideTransientIndicationDelayed(HIDE_DELAY_MS);
Selim Cinekcfafe4e2015-08-11 14:58:44 -0700568 mMessageToShowOnScreenOn = null;
569 }
570 }
571
572 @Override
573 public void onFingerprintRunningStateChanged(boolean running) {
574 if (running) {
575 mMessageToShowOnScreenOn = null;
576 }
577 }
Selim Cinek3e451942016-07-14 18:07:53 -0700578
579 @Override
580 public void onFingerprintAuthenticated(int userId) {
581 super.onFingerprintAuthenticated(userId);
582 mLastSuccessiveErrorMessage = -1;
583 }
584
585 @Override
586 public void onFingerprintAuthFailed() {
587 super.onFingerprintAuthFailed();
588 mLastSuccessiveErrorMessage = -1;
589 }
Jorim Jaggidadafd42016-09-30 07:20:25 -0700590
591 @Override
592 public void onUserUnlocked() {
593 if (mVisible) {
Beverly8c785892018-01-31 17:25:52 -0500594 updateIndication(false);
Jorim Jaggidadafd42016-09-30 07:20:25 -0700595 }
596 }
Adrian Roos12c1ef52014-06-04 13:54:08 +0200597 };
Adrian Roos12c1ef52014-06-04 13:54:08 +0200598}