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
17package com.android.keyguard;
18
19import android.app.ActivityManagerNative;
20import android.app.AlarmManager;
21import android.app.IUserSwitchObserver;
22import android.app.PendingIntent;
23import android.app.admin.DevicePolicyManager;
24import android.app.trust.TrustManager;
25import android.content.BroadcastReceiver;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.database.ContentObserver;
31import android.graphics.Bitmap;
32
33import static android.os.BatteryManager.BATTERY_STATUS_FULL;
34import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
35import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
36import static android.os.BatteryManager.EXTRA_STATUS;
37import static android.os.BatteryManager.EXTRA_PLUGGED;
38import static android.os.BatteryManager.EXTRA_LEVEL;
39import static android.os.BatteryManager.EXTRA_HEALTH;
40
41import android.media.AudioManager;
42import android.os.BatteryManager;
43import android.os.Handler;
44import android.os.IRemoteCallback;
45import android.os.Message;
46import android.os.RemoteException;
47import android.os.UserHandle;
48import android.provider.Settings;
49
50import com.android.internal.telephony.IccCardConstants;
51import com.android.internal.telephony.IccCardConstants.State;
52import com.android.internal.telephony.PhoneConstants;
53import com.android.internal.telephony.TelephonyIntents;
54import com.android.internal.telephony.TelephonyProperties;
55
56import android.service.fingerprint.FingerprintManager;
57import android.service.fingerprint.FingerprintManagerReceiver;
58import android.service.fingerprint.FingerprintUtils;
59import android.telephony.SubscriptionInfo;
60import android.telephony.SubscriptionManager;
61import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
62import android.telephony.TelephonyManager;
63import android.util.Log;
64import android.util.SparseBooleanArray;
65
66import com.google.android.collect.Lists;
67
68import java.lang.ref.WeakReference;
69import java.util.ArrayList;
70import java.util.HashMap;
71import java.util.List;
72import java.util.Map.Entry;
73
74/**
75 * Watches for updates that may be interesting to the keyguard, and provides
76 * the up to date information as well as a registration for callbacks that care
77 * to be updated.
78 *
79 * Note: under time crunch, this has been extended to include some stuff that
80 * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
81 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
82 * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
83 */
84public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
85
86    private static final String TAG = "KeyguardUpdateMonitor";
87    private static final boolean DEBUG = KeyguardConstants.DEBUG;
88    private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
89    private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
90    private static final int LOW_BATTERY_THRESHOLD = 20;
91
92    private static final String ACTION_FACE_UNLOCK_STARTED
93            = "com.android.facelock.FACE_UNLOCK_STARTED";
94    private static final String ACTION_FACE_UNLOCK_STOPPED
95            = "com.android.facelock.FACE_UNLOCK_STOPPED";
96
97    // Callback messages
98    private static final int MSG_TIME_UPDATE = 301;
99    private static final int MSG_BATTERY_UPDATE = 302;
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    private static final int MSG_DPM_STATE_CHANGED = 309;
106    private static final int MSG_USER_SWITCHING = 310;
107    private static final int MSG_USER_REMOVED = 311;
108    private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
109    private static final int MSG_BOOT_COMPLETED = 313;
110    private static final int MSG_USER_SWITCH_COMPLETE = 314;
111    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
112    private static final int MSG_SET_PLAYBACK_STATE = 316;
113    private static final int MSG_USER_INFO_CHANGED = 317;
114    private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
115    private static final int MSG_SCREEN_TURNED_ON = 319;
116    private static final int MSG_SCREEN_TURNED_OFF = 320;
117    private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
118    private static final int MSG_FINGERPRINT_PROCESSED = 323;
119    private static final int MSG_FINGERPRINT_ACQUIRED = 324;
120    private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325;
121    private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326;
122
123    private static KeyguardUpdateMonitor sInstance;
124
125    private final Context mContext;
126    HashMap<Integer, SimData> mSimDatas = new HashMap<Integer, SimData>();
127
128    private int mRingMode;
129    private int mPhoneState;
130    private boolean mKeyguardIsVisible;
131    private boolean mBouncer;
132    private boolean mBootCompleted;
133
134    // Device provisioning state
135    private boolean mDeviceProvisioned;
136
137    // Battery status
138    private BatteryStatus mBatteryStatus;
139
140    // Password attempts
141    private int mFailedAttempts = 0;
142    private int mFailedBiometricUnlockAttempts = 0;
143
144    private boolean mAlternateUnlockEnabled;
145
146    private boolean mClockVisible;
147
148    private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
149            mCallbacks = Lists.newArrayList();
150    private ContentObserver mDeviceProvisionedObserver;
151
152    private boolean mSwitchingUser;
153
154    private boolean mScreenOn;
155    private SubscriptionManager mSubscriptionManager;
156    private List<SubscriptionInfo> mSubscriptionInfo;
157
158    private final Handler mHandler = new Handler() {
159        @Override
160        public void handleMessage(Message msg) {
161            switch (msg.what) {
162                case MSG_TIME_UPDATE:
163                    handleTimeUpdate();
164                    break;
165                case MSG_BATTERY_UPDATE:
166                    handleBatteryUpdate((BatteryStatus) msg.obj);
167                    break;
168                case MSG_SIM_STATE_CHANGE:
169                    handleSimStateChange(msg.arg1, msg.arg2, (State) msg.obj);
170                    break;
171                case MSG_RINGER_MODE_CHANGED:
172                    handleRingerModeChange(msg.arg1);
173                    break;
174                case MSG_PHONE_STATE_CHANGED:
175                    handlePhoneStateChanged((String) msg.obj);
176                    break;
177                case MSG_CLOCK_VISIBILITY_CHANGED:
178                    handleClockVisibilityChanged();
179                    break;
180                case MSG_DEVICE_PROVISIONED:
181                    handleDeviceProvisioned();
182                    break;
183                case MSG_DPM_STATE_CHANGED:
184                    handleDevicePolicyManagerStateChanged();
185                    break;
186                case MSG_USER_SWITCHING:
187                    handleUserSwitching(msg.arg1, (IRemoteCallback) msg.obj);
188                    break;
189                case MSG_USER_SWITCH_COMPLETE:
190                    handleUserSwitchComplete(msg.arg1);
191                    break;
192                case MSG_USER_REMOVED:
193                    handleUserRemoved(msg.arg1);
194                    break;
195                case MSG_KEYGUARD_VISIBILITY_CHANGED:
196                    handleKeyguardVisibilityChanged(msg.arg1);
197                    break;
198                case MSG_KEYGUARD_BOUNCER_CHANGED:
199                    handleKeyguardBouncerChanged(msg.arg1);
200                    break;
201                case MSG_BOOT_COMPLETED:
202                    handleBootCompleted();
203                    break;
204                case MSG_USER_INFO_CHANGED:
205                    handleUserInfoChanged(msg.arg1);
206                    break;
207                case MSG_REPORT_EMERGENCY_CALL_ACTION:
208                    handleReportEmergencyCallAction();
209                    break;
210                case MSG_SCREEN_TURNED_OFF:
211                    handleScreenTurnedOff(msg.arg1);
212                    break;
213                case MSG_SCREEN_TURNED_ON:
214                    handleScreenTurnedOn();
215                    break;
216                case MSG_FINGERPRINT_ACQUIRED:
217                    handleFingerprintAcquired(msg.arg1);
218                    break;
219                case MSG_FINGERPRINT_PROCESSED:
220                    handleFingerprintProcessed(msg.arg1);
221                    break;
222                case MSG_FACE_UNLOCK_STATE_CHANGED:
223                    handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
224                    break;
225                case MSG_SIM_SUBSCRIPTION_INFO_CHANGED:
226                    handleSimSubscriptionInfoChanged();
227                    break;
228            }
229        }
230    };
231
232    private OnSubscriptionsChangedListener mSubscriptionListener =
233            new OnSubscriptionsChangedListener() {
234        @Override
235        public void onSubscriptionsChanged() {
236            mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
237        }
238    };
239
240    private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
241    private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
242    private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
243    private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
244
245    @Override
246    public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
247        mUserHasTrust.put(userId, enabled);
248
249        for (int i = 0; i < mCallbacks.size(); i++) {
250            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
251            if (cb != null) {
252                cb.onTrustChanged(userId);
253                if (enabled && initiatedByUser) {
254                    cb.onTrustInitiatedByUser(userId);
255                }
256            }
257        }
258    }
259
260    protected void handleSimSubscriptionInfoChanged() {
261        if (DEBUG_SIM_STATES) {
262            Log.v(TAG, "onSubscriptionInfoChanged()");
263            List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList();
264            if (sil != null) {
265                for (SubscriptionInfo subInfo : sil) {
266                    Log.v(TAG, "SubInfo:" + subInfo);
267                }
268            } else {
269                Log.v(TAG, "onSubscriptionInfoChanged: list is null");
270            }
271        }
272        List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */);
273
274        // Hack level over 9000: Because the subscription id is not yet valid when we see the
275        // first update in handleSimStateChange, we need to force refresh all all SIM states
276        // so the subscription id for them is consistent.
277        ArrayList<SubscriptionInfo> changedSubscriptions = new ArrayList<>();
278        for (int i = 0; i < subscriptionInfos.size(); i++) {
279            SubscriptionInfo info = subscriptionInfos.get(i);
280            boolean changed = refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex());
281            if (changed) {
282                changedSubscriptions.add(info);
283            }
284        }
285        for (int i = 0; i < changedSubscriptions.size(); i++) {
286            SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
287            for (int j = 0; j < mCallbacks.size(); j++) {
288                KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
289                if (cb != null) {
290                    cb.onSimStateChanged(data.subId, data.slotId, data.simState);
291                }
292            }
293        }
294        for (int j = 0; j < mCallbacks.size(); j++) {
295            KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
296            if (cb != null) {
297                cb.onRefreshCarrierInfo();
298            }
299        }
300    }
301
302    /** @return List of SubscriptionInfo records, maybe empty but never null */
303    List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
304        List<SubscriptionInfo> sil = mSubscriptionInfo;
305        if (sil == null || forceReload) {
306            sil = mSubscriptionManager.getActiveSubscriptionInfoList();
307        }
308        if (sil == null) {
309            // getActiveSubscriptionInfoList was null callers expect an empty list.
310            mSubscriptionInfo = new ArrayList<SubscriptionInfo>();
311        } else {
312            mSubscriptionInfo = sil;
313        }
314        return mSubscriptionInfo;
315    }
316
317    @Override
318    public void onTrustManagedChanged(boolean managed, int userId) {
319        mUserTrustIsManaged.put(userId, managed);
320
321        for (int i = 0; i < mCallbacks.size(); i++) {
322            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
323            if (cb != null) {
324                cb.onTrustManagedChanged(userId);
325            }
326        }
327    }
328
329    private void onFingerprintRecognized(int userId) {
330        mUserFingerprintRecognized.put(userId, true);
331        for (int i = 0; i < mCallbacks.size(); i++) {
332            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
333            if (cb != null) {
334                cb.onFingerprintRecognized(userId);
335            }
336        }
337    }
338
339    private void handleFingerprintProcessed(int fingerprintId) {
340        if (fingerprintId == 0) return; // not a valid fingerprint
341
342        final int userId;
343        try {
344            userId = ActivityManagerNative.getDefault().getCurrentUser().id;
345        } catch (RemoteException e) {
346            Log.e(TAG, "Failed to get current user id: ", e);
347            return;
348        }
349        if (isFingerprintDisabled(userId)) {
350            Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
351            return;
352        }
353        final ContentResolver res = mContext.getContentResolver();
354        final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
355        for (int i = 0; i < ids.length; i++) {
356            if (ids[i] == fingerprintId) {
357                onFingerprintRecognized(userId);
358            }
359        }
360    }
361
362    private void handleFingerprintAcquired(int info) {
363        for (int i = 0; i < mCallbacks.size(); i++) {
364            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
365            if (cb != null) {
366                cb.onFingerprintAcquired(info);
367            }
368        }
369    }
370
371    private void handleFaceUnlockStateChanged(boolean running, int userId) {
372        mUserFaceUnlockRunning.put(userId, running);
373        for (int i = 0; i < mCallbacks.size(); i++) {
374            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
375            if (cb != null) {
376                cb.onFaceUnlockStateChanged(running, userId);
377            }
378        }
379    }
380
381    public boolean isFaceUnlockRunning(int userId) {
382        return mUserFaceUnlockRunning.get(userId);
383    }
384
385    private boolean isTrustDisabled(int userId) {
386        final DevicePolicyManager dpm =
387                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
388        if (dpm != null) {
389                // TODO once UI is finalized
390                final boolean disabledByGlobalActions = false;
391                final boolean disabledBySettings = false;
392
393                // Don't allow trust agent if device is secured with a SIM PIN. This is here
394                // mainly because there's no other way to prompt the user to enter their SIM PIN
395                // once they get past the keyguard screen.
396                final boolean disabledBySimPin = isSimPinSecure();
397
398                final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId)
399                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
400                return disabledByDpm || disabledByGlobalActions || disabledBySettings
401                        || disabledBySimPin;
402        }
403        return false;
404    }
405
406    private boolean isFingerprintDisabled(int userId) {
407        final DevicePolicyManager dpm =
408                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
409        return dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
410                    & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0;
411    }
412
413    public boolean getUserHasTrust(int userId) {
414        return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
415                || mUserFingerprintRecognized.get(userId);
416    }
417
418    public boolean getUserTrustIsManaged(int userId) {
419        return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
420    }
421
422    static class DisplayClientState {
423        public int clientGeneration;
424        public boolean clearing;
425        public PendingIntent intent;
426        public int playbackState;
427        public long playbackEventTime;
428    }
429
430    private DisplayClientState mDisplayClientState = new DisplayClientState();
431
432    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
433
434        public void onReceive(Context context, Intent intent) {
435            final String action = intent.getAction();
436            if (DEBUG) Log.d(TAG, "received broadcast " + action);
437
438            if (Intent.ACTION_TIME_TICK.equals(action)
439                    || Intent.ACTION_TIME_CHANGED.equals(action)
440                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
441                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
442            } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
443                final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
444                final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
445                final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
446                final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
447                final Message msg = mHandler.obtainMessage(
448                        MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
449                mHandler.sendMessage(msg);
450            } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
451                SimData args = SimData.fromIntent(intent);
452                if (DEBUG_SIM_STATES) {
453                    Log.v(TAG, "action " + action
454                        + " state: " + intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)
455                        + " slotId: " + args.slotId + " subid: " + args.subId);
456                }
457                mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState)
458                        .sendToTarget();
459            } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
460                mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
461                        intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
462            } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
463                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
464                mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
465            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
466                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
467                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
468            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
469                dispatchBootCompleted();
470            }
471        }
472    };
473
474    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
475
476        public void onReceive(Context context, Intent intent) {
477            final String action = intent.getAction();
478            if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {
479                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
480            } else if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
481                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
482                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
483            } else if (ACTION_FACE_UNLOCK_STARTED.equals(action)) {
484                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 1,
485                        getSendingUserId()));
486            } else if (ACTION_FACE_UNLOCK_STOPPED.equals(action)) {
487                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 0,
488                        getSendingUserId()));
489            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
490                    .equals(action)) {
491                mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
492            }
493        }
494    };
495    private FingerprintManagerReceiver mFingerprintManagerReceiver =
496            new FingerprintManagerReceiver() {
497        @Override
498        public void onProcessed(int fingerprintId) {
499            mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
500        };
501
502        @Override
503        public void onAcquired(int info) {
504            mHandler.obtainMessage(MSG_FINGERPRINT_ACQUIRED, info, 0).sendToTarget();
505        }
506
507        @Override
508        public void onError(int error) {
509            if (DEBUG) Log.w(TAG, "FingerprintManager reported error: " + error);
510        }
511    };
512
513    /**
514     * When we receive a
515     * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
516     * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
517     * we need a single object to pass to the handler.  This class helps decode
518     * the intent and provide a {@link SimCard.State} result.
519     */
520    private static class SimData {
521        public State simState;
522        public int slotId;
523        public int subId;
524
525        SimData(State state, int slot, int id) {
526            simState = state;
527            slotId = slot;
528            subId = id;
529        }
530
531        static SimData fromIntent(Intent intent) {
532            State state;
533            if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
534                throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
535            }
536            String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
537            int slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY, 0);
538            int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
539                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
540            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
541                final String absentReason = intent
542                    .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
543
544                if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
545                        absentReason)) {
546                    state = IccCardConstants.State.PERM_DISABLED;
547                } else {
548                    state = IccCardConstants.State.ABSENT;
549                }
550            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
551                state = IccCardConstants.State.READY;
552            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
553                final String lockedReason = intent
554                        .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
555                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
556                    state = IccCardConstants.State.PIN_REQUIRED;
557                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
558                    state = IccCardConstants.State.PUK_REQUIRED;
559                } else {
560                    state = IccCardConstants.State.UNKNOWN;
561                }
562            } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
563                state = IccCardConstants.State.NETWORK_LOCKED;
564            } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
565                        || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
566                // This is required because telephony doesn't return to "READY" after
567                // these state transitions. See bug 7197471.
568                state = IccCardConstants.State.READY;
569            } else {
570                state = IccCardConstants.State.UNKNOWN;
571            }
572            return new SimData(state, slotId, subId);
573        }
574
575        public String toString() {
576            return "SimData{state=" + simState + ",slotId=" + slotId + ",subId=" + subId + "}";
577        }
578    }
579
580    public static class BatteryStatus {
581        public final int status;
582        public final int level;
583        public final int plugged;
584        public final int health;
585        public BatteryStatus(int status, int level, int plugged, int health) {
586            this.status = status;
587            this.level = level;
588            this.plugged = plugged;
589            this.health = health;
590        }
591
592        /**
593         * Determine whether the device is plugged in (USB, power, or wireless).
594         * @return true if the device is plugged in.
595         */
596        public boolean isPluggedIn() {
597            return plugged == BatteryManager.BATTERY_PLUGGED_AC
598                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
599                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
600        }
601
602        /**
603         * Whether or not the device is charged. Note that some devices never return 100% for
604         * battery level, so this allows either battery level or status to determine if the
605         * battery is charged.
606         * @return true if the device is charged
607         */
608        public boolean isCharged() {
609            return status == BATTERY_STATUS_FULL || level >= 100;
610        }
611
612        /**
613         * Whether battery is low and needs to be charged.
614         * @return true if battery is low
615         */
616        public boolean isBatteryLow() {
617            return level < LOW_BATTERY_THRESHOLD;
618        }
619
620    }
621
622    public static KeyguardUpdateMonitor getInstance(Context context) {
623        if (sInstance == null) {
624            sInstance = new KeyguardUpdateMonitor(context);
625        }
626        return sInstance;
627    }
628
629    protected void handleScreenTurnedOn() {
630        final int count = mCallbacks.size();
631        for (int i = 0; i < count; i++) {
632            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
633            if (cb != null) {
634                cb.onScreenTurnedOn();
635            }
636        }
637    }
638
639    protected void handleScreenTurnedOff(int arg1) {
640        clearFingerprintRecognized();
641        final int count = mCallbacks.size();
642        for (int i = 0; i < count; i++) {
643            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
644            if (cb != null) {
645                cb.onScreenTurnedOff(arg1);
646            }
647        }
648    }
649
650    /**
651     * IMPORTANT: Must be called from UI thread.
652     */
653    public void dispatchSetBackground(Bitmap bmp) {
654        if (DEBUG) Log.d(TAG, "dispatchSetBackground");
655        final int count = mCallbacks.size();
656        for (int i = 0; i < count; i++) {
657            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
658            if (cb != null) {
659                cb.onSetBackground(bmp);
660            }
661        }
662    }
663
664    private void handleUserInfoChanged(int userId) {
665        for (int i = 0; i < mCallbacks.size(); i++) {
666            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
667            if (cb != null) {
668                cb.onUserInfoChanged(userId);
669            }
670        }
671    }
672
673    private KeyguardUpdateMonitor(Context context) {
674        mContext = context;
675        mSubscriptionManager = SubscriptionManager.from(context);
676        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
677        // Since device can't be un-provisioned, we only need to register a content observer
678        // to update mDeviceProvisioned when we are...
679        if (!mDeviceProvisioned) {
680            watchForDeviceProvisioning();
681        }
682
683        // Take a guess at initial SIM state, battery status and PLMN until we get an update
684        mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
685
686        // Watch for interesting updates
687        final IntentFilter filter = new IntentFilter();
688        filter.addAction(Intent.ACTION_TIME_TICK);
689        filter.addAction(Intent.ACTION_TIME_CHANGED);
690        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
691        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
692        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
693        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
694        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
695        filter.addAction(Intent.ACTION_USER_REMOVED);
696        context.registerReceiver(mBroadcastReceiver, filter);
697
698        final IntentFilter bootCompleteFilter = new IntentFilter();
699        bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
700        bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
701        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
702
703        final IntentFilter allUserFilter = new IntentFilter();
704        allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
705        allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
706        allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
707        allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
708        allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
709        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
710                null, null);
711
712        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
713        try {
714            ActivityManagerNative.getDefault().registerUserSwitchObserver(
715                    new IUserSwitchObserver.Stub() {
716                        @Override
717                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
718                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
719                                    newUserId, 0, reply));
720                            mSwitchingUser = true;
721                        }
722                        @Override
723                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
724                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
725                                    newUserId, 0));
726                            mSwitchingUser = false;
727                        }
728                    });
729        } catch (RemoteException e) {
730            // TODO Auto-generated catch block
731            e.printStackTrace();
732        }
733
734        TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
735        trustManager.registerTrustListener(this);
736
737        FingerprintManager fpm;
738        fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
739        fpm.startListening(mFingerprintManagerReceiver);
740    }
741
742    private boolean isDeviceProvisionedInSettingsDb() {
743        return Settings.Global.getInt(mContext.getContentResolver(),
744                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
745    }
746
747    private void watchForDeviceProvisioning() {
748        mDeviceProvisionedObserver = new ContentObserver(mHandler) {
749            @Override
750            public void onChange(boolean selfChange) {
751                super.onChange(selfChange);
752                mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
753                if (mDeviceProvisioned) {
754                    mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
755                }
756                if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
757            }
758        };
759
760        mContext.getContentResolver().registerContentObserver(
761                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
762                false, mDeviceProvisionedObserver);
763
764        // prevent a race condition between where we check the flag and where we register the
765        // observer by grabbing the value once again...
766        boolean provisioned = isDeviceProvisionedInSettingsDb();
767        if (provisioned != mDeviceProvisioned) {
768            mDeviceProvisioned = provisioned;
769            if (mDeviceProvisioned) {
770                mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
771            }
772        }
773    }
774
775    /**
776     * Handle {@link #MSG_DPM_STATE_CHANGED}
777     */
778    protected void handleDevicePolicyManagerStateChanged() {
779        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
780            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
781            if (cb != null) {
782                cb.onDevicePolicyManagerStateChanged();
783            }
784        }
785    }
786
787    /**
788     * Handle {@link #MSG_USER_SWITCHING}
789     */
790    protected void handleUserSwitching(int userId, IRemoteCallback reply) {
791        for (int i = 0; i < mCallbacks.size(); i++) {
792            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
793            if (cb != null) {
794                cb.onUserSwitching(userId);
795            }
796        }
797        try {
798            reply.sendResult(null);
799        } catch (RemoteException e) {
800        }
801    }
802
803    /**
804     * Handle {@link #MSG_USER_SWITCH_COMPLETE}
805     */
806    protected void handleUserSwitchComplete(int userId) {
807        for (int i = 0; i < mCallbacks.size(); i++) {
808            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
809            if (cb != null) {
810                cb.onUserSwitchComplete(userId);
811            }
812        }
813    }
814
815    /**
816     * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
817     * keyguard crashes sometime after boot, then it will never receive this
818     * broadcast and hence not handle the event. This method is ultimately called by
819     * PhoneWindowManager in this case.
820     */
821    public void dispatchBootCompleted() {
822        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
823    }
824
825    /**
826     * Handle {@link #MSG_BOOT_COMPLETED}
827     */
828    protected void handleBootCompleted() {
829        if (mBootCompleted) return;
830        mBootCompleted = true;
831        for (int i = 0; i < mCallbacks.size(); i++) {
832            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
833            if (cb != null) {
834                cb.onBootCompleted();
835            }
836        }
837    }
838
839    /**
840     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
841     * destroyed.
842     */
843    public boolean hasBootCompleted() {
844        return mBootCompleted;
845    }
846
847    /**
848     * Handle {@link #MSG_USER_REMOVED}
849     */
850    protected void handleUserRemoved(int userId) {
851        for (int i = 0; i < mCallbacks.size(); i++) {
852            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
853            if (cb != null) {
854                cb.onUserRemoved(userId);
855            }
856        }
857    }
858
859    /**
860     * Handle {@link #MSG_DEVICE_PROVISIONED}
861     */
862    protected void handleDeviceProvisioned() {
863        for (int i = 0; i < mCallbacks.size(); i++) {
864            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
865            if (cb != null) {
866                cb.onDeviceProvisioned();
867            }
868        }
869        if (mDeviceProvisionedObserver != null) {
870            // We don't need the observer anymore...
871            mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
872            mDeviceProvisionedObserver = null;
873        }
874    }
875
876    /**
877     * Handle {@link #MSG_PHONE_STATE_CHANGED}
878     */
879    protected void handlePhoneStateChanged(String newState) {
880        if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
881        if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
882            mPhoneState = TelephonyManager.CALL_STATE_IDLE;
883        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
884            mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
885        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
886            mPhoneState = TelephonyManager.CALL_STATE_RINGING;
887        }
888        for (int i = 0; i < mCallbacks.size(); i++) {
889            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
890            if (cb != null) {
891                cb.onPhoneStateChanged(mPhoneState);
892            }
893        }
894    }
895
896    /**
897     * Handle {@link #MSG_RINGER_MODE_CHANGED}
898     */
899    protected void handleRingerModeChange(int mode) {
900        if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
901        mRingMode = mode;
902        for (int i = 0; i < mCallbacks.size(); i++) {
903            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
904            if (cb != null) {
905                cb.onRingerModeChanged(mode);
906            }
907        }
908    }
909
910    /**
911     * Handle {@link #MSG_TIME_UPDATE}
912     */
913    private void handleTimeUpdate() {
914        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
915        for (int i = 0; i < mCallbacks.size(); i++) {
916            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
917            if (cb != null) {
918                cb.onTimeChanged();
919            }
920        }
921    }
922
923    /**
924     * Handle {@link #MSG_BATTERY_UPDATE}
925     */
926    private void handleBatteryUpdate(BatteryStatus status) {
927        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
928        final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
929        mBatteryStatus = status;
930        if (batteryUpdateInteresting) {
931            for (int i = 0; i < mCallbacks.size(); i++) {
932                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
933                if (cb != null) {
934                    cb.onRefreshBatteryInfo(status);
935                }
936            }
937        }
938    }
939
940    /**
941     * Handle {@link #MSG_SIM_STATE_CHANGE}
942     */
943    private void handleSimStateChange(int subId, int slotId, State state) {
944
945        if (DEBUG_SIM_STATES) {
946            Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId="
947                    + slotId + ", state=" + state +")");
948        }
949
950        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
951            Log.w(TAG, "invalid subId in handleSimStateChange()");
952            return;
953        }
954
955        SimData data = mSimDatas.get(subId);
956        final boolean changed;
957        if (data == null) {
958            data = new SimData(state, slotId, subId);
959            mSimDatas.put(subId, data);
960            changed = true; // no data yet; force update
961        } else {
962            changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
963            data.simState = state;
964            data.subId = subId;
965            data.slotId = slotId;
966        }
967        if (changed && state != State.UNKNOWN) {
968            for (int i = 0; i < mCallbacks.size(); i++) {
969                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
970                if (cb != null) {
971                    cb.onSimStateChanged(subId, slotId, state);
972                }
973            }
974        }
975    }
976
977    /**
978     * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
979     */
980    private void handleClockVisibilityChanged() {
981        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
982        for (int i = 0; i < mCallbacks.size(); i++) {
983            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
984            if (cb != null) {
985                cb.onClockVisibilityChanged();
986            }
987        }
988    }
989
990    /**
991     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
992     */
993    private void handleKeyguardVisibilityChanged(int showing) {
994        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
995        boolean isShowing = (showing == 1);
996        mKeyguardIsVisible = isShowing;
997        for (int i = 0; i < mCallbacks.size(); i++) {
998            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
999            if (cb != null) {
1000                cb.onKeyguardVisibilityChangedRaw(isShowing);
1001            }
1002        }
1003    }
1004
1005    /**
1006     * Handle {@link #MSG_KEYGUARD_BOUNCER_CHANGED}
1007     * @see #sendKeyguardBouncerChanged(boolean)
1008     */
1009    private void handleKeyguardBouncerChanged(int bouncer) {
1010        if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
1011        boolean isBouncer = (bouncer == 1);
1012        mBouncer = isBouncer;
1013        for (int i = 0; i < mCallbacks.size(); i++) {
1014            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
1015            if (cb != null) {
1016                cb.onKeyguardBouncerChanged(isBouncer);
1017            }
1018        }
1019    }
1020
1021    /**
1022     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
1023     */
1024    private void handleReportEmergencyCallAction() {
1025        for (int i = 0; i < mCallbacks.size(); i++) {
1026            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
1027            if (cb != null) {
1028                cb.onEmergencyCallAction();
1029            }
1030        }
1031    }
1032
1033    public boolean isKeyguardVisible() {
1034        return mKeyguardIsVisible;
1035    }
1036
1037    /**
1038     * @return if the keyguard is currently in bouncer mode.
1039     */
1040    public boolean isKeyguardBouncer() {
1041        return mBouncer;
1042    }
1043
1044    public boolean isSwitchingUser() {
1045        return mSwitchingUser;
1046    }
1047
1048    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
1049        final boolean nowPluggedIn = current.isPluggedIn();
1050        final boolean wasPluggedIn = old.isPluggedIn();
1051        final boolean stateChangedWhilePluggedIn =
1052            wasPluggedIn == true && nowPluggedIn == true
1053            && (old.status != current.status);
1054
1055        // change in plug state is always interesting
1056        if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
1057            return true;
1058        }
1059
1060        // change in battery level while plugged in
1061        if (nowPluggedIn && old.level != current.level) {
1062            return true;
1063        }
1064
1065        // change where battery needs charging
1066        if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
1067            return true;
1068        }
1069        return false;
1070    }
1071
1072    /**
1073     * @return The default plmn (no service)
1074     */
1075    private CharSequence getDefaultPlmn() {
1076        return mContext.getResources().getText(R.string.keyguard_carrier_default);
1077    }
1078
1079    /**
1080     * Remove the given observer's callback.
1081     *
1082     * @param callback The callback to remove
1083     */
1084    public void removeCallback(KeyguardUpdateMonitorCallback callback) {
1085        if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
1086        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
1087            if (mCallbacks.get(i).get() == callback) {
1088                mCallbacks.remove(i);
1089            }
1090        }
1091    }
1092
1093    /**
1094     * Register to receive notifications about general keyguard information
1095     * (see {@link InfoCallback}.
1096     * @param callback The callback to register
1097     */
1098    public void registerCallback(KeyguardUpdateMonitorCallback callback) {
1099        if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
1100        // Prevent adding duplicate callbacks
1101        for (int i = 0; i < mCallbacks.size(); i++) {
1102            if (mCallbacks.get(i).get() == callback) {
1103                if (DEBUG) Log.e(TAG, "Object tried to add another callback",
1104                        new Exception("Called by"));
1105                return;
1106            }
1107        }
1108        mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
1109        removeCallback(null); // remove unused references
1110        sendUpdates(callback);
1111    }
1112
1113    private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
1114        // Notify listener of the current state
1115        callback.onRefreshBatteryInfo(mBatteryStatus);
1116        callback.onTimeChanged();
1117        callback.onRingerModeChanged(mRingMode);
1118        callback.onPhoneStateChanged(mPhoneState);
1119        callback.onRefreshCarrierInfo();
1120        callback.onClockVisibilityChanged();
1121        for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
1122            final SimData state = data.getValue();
1123            callback.onSimStateChanged(state.subId, state.slotId, state.simState);
1124        }
1125    }
1126
1127    public void sendKeyguardVisibilityChanged(boolean showing) {
1128        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
1129        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
1130        message.arg1 = showing ? 1 : 0;
1131        message.sendToTarget();
1132    }
1133
1134    /**
1135     * @see #handleKeyguardBouncerChanged(int)
1136     */
1137    public void sendKeyguardBouncerChanged(boolean showingBouncer) {
1138        if (DEBUG) Log.d(TAG, "sendKeyguardBouncerChanged(" + showingBouncer + ")");
1139        Message message = mHandler.obtainMessage(MSG_KEYGUARD_BOUNCER_CHANGED);
1140        message.arg1 = showingBouncer ? 1 : 0;
1141        message.sendToTarget();
1142    }
1143
1144    public void reportClockVisible(boolean visible) {
1145        mClockVisible = visible;
1146        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
1147    }
1148
1149    /**
1150     * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
1151     * have the information earlier than waiting for the intent
1152     * broadcast from the telephony code.
1153     *
1154     * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
1155     * through mHandler, this *must* be called from the UI thread.
1156     */
1157    public void reportSimUnlocked(int subId) {
1158        if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")");
1159        int slotId = SubscriptionManager.getSlotId(subId);
1160        handleSimStateChange(subId, slotId, State.READY);
1161    }
1162
1163    /**
1164     * Report that the emergency call button has been pressed and the emergency dialer is
1165     * about to be displayed.
1166     *
1167     * @param bypassHandler runs immediately.
1168     *
1169     * NOTE: Must be called from UI thread if bypassHandler == true.
1170     */
1171    public void reportEmergencyCallAction(boolean bypassHandler) {
1172        if (!bypassHandler) {
1173            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
1174        } else {
1175            handleReportEmergencyCallAction();
1176        }
1177    }
1178
1179    /**
1180     * @return Whether the device is provisioned (whether they have gone through
1181     *   the setup wizard)
1182     */
1183    public boolean isDeviceProvisioned() {
1184        return mDeviceProvisioned;
1185    }
1186
1187    public int getFailedUnlockAttempts() {
1188        return mFailedAttempts;
1189    }
1190
1191    public void clearFailedUnlockAttempts() {
1192        mFailedAttempts = 0;
1193        mFailedBiometricUnlockAttempts = 0;
1194    }
1195
1196    public void clearFingerprintRecognized() {
1197        mUserFingerprintRecognized.clear();
1198    }
1199
1200    public void reportFailedUnlockAttempt() {
1201        mFailedAttempts++;
1202    }
1203
1204    public boolean isClockVisible() {
1205        return mClockVisible;
1206    }
1207
1208    public int getPhoneState() {
1209        return mPhoneState;
1210    }
1211
1212    public void reportFailedBiometricUnlockAttempt() {
1213        mFailedBiometricUnlockAttempts++;
1214    }
1215
1216    public boolean getMaxBiometricUnlockAttemptsReached() {
1217        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
1218    }
1219
1220    public boolean isAlternateUnlockEnabled() {
1221        return mAlternateUnlockEnabled;
1222    }
1223
1224    public void setAlternateUnlockEnabled(boolean enabled) {
1225        mAlternateUnlockEnabled = enabled;
1226    }
1227
1228    public boolean isSimPinVoiceSecure() {
1229        // TODO: only count SIMs that handle voice
1230        return isSimPinSecure();
1231    }
1232
1233    public boolean isSimPinSecure() {
1234        // True if any SIM is pin secure
1235        for (SubscriptionInfo info : getSubscriptionInfo(false /* forceReload */)) {
1236            if (isSimPinSecure(getSimState(info.getSubscriptionId()))) return true;
1237        }
1238        return false;
1239    }
1240
1241    public State getSimState(int subId) {
1242        if (mSimDatas.containsKey(subId)) {
1243            return mSimDatas.get(subId).simState;
1244        } else {
1245            return State.UNKNOWN;
1246        }
1247    }
1248
1249    /**
1250     * @return true if and only if the state has changed for the specified {@code slotId}
1251     */
1252    private boolean refreshSimState(int subId, int slotId) {
1253
1254        // This is awful. It exists because there are two APIs for getting the SIM status
1255        // that don't return the complete set of values and have different types. In Keyguard we
1256        // need IccCardConstants, but TelephonyManager would only give us
1257        // TelephonyManager.SIM_STATE*, so we retrieve it manually.
1258        final TelephonyManager tele = TelephonyManager.from(mContext);
1259        int simState =  tele.getSimState(slotId);
1260        State state;
1261        try {
1262            state = State.intToState(simState);
1263        } catch(IllegalArgumentException ex) {
1264            Log.w(TAG, "Unknown sim state: " + simState);
1265            state = State.UNKNOWN;
1266        }
1267        SimData data = mSimDatas.get(subId);
1268        final boolean changed;
1269        if (data == null) {
1270            data = new SimData(state, slotId, subId);
1271            mSimDatas.put(subId, data);
1272            changed = true; // no data yet; force update
1273        } else {
1274            changed = data.simState != state;
1275            data.simState = state;
1276        }
1277        return changed;
1278    }
1279
1280    public static boolean isSimPinSecure(IccCardConstants.State state) {
1281        final IccCardConstants.State simState = state;
1282        return (simState == IccCardConstants.State.PIN_REQUIRED
1283                || simState == IccCardConstants.State.PUK_REQUIRED
1284                || simState == IccCardConstants.State.PERM_DISABLED);
1285    }
1286
1287    public DisplayClientState getCachedDisplayClientState() {
1288        return mDisplayClientState;
1289    }
1290
1291    // TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
1292    // (KeyguardViewMediator, KeyguardHostView)
1293    public void dispatchScreenTurnedOn() {
1294        synchronized (this) {
1295            mScreenOn = true;
1296        }
1297        mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON);
1298    }
1299
1300    public void dispatchScreenTurndOff(int why) {
1301        synchronized(this) {
1302            mScreenOn = false;
1303        }
1304        mHandler.sendMessage(mHandler.obtainMessage(MSG_SCREEN_TURNED_OFF, why, 0));
1305    }
1306
1307    public boolean isScreenOn() {
1308        return mScreenOn;
1309    }
1310
1311    /**
1312     * Find the next SubscriptionId for a SIM in the given state, favoring lower slot numbers first.
1313     * @param state
1314     * @return subid or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if none found
1315     */
1316    public int getNextSubIdForState(State state) {
1317        List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */);
1318        int resultId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1319        int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first
1320        for (int i = 0; i < list.size(); i++) {
1321            final SubscriptionInfo info = list.get(i);
1322            final int id = info.getSubscriptionId();
1323            int slotId = SubscriptionManager.getSlotId(id);
1324            if (state == getSimState(id) && bestSlotId > slotId ) {
1325                resultId = id;
1326                bestSlotId = slotId;
1327            }
1328        }
1329        return resultId;
1330    }
1331
1332    public SubscriptionInfo getSubscriptionInfoForSubId(int subId) {
1333        List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */);
1334        for (int i = 0; i < list.size(); i++) {
1335            SubscriptionInfo info = list.get(i);
1336            if (subId == info.getSubscriptionId()) return info;
1337        }
1338        return null; // not found
1339    }
1340}
1341