• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.internal.policy.impl;
18 
19 import android.app.admin.DevicePolicyManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.database.ContentObserver;
25 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
26 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
27 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
28 import static android.os.BatteryManager.EXTRA_STATUS;
29 import static android.os.BatteryManager.EXTRA_PLUGGED;
30 import static android.os.BatteryManager.EXTRA_LEVEL;
31 import static android.os.BatteryManager.EXTRA_HEALTH;
32 import android.media.AudioManager;
33 import android.os.BatteryManager;
34 import android.os.Handler;
35 import android.os.Message;
36 import android.provider.Settings;
37 import android.provider.Telephony;
38 import static android.provider.Telephony.Intents.EXTRA_PLMN;
39 import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN;
40 import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN;
41 import static android.provider.Telephony.Intents.EXTRA_SPN;
42 import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION;
43 
44 import com.android.internal.telephony.IccCard;
45 import com.android.internal.telephony.TelephonyIntents;
46 
47 import android.telephony.TelephonyManager;
48 import android.util.Log;
49 import com.android.internal.R;
50 import com.google.android.collect.Lists;
51 
52 import java.util.ArrayList;
53 
54 /**
55  * Watches for updates that may be interesting to the keyguard, and provides
56  * the up to date information as well as a registration for callbacks that care
57  * to be updated.
58  *
59  * Note: under time crunch, this has been extended to include some stuff that
60  * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
61  * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()}
62  * and {@link #clearFailedAttempts()}.  Maybe we should rename this 'KeyguardContext'...
63  */
64 public class KeyguardUpdateMonitor {
65 
66     static private final String TAG = "KeyguardUpdateMonitor";
67     static private final boolean DEBUG = false;
68 
69     /* package */ static final int LOW_BATTERY_THRESHOLD = 20;
70 
71     private final Context mContext;
72 
73     private IccCard.State mSimState = IccCard.State.READY;
74 
75     private boolean mDeviceProvisioned;
76 
77     private BatteryStatus mBatteryStatus;
78 
79     private CharSequence mTelephonyPlmn;
80     private CharSequence mTelephonySpn;
81 
82     private int mFailedAttempts = 0;
83     private int mFailedBiometricUnlockAttempts = 0;
84     private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
85 
86     private boolean mClockVisible;
87 
88     private Handler mHandler;
89 
90     private ArrayList<InfoCallback> mInfoCallbacks = Lists.newArrayList();
91     private ArrayList<SimStateCallback> mSimStateCallbacks = Lists.newArrayList();
92     private ContentObserver mContentObserver;
93     private int mRingMode;
94     private int mPhoneState;
95 
96     // messages for the handler
97     private static final int MSG_TIME_UPDATE = 301;
98     private static final int MSG_BATTERY_UPDATE = 302;
99     private static final int MSG_CARRIER_INFO_UPDATE = 303;
100     private static final int MSG_SIM_STATE_CHANGE = 304;
101     private static final int MSG_RINGER_MODE_CHANGED = 305;
102     private static final int MSG_PHONE_STATE_CHANGED = 306;
103     private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
104     private static final int MSG_DEVICE_PROVISIONED = 308;
105     protected static final int MSG_DPM_STATE_CHANGED = 309;
106     protected static final int MSG_USER_CHANGED = 310;
107 
108     protected static final boolean DEBUG_SIM_STATES = DEBUG || false;
109 
110     /**
111      * When we receive a
112      * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
113      * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
114      * we need a single object to pass to the handler.  This class helps decode
115      * the intent and provide a {@link SimCard.State} result.
116      */
117     private static class SimArgs {
118         public final IccCard.State simState;
119 
SimArgs(IccCard.State state)120         SimArgs(IccCard.State state) {
121             simState = state;
122         }
123 
fromIntent(Intent intent)124         static SimArgs fromIntent(Intent intent) {
125             IccCard.State state;
126             if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
127                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
128             }
129             String stateExtra = intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE);
130             if (IccCard.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
131                 final String absentReason = intent
132                     .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
133 
134                 if (IccCard.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
135                         absentReason)) {
136                     state = IccCard.State.PERM_DISABLED;
137                 } else {
138                     state = IccCard.State.ABSENT;
139                 }
140             } else if (IccCard.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
141                 state = IccCard.State.READY;
142             } else if (IccCard.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
143                 final String lockedReason = intent
144                         .getStringExtra(IccCard.INTENT_KEY_LOCKED_REASON);
145                 if (IccCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
146                     state = IccCard.State.PIN_REQUIRED;
147                 } else if (IccCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
148                     state = IccCard.State.PUK_REQUIRED;
149                 } else {
150                     state = IccCard.State.UNKNOWN;
151                 }
152             } else if (IccCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
153                 state = IccCard.State.NETWORK_LOCKED;
154             } else {
155                 state = IccCard.State.UNKNOWN;
156             }
157             return new SimArgs(state);
158         }
159 
toString()160         public String toString() {
161             return simState.toString();
162         }
163     }
164 
165     private static class BatteryStatus {
166         public final int status;
167         public final int level;
168         public final int plugged;
169         public final int health;
BatteryStatus(int status, int level, int plugged, int health)170         public BatteryStatus(int status, int level, int plugged, int health) {
171             this.status = status;
172             this.level = level;
173             this.plugged = plugged;
174             this.health = health;
175         }
176 
177     }
178 
KeyguardUpdateMonitor(Context context)179     public KeyguardUpdateMonitor(Context context) {
180         mContext = context;
181 
182         mHandler = new Handler() {
183             @Override
184             public void handleMessage(Message msg) {
185                 switch (msg.what) {
186                     case MSG_TIME_UPDATE:
187                         handleTimeUpdate();
188                         break;
189                     case MSG_BATTERY_UPDATE:
190                         handleBatteryUpdate((BatteryStatus) msg.obj);
191                         break;
192                     case MSG_CARRIER_INFO_UPDATE:
193                         handleCarrierInfoUpdate();
194                         break;
195                     case MSG_SIM_STATE_CHANGE:
196                         handleSimStateChange((SimArgs) msg.obj);
197                         break;
198                     case MSG_RINGER_MODE_CHANGED:
199                         handleRingerModeChange(msg.arg1);
200                         break;
201                     case MSG_PHONE_STATE_CHANGED:
202                         handlePhoneStateChanged((String)msg.obj);
203                         break;
204                     case MSG_CLOCK_VISIBILITY_CHANGED:
205                         handleClockVisibilityChanged();
206                         break;
207                     case MSG_DEVICE_PROVISIONED:
208                         handleDeviceProvisioned();
209                         break;
210                     case MSG_DPM_STATE_CHANGED:
211                         handleDevicePolicyManagerStateChanged();
212                         break;
213                     case MSG_USER_CHANGED:
214                         handleUserChanged(msg.arg1);
215                         break;
216                 }
217             }
218         };
219 
220         mDeviceProvisioned = Settings.Secure.getInt(
221                 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
222 
223         // Since device can't be un-provisioned, we only need to register a content observer
224         // to update mDeviceProvisioned when we are...
225         if (!mDeviceProvisioned) {
226             mContentObserver = new ContentObserver(mHandler) {
227                 @Override
228                 public void onChange(boolean selfChange) {
229                     super.onChange(selfChange);
230                     mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(),
231                         Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
232                     if (mDeviceProvisioned) {
233                         mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
234                     }
235                     if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
236                 }
237             };
238 
239             mContext.getContentResolver().registerContentObserver(
240                     Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED),
241                     false, mContentObserver);
242 
243             // prevent a race condition between where we check the flag and where we register the
244             // observer by grabbing the value once again...
245             boolean provisioned = Settings.Secure.getInt(mContext.getContentResolver(),
246                 Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
247             if (provisioned != mDeviceProvisioned) {
248                 mDeviceProvisioned = provisioned;
249                 if (mDeviceProvisioned) {
250                     mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
251                 }
252             }
253         }
254 
255         // take a guess to start
256         mSimState = IccCard.State.READY;
257         mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
258 
259         mTelephonyPlmn = getDefaultPlmn();
260 
261         // setup receiver
262         final IntentFilter filter = new IntentFilter();
263         filter.addAction(Intent.ACTION_TIME_TICK);
264         filter.addAction(Intent.ACTION_TIME_CHANGED);
265         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
266         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
267         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
268         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
269         filter.addAction(SPN_STRINGS_UPDATED_ACTION);
270         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
271         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
272         filter.addAction(Intent.ACTION_USER_SWITCHED);
273         filter.addAction(Intent.ACTION_USER_REMOVED);
274         context.registerReceiver(new BroadcastReceiver() {
275 
276             public void onReceive(Context context, Intent intent) {
277                 final String action = intent.getAction();
278                 if (DEBUG) Log.d(TAG, "received broadcast " + action);
279 
280                 if (Intent.ACTION_TIME_TICK.equals(action)
281                         || Intent.ACTION_TIME_CHANGED.equals(action)
282                         || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
283                     mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
284                 } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) {
285                     mTelephonyPlmn = getTelephonyPlmnFrom(intent);
286                     mTelephonySpn = getTelephonySpnFrom(intent);
287                     mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
288                 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
289                     final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
290                     final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
291                     final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
292                     final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
293                     final Message msg = mHandler.obtainMessage(
294                             MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
295                     mHandler.sendMessage(msg);
296                 } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
297                     if (DEBUG_SIM_STATES) {
298                         Log.v(TAG, "action " + action + " state" +
299                             intent.getStringExtra(IccCard.INTENT_KEY_ICC_STATE));
300                     }
301                     mHandler.sendMessage(mHandler.obtainMessage(
302                             MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
303                 } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
304                     mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
305                             intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
306                 } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
307                     String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
308                     mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
309                 } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
310                         .equals(action)) {
311                     mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
312                 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
313                     mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_CHANGED,
314                             intent.getIntExtra(Intent.EXTRA_USERID, 0), 0));
315                 }
316             }
317         }, filter);
318     }
319 
handleDevicePolicyManagerStateChanged()320     protected void handleDevicePolicyManagerStateChanged() {
321         for (int i = 0; i < mInfoCallbacks.size(); i++) {
322             mInfoCallbacks.get(i).onDevicePolicyManagerStateChanged();
323         }
324     }
325 
handleUserChanged(int userId)326     protected void handleUserChanged(int userId) {
327         for (int i = 0; i < mInfoCallbacks.size(); i++) {
328             mInfoCallbacks.get(i).onUserChanged(userId);
329         }
330     }
331 
handleDeviceProvisioned()332     protected void handleDeviceProvisioned() {
333         for (int i = 0; i < mInfoCallbacks.size(); i++) {
334             mInfoCallbacks.get(i).onDeviceProvisioned();
335         }
336         if (mContentObserver != null) {
337             // We don't need the observer anymore...
338             mContext.getContentResolver().unregisterContentObserver(mContentObserver);
339             mContentObserver = null;
340         }
341     }
342 
handlePhoneStateChanged(String newState)343     protected void handlePhoneStateChanged(String newState) {
344         if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
345         if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
346             mPhoneState = TelephonyManager.CALL_STATE_IDLE;
347         } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
348             mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
349         } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
350             mPhoneState = TelephonyManager.CALL_STATE_RINGING;
351         }
352         for (int i = 0; i < mInfoCallbacks.size(); i++) {
353             mInfoCallbacks.get(i).onPhoneStateChanged(mPhoneState);
354         }
355     }
356 
handleRingerModeChange(int mode)357     protected void handleRingerModeChange(int mode) {
358         if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
359         mRingMode = mode;
360         for (int i = 0; i < mInfoCallbacks.size(); i++) {
361             mInfoCallbacks.get(i).onRingerModeChanged(mode);
362         }
363     }
364 
365     /**
366      * Handle {@link #MSG_TIME_UPDATE}
367      */
handleTimeUpdate()368     private void handleTimeUpdate() {
369         if (DEBUG) Log.d(TAG, "handleTimeUpdate");
370         for (int i = 0; i < mInfoCallbacks.size(); i++) {
371             mInfoCallbacks.get(i).onTimeChanged();
372         }
373     }
374 
375     /**
376      * Handle {@link #MSG_BATTERY_UPDATE}
377      */
handleBatteryUpdate(BatteryStatus batteryStatus)378     private void handleBatteryUpdate(BatteryStatus batteryStatus) {
379         if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
380         final boolean batteryUpdateInteresting =
381                 isBatteryUpdateInteresting(mBatteryStatus, batteryStatus);
382         mBatteryStatus = batteryStatus;
383         if (batteryUpdateInteresting) {
384             for (int i = 0; i < mInfoCallbacks.size(); i++) {
385                 // TODO: pass BatteryStatus object to onRefreshBatteryInfo() instead...
386                 mInfoCallbacks.get(i).onRefreshBatteryInfo(
387                     shouldShowBatteryInfo(),isPluggedIn(batteryStatus), batteryStatus.level);
388             }
389         }
390     }
391 
392     /**
393      * Handle {@link #MSG_CARRIER_INFO_UPDATE}
394      */
handleCarrierInfoUpdate()395     private void handleCarrierInfoUpdate() {
396         if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
397             + ", spn = " + mTelephonySpn);
398 
399         for (int i = 0; i < mInfoCallbacks.size(); i++) {
400             mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
401         }
402     }
403 
404     /**
405      * Handle {@link #MSG_SIM_STATE_CHANGE}
406      */
handleSimStateChange(SimArgs simArgs)407     private void handleSimStateChange(SimArgs simArgs) {
408         final IccCard.State state = simArgs.simState;
409 
410         if (DEBUG) {
411             Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
412                     + "state resolved to " + state.toString());
413         }
414 
415         if (state != IccCard.State.UNKNOWN && state != mSimState) {
416             if (DEBUG_SIM_STATES) Log.v(TAG, "dispatching state: " + state);
417             mSimState = state;
418             for (int i = 0; i < mSimStateCallbacks.size(); i++) {
419                 mSimStateCallbacks.get(i).onSimStateChanged(state);
420             }
421         }
422     }
423 
handleClockVisibilityChanged()424     private void handleClockVisibilityChanged() {
425         if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
426         for (int i = 0; i < mInfoCallbacks.size(); i++) {
427             mInfoCallbacks.get(i).onClockVisibilityChanged();
428         }
429     }
430 
431     /**
432      * @param pluggedIn state from {@link android.os.BatteryManager#EXTRA_PLUGGED}
433      * @return Whether the device is considered "plugged in."
434      */
isPluggedIn(BatteryStatus status)435     private static boolean isPluggedIn(BatteryStatus status) {
436         return status.plugged == BatteryManager.BATTERY_PLUGGED_AC
437                 || status.plugged == BatteryManager.BATTERY_PLUGGED_USB;
438     }
439 
isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current)440     private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
441         final boolean nowPluggedIn = isPluggedIn(current);
442         final boolean wasPluggedIn = isPluggedIn(old);
443         final boolean stateChangedWhilePluggedIn =
444             wasPluggedIn == true && nowPluggedIn == true
445             && (old.status != current.status);
446 
447         // change in plug state is always interesting
448         if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
449             return true;
450         }
451 
452         // change in battery level while plugged in
453         if (nowPluggedIn && old.level != current.level) {
454             return true;
455         }
456 
457         // change where battery needs charging
458         if (!nowPluggedIn && isBatteryLow(current) && current.level != old.level) {
459             return true;
460         }
461         return false;
462     }
463 
isBatteryLow(BatteryStatus status)464     private static boolean isBatteryLow(BatteryStatus status) {
465         return status.level < LOW_BATTERY_THRESHOLD;
466     }
467 
468     /**
469      * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
470      * @return The string to use for the plmn, or null if it should not be shown.
471      */
getTelephonyPlmnFrom(Intent intent)472     private CharSequence getTelephonyPlmnFrom(Intent intent) {
473         if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) {
474             final String plmn = intent.getStringExtra(EXTRA_PLMN);
475             if (plmn != null) {
476                 return plmn;
477             } else {
478                 return getDefaultPlmn();
479             }
480         }
481         return null;
482     }
483 
484     /**
485      * @return The default plmn (no service)
486      */
getDefaultPlmn()487     private CharSequence getDefaultPlmn() {
488         return mContext.getResources().getText(
489                         R.string.lockscreen_carrier_default);
490     }
491 
492     /**
493      * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
494      * @return The string to use for the plmn, or null if it should not be shown.
495      */
getTelephonySpnFrom(Intent intent)496     private CharSequence getTelephonySpnFrom(Intent intent) {
497         if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) {
498             final String spn = intent.getStringExtra(EXTRA_SPN);
499             if (spn != null) {
500                 return spn;
501             }
502         }
503         return null;
504     }
505 
506     /**
507      * Remove the given observer from being registered from any of the kinds
508      * of callbacks.
509      * @param observer The observer to remove (an instance of {@link ConfigurationChangeCallback},
510      *   {@link InfoCallback} or {@link SimStateCallback}
511      */
removeCallback(Object observer)512     public void removeCallback(Object observer) {
513         mInfoCallbacks.remove(observer);
514         mSimStateCallbacks.remove(observer);
515     }
516 
517     /**
518      * Callback for general information relevant to lock screen.
519      */
520     interface InfoCallback {
onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel)521         void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel);
onTimeChanged()522         void onTimeChanged();
523 
524         /**
525          * @param plmn The operator name of the registered network.  May be null if it shouldn't
526          *   be displayed.
527          * @param spn The service provider name.  May be null if it shouldn't be displayed.
528          */
onRefreshCarrierInfo(CharSequence plmn, CharSequence spn)529         void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn);
530 
531         /**
532          * Called when the ringer mode changes.
533          * @param state the current ringer state, as defined in
534          * {@link AudioManager#RINGER_MODE_CHANGED_ACTION}
535          */
onRingerModeChanged(int state)536         void onRingerModeChanged(int state);
537 
538         /**
539          * Called when the phone state changes. String will be one of:
540          * {@link TelephonyManager#EXTRA_STATE_IDLE}
541          * {@link TelephonyManager@EXTRA_STATE_RINGING}
542          * {@link TelephonyManager#EXTRA_STATE_OFFHOOK
543          */
onPhoneStateChanged(int phoneState)544         void onPhoneStateChanged(int phoneState);
545 
546         /**
547          * Called when visibility of lockscreen clock changes, such as when
548          * obscured by a widget.
549          */
onClockVisibilityChanged()550         void onClockVisibilityChanged();
551 
552         /**
553          * Called when the device becomes provisioned
554          */
onDeviceProvisioned()555         void onDeviceProvisioned();
556 
557         /**
558          * Called when the device policy changes.
559          * See {@link DevicePolicyManager#ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED}
560          */
onDevicePolicyManagerStateChanged()561         void onDevicePolicyManagerStateChanged();
562 
563         /**
564          * Called when the user changes.
565          */
onUserChanged(int userId)566         void onUserChanged(int userId);
567     }
568 
569     // Simple class that allows methods to easily be overwritten
570     public static class InfoCallbackImpl implements InfoCallback {
onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel)571         public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
572                 int batteryLevel) {
573         }
574 
onTimeChanged()575         public void onTimeChanged() {
576         }
577 
onRefreshCarrierInfo(CharSequence plmn, CharSequence spn)578         public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
579         }
580 
onRingerModeChanged(int state)581         public void onRingerModeChanged(int state) {
582         }
583 
onPhoneStateChanged(int phoneState)584         public void onPhoneStateChanged(int phoneState) {
585         }
586 
onClockVisibilityChanged()587         public void onClockVisibilityChanged() {
588         }
589 
onDeviceProvisioned()590         public void onDeviceProvisioned() {
591         }
592 
onDevicePolicyManagerStateChanged()593         public void onDevicePolicyManagerStateChanged() {
594         }
595 
onUserChanged(int userId)596         public void onUserChanged(int userId) {
597         }
598     }
599 
600     /**
601      * Callback to notify of sim state change.
602      */
603     interface SimStateCallback {
onSimStateChanged(IccCard.State simState)604         void onSimStateChanged(IccCard.State simState);
605     }
606 
607     /**
608      * Register to receive notifications about general keyguard information
609      * (see {@link InfoCallback}.
610      * @param callback The callback.
611      */
registerInfoCallback(InfoCallback callback)612     public void registerInfoCallback(InfoCallback callback) {
613         if (!mInfoCallbacks.contains(callback)) {
614             mInfoCallbacks.add(callback);
615             // Notify listener of the current state
616             callback.onRefreshBatteryInfo(shouldShowBatteryInfo(),isPluggedIn(mBatteryStatus),
617                     mBatteryStatus.level);
618             callback.onTimeChanged();
619             callback.onRingerModeChanged(mRingMode);
620             callback.onPhoneStateChanged(mPhoneState);
621             callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
622             callback.onClockVisibilityChanged();
623         } else {
624             if (DEBUG) Log.e(TAG, "Object tried to add another INFO callback",
625                     new Exception("Whoops"));
626         }
627     }
628 
629     /**
630      * Register to be notified of sim state changes.
631      * @param callback The callback.
632      */
registerSimStateCallback(SimStateCallback callback)633     public void registerSimStateCallback(SimStateCallback callback) {
634         if (!mSimStateCallbacks.contains(callback)) {
635             mSimStateCallbacks.add(callback);
636             // Notify listener of the current state
637             callback.onSimStateChanged(mSimState);
638         } else {
639             if (DEBUG) Log.e(TAG, "Object tried to add another SIM callback",
640                     new Exception("Whoops"));
641         }
642     }
643 
reportClockVisible(boolean visible)644     public void reportClockVisible(boolean visible) {
645         mClockVisible = visible;
646         mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
647     }
648 
getSimState()649     public IccCard.State getSimState() {
650         return mSimState;
651     }
652 
653     /**
654      * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
655      * have the information earlier than waiting for the intent
656      * broadcast from the telephony code.
657      *
658      * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
659      * through mHandler, this *must* be called from the UI thread.
660      */
reportSimUnlocked()661     public void reportSimUnlocked() {
662         handleSimStateChange(new SimArgs(IccCard.State.READY));
663     }
664 
isDevicePluggedIn()665     public boolean isDevicePluggedIn() {
666         return isPluggedIn(mBatteryStatus);
667     }
668 
isDeviceCharged()669     public boolean isDeviceCharged() {
670         return mBatteryStatus.status == BATTERY_STATUS_FULL
671                 || mBatteryStatus.level >= 100; // in case particular device doesn't flag it
672     }
673 
getBatteryLevel()674     public int getBatteryLevel() {
675         return mBatteryStatus.level;
676     }
677 
shouldShowBatteryInfo()678     public boolean shouldShowBatteryInfo() {
679         return isPluggedIn(mBatteryStatus) || isBatteryLow(mBatteryStatus);
680     }
681 
getTelephonyPlmn()682     public CharSequence getTelephonyPlmn() {
683         return mTelephonyPlmn;
684     }
685 
getTelephonySpn()686     public CharSequence getTelephonySpn() {
687         return mTelephonySpn;
688     }
689 
690     /**
691      * @return Whether the device is provisioned (whether they have gone through
692      *   the setup wizard)
693      */
isDeviceProvisioned()694     public boolean isDeviceProvisioned() {
695         return mDeviceProvisioned;
696     }
697 
getFailedAttempts()698     public int getFailedAttempts() {
699         return mFailedAttempts;
700     }
701 
clearFailedAttempts()702     public void clearFailedAttempts() {
703         mFailedAttempts = 0;
704         mFailedBiometricUnlockAttempts = 0;
705     }
706 
reportFailedAttempt()707     public void reportFailedAttempt() {
708         mFailedAttempts++;
709     }
710 
isClockVisible()711     public boolean isClockVisible() {
712         return mClockVisible;
713     }
714 
getPhoneState()715     public int getPhoneState() {
716         return mPhoneState;
717     }
718 
reportFailedBiometricUnlockAttempt()719     public void reportFailedBiometricUnlockAttempt() {
720         mFailedBiometricUnlockAttempts++;
721     }
722 
getMaxBiometricUnlockAttemptsReached()723     public boolean getMaxBiometricUnlockAttemptsReached() {
724         return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
725     }
726 
isSimLocked()727     public boolean isSimLocked() {
728         return mSimState == IccCard.State.PIN_REQUIRED
729             || mSimState == IccCard.State.PUK_REQUIRED
730             || mSimState == IccCard.State.PERM_DISABLED;
731     }
732 }
733