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.IUserSwitchObserver;
21import android.app.PendingIntent;
22import android.app.admin.DevicePolicyManager;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.database.ContentObserver;
28import android.graphics.Bitmap;
29
30import static android.os.BatteryManager.BATTERY_STATUS_FULL;
31import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
32import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
33import static android.os.BatteryManager.EXTRA_STATUS;
34import static android.os.BatteryManager.EXTRA_PLUGGED;
35import static android.os.BatteryManager.EXTRA_LEVEL;
36import static android.os.BatteryManager.EXTRA_HEALTH;
37import android.media.AudioManager;
38import android.media.IRemoteControlDisplay;
39import android.os.BatteryManager;
40import android.os.Bundle;
41import android.os.Handler;
42import android.os.IRemoteCallback;
43import android.os.Message;
44import android.os.RemoteException;
45import android.os.UserHandle;
46import android.provider.Settings;
47
48import com.android.internal.telephony.IccCardConstants;
49import com.android.internal.telephony.TelephonyIntents;
50
51import android.telephony.TelephonyManager;
52import android.util.Log;
53import com.google.android.collect.Lists;
54
55import java.lang.ref.WeakReference;
56import java.util.ArrayList;
57
58/**
59 * Watches for updates that may be interesting to the keyguard, and provides
60 * the up to date information as well as a registration for callbacks that care
61 * to be updated.
62 *
63 * Note: under time crunch, this has been extended to include some stuff that
64 * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
65 * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
66 * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
67 */
68public class KeyguardUpdateMonitor {
69
70    private static final String TAG = "KeyguardUpdateMonitor";
71    private static final boolean DEBUG = false;
72    private static final boolean DEBUG_SIM_STATES = DEBUG || false;
73    private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
74    private static final int LOW_BATTERY_THRESHOLD = 20;
75
76    // Callback messages
77    private static final int MSG_TIME_UPDATE = 301;
78    private static final int MSG_BATTERY_UPDATE = 302;
79    private static final int MSG_CARRIER_INFO_UPDATE = 303;
80    private static final int MSG_SIM_STATE_CHANGE = 304;
81    private static final int MSG_RINGER_MODE_CHANGED = 305;
82    private static final int MSG_PHONE_STATE_CHANGED = 306;
83    private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
84    private static final int MSG_DEVICE_PROVISIONED = 308;
85    private static final int MSG_DPM_STATE_CHANGED = 309;
86    private static final int MSG_USER_SWITCHING = 310;
87    private static final int MSG_USER_REMOVED = 311;
88    private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
89    protected static final int MSG_BOOT_COMPLETED = 313;
90    private static final int MSG_USER_SWITCH_COMPLETE = 314;
91    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
92    protected static final int MSG_SET_PLAYBACK_STATE = 316;
93    protected static final int MSG_USER_INFO_CHANGED = 317;
94    protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
95    private static final int MSG_SCREEN_TURNED_ON = 319;
96    private static final int MSG_SCREEN_TURNED_OFF = 320;
97
98    private static KeyguardUpdateMonitor sInstance;
99
100    private final Context mContext;
101
102    // Telephony state
103    private IccCardConstants.State mSimState = IccCardConstants.State.READY;
104    private CharSequence mTelephonyPlmn;
105    private CharSequence mTelephonySpn;
106    private int mRingMode;
107    private int mPhoneState;
108    private boolean mKeyguardIsVisible;
109    private boolean mBootCompleted;
110
111    // Device provisioning state
112    private boolean mDeviceProvisioned;
113
114    // Battery status
115    private BatteryStatus mBatteryStatus;
116
117    // Password attempts
118    private int mFailedAttempts = 0;
119    private int mFailedBiometricUnlockAttempts = 0;
120
121    private boolean mAlternateUnlockEnabled;
122
123    private boolean mClockVisible;
124
125    private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
126            mCallbacks = Lists.newArrayList();
127    private ContentObserver mDeviceProvisionedObserver;
128
129    private boolean mSwitchingUser;
130
131    private boolean mScreenOn;
132
133    private final Handler mHandler = new Handler() {
134        @Override
135        public void handleMessage(Message msg) {
136            switch (msg.what) {
137                case MSG_TIME_UPDATE:
138                    handleTimeUpdate();
139                    break;
140                case MSG_BATTERY_UPDATE:
141                    handleBatteryUpdate((BatteryStatus) msg.obj);
142                    break;
143                case MSG_CARRIER_INFO_UPDATE:
144                    handleCarrierInfoUpdate();
145                    break;
146                case MSG_SIM_STATE_CHANGE:
147                    handleSimStateChange((SimArgs) msg.obj);
148                    break;
149                case MSG_RINGER_MODE_CHANGED:
150                    handleRingerModeChange(msg.arg1);
151                    break;
152                case MSG_PHONE_STATE_CHANGED:
153                    handlePhoneStateChanged((String)msg.obj);
154                    break;
155                case MSG_CLOCK_VISIBILITY_CHANGED:
156                    handleClockVisibilityChanged();
157                    break;
158                case MSG_DEVICE_PROVISIONED:
159                    handleDeviceProvisioned();
160                    break;
161                case MSG_DPM_STATE_CHANGED:
162                    handleDevicePolicyManagerStateChanged();
163                    break;
164                case MSG_USER_SWITCHING:
165                    handleUserSwitching(msg.arg1, (IRemoteCallback)msg.obj);
166                    break;
167                case MSG_USER_SWITCH_COMPLETE:
168                    handleUserSwitchComplete(msg.arg1);
169                    break;
170                case MSG_USER_REMOVED:
171                    handleUserRemoved(msg.arg1);
172                    break;
173                case MSG_KEYGUARD_VISIBILITY_CHANGED:
174                    handleKeyguardVisibilityChanged(msg.arg1);
175                    break;
176                case MSG_BOOT_COMPLETED:
177                    handleBootCompleted();
178                    break;
179                case MSG_SET_CURRENT_CLIENT_ID:
180                    handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
181                    break;
182                case MSG_SET_PLAYBACK_STATE:
183                    handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
184                    break;
185                case MSG_USER_INFO_CHANGED:
186                    handleUserInfoChanged(msg.arg1);
187                    break;
188                case MSG_REPORT_EMERGENCY_CALL_ACTION:
189                    handleReportEmergencyCallAction();
190                    break;
191                case MSG_SCREEN_TURNED_OFF:
192                    handleScreenTurnedOff(msg.arg1);
193                    break;
194                case MSG_SCREEN_TURNED_ON:
195                    handleScreenTurnedOn();
196                    break;
197            }
198        }
199    };
200
201    private AudioManager mAudioManager;
202
203    static class DisplayClientState {
204        public int clientGeneration;
205        public boolean clearing;
206        public PendingIntent intent;
207        public int playbackState;
208        public long playbackEventTime;
209    }
210
211    private DisplayClientState mDisplayClientState = new DisplayClientState();
212
213    /**
214     * This currently implements the bare minimum required to enable showing and hiding
215     * KeyguardTransportControl.  There's a lot of client state to maintain which is why
216     * KeyguardTransportControl maintains an independent connection while it's showing.
217     */
218    private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
219                new IRemoteControlDisplay.Stub() {
220
221        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
222                long currentPosMs, float speed) {
223            Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
224                    generationId, state, stateChangeTimeMs);
225            mHandler.sendMessage(msg);
226        }
227
228        public void setMetadata(int generationId, Bundle metadata) {
229
230        }
231
232        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
233
234        }
235
236        public void setArtwork(int generationId, Bitmap bitmap) {
237
238        }
239
240        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
241
242        }
243
244        public void setEnabled(boolean enabled) {
245            // no-op: this RemoteControlDisplay is not subject to being disabled.
246        }
247
248        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
249                boolean clearing) throws RemoteException {
250            Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
251                        clientGeneration, (clearing ? 1 : 0), mediaIntent);
252            mHandler.sendMessage(msg);
253        }
254    };
255
256    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
257
258        public void onReceive(Context context, Intent intent) {
259            final String action = intent.getAction();
260            if (DEBUG) Log.d(TAG, "received broadcast " + action);
261
262            if (Intent.ACTION_TIME_TICK.equals(action)
263                    || Intent.ACTION_TIME_CHANGED.equals(action)
264                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
265                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
266            } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
267                mTelephonyPlmn = getTelephonyPlmnFrom(intent);
268                mTelephonySpn = getTelephonySpnFrom(intent);
269                mHandler.sendEmptyMessage(MSG_CARRIER_INFO_UPDATE);
270            } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
271                final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
272                final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
273                final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
274                final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
275                final Message msg = mHandler.obtainMessage(
276                        MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
277                mHandler.sendMessage(msg);
278            } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
279                if (DEBUG_SIM_STATES) {
280                    Log.v(TAG, "action " + action + " state" +
281                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE));
282                }
283                mHandler.sendMessage(mHandler.obtainMessage(
284                        MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
285            } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
286                mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
287                        intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
288            } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
289                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
290                mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
291            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
292                    .equals(action)) {
293                mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
294            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
295                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
296                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
297            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
298                dispatchBootCompleted();
299            }
300        }
301    };
302
303    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {
304
305        public void onReceive(Context context, Intent intent) {
306            final String action = intent.getAction();
307            if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {
308                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,
309                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));
310            }
311        }
312    };
313
314    /**
315     * When we receive a
316     * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
317     * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
318     * we need a single object to pass to the handler.  This class helps decode
319     * the intent and provide a {@link SimCard.State} result.
320     */
321    private static class SimArgs {
322        public final IccCardConstants.State simState;
323
324        SimArgs(IccCardConstants.State state) {
325            simState = state;
326        }
327
328        static SimArgs fromIntent(Intent intent) {
329            IccCardConstants.State state;
330            if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
331                throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
332            }
333            String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
334            if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
335                final String absentReason = intent
336                    .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
337
338                if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
339                        absentReason)) {
340                    state = IccCardConstants.State.PERM_DISABLED;
341                } else {
342                    state = IccCardConstants.State.ABSENT;
343                }
344            } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
345                state = IccCardConstants.State.READY;
346            } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
347                final String lockedReason = intent
348                        .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
349                if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
350                    state = IccCardConstants.State.PIN_REQUIRED;
351                } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
352                    state = IccCardConstants.State.PUK_REQUIRED;
353                } else {
354                    state = IccCardConstants.State.UNKNOWN;
355                }
356            } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
357                state = IccCardConstants.State.NETWORK_LOCKED;
358            } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
359                        || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
360                // This is required because telephony doesn't return to "READY" after
361                // these state transitions. See bug 7197471.
362                state = IccCardConstants.State.READY;
363            } else {
364                state = IccCardConstants.State.UNKNOWN;
365            }
366            return new SimArgs(state);
367        }
368
369        public String toString() {
370            return simState.toString();
371        }
372    }
373
374    /* package */ static class BatteryStatus {
375        public final int status;
376        public final int level;
377        public final int plugged;
378        public final int health;
379        public BatteryStatus(int status, int level, int plugged, int health) {
380            this.status = status;
381            this.level = level;
382            this.plugged = plugged;
383            this.health = health;
384        }
385
386        /**
387         * Determine whether the device is plugged in (USB, power, or wireless).
388         * @return true if the device is plugged in.
389         */
390        boolean isPluggedIn() {
391            return plugged == BatteryManager.BATTERY_PLUGGED_AC
392                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
393                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
394        }
395
396        /**
397         * Whether or not the device is charged. Note that some devices never return 100% for
398         * battery level, so this allows either battery level or status to determine if the
399         * battery is charged.
400         * @return true if the device is charged
401         */
402        public boolean isCharged() {
403            return status == BATTERY_STATUS_FULL || level >= 100;
404        }
405
406        /**
407         * Whether battery is low and needs to be charged.
408         * @return true if battery is low
409         */
410        public boolean isBatteryLow() {
411            return level < LOW_BATTERY_THRESHOLD;
412        }
413
414    }
415
416    public static KeyguardUpdateMonitor getInstance(Context context) {
417        if (sInstance == null) {
418            sInstance = new KeyguardUpdateMonitor(context);
419        }
420        return sInstance;
421    }
422
423    protected void handleScreenTurnedOn() {
424        final int count = mCallbacks.size();
425        for (int i = 0; i < count; i++) {
426            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
427            if (cb != null) {
428                cb.onScreenTurnedOn();
429            }
430        }
431    }
432
433    protected void handleScreenTurnedOff(int arg1) {
434        final int count = mCallbacks.size();
435        for (int i = 0; i < count; i++) {
436            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
437            if (cb != null) {
438                cb.onScreenTurnedOff(arg1);
439            }
440        }
441    }
442
443    /**
444     * IMPORTANT: Must be called from UI thread.
445     */
446    public void dispatchSetBackground(Bitmap bmp) {
447        if (DEBUG) Log.d(TAG, "dispatchSetBackground");
448        final int count = mCallbacks.size();
449        for (int i = 0; i < count; i++) {
450            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
451            if (cb != null) {
452                cb.onSetBackground(bmp);
453            }
454        }
455    }
456
457    protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
458        mDisplayClientState.clientGeneration = clientGeneration;
459        mDisplayClientState.clearing = clearing;
460        mDisplayClientState.intent = p;
461        if (DEBUG)
462            Log.v(TAG, "handleSetGenerationId(g=" + clientGeneration + ", clear=" + clearing + ")");
463        for (int i = 0; i < mCallbacks.size(); i++) {
464            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
465            if (cb != null) {
466                cb.onMusicClientIdChanged(clientGeneration, clearing, p);
467            }
468        }
469    }
470
471    protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
472        if (DEBUG)
473            Log.v(TAG, "handleSetPlaybackState(gen=" + generationId
474                + ", state=" + playbackState + ", t=" + eventTime + ")");
475        mDisplayClientState.playbackState = playbackState;
476        mDisplayClientState.playbackEventTime = eventTime;
477        if (generationId == mDisplayClientState.clientGeneration) {
478            for (int i = 0; i < mCallbacks.size(); i++) {
479                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
480                if (cb != null) {
481                    cb.onMusicPlaybackStateChanged(playbackState, eventTime);
482                }
483            }
484        } else {
485            Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
486        }
487    }
488
489    private void handleUserInfoChanged(int userId) {
490        for (int i = 0; i < mCallbacks.size(); i++) {
491            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
492            if (cb != null) {
493                cb.onUserInfoChanged(userId);
494            }
495        }
496    }
497
498    private KeyguardUpdateMonitor(Context context) {
499        mContext = context;
500
501        mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
502        // Since device can't be un-provisioned, we only need to register a content observer
503        // to update mDeviceProvisioned when we are...
504        if (!mDeviceProvisioned) {
505            watchForDeviceProvisioning();
506        }
507
508        // Take a guess at initial SIM state, battery status and PLMN until we get an update
509        mSimState = IccCardConstants.State.NOT_READY;
510        mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
511        mTelephonyPlmn = getDefaultPlmn();
512
513        // Watch for interesting updates
514        final IntentFilter filter = new IntentFilter();
515        filter.addAction(Intent.ACTION_TIME_TICK);
516        filter.addAction(Intent.ACTION_TIME_CHANGED);
517        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
518        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
519        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
520        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
521        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
522        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
523        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
524        filter.addAction(Intent.ACTION_USER_REMOVED);
525        context.registerReceiver(mBroadcastReceiver, filter);
526
527        final IntentFilter bootCompleteFilter = new IntentFilter();
528        bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
529        bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
530        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
531
532        final IntentFilter userInfoFilter = new IntentFilter(Intent.ACTION_USER_INFO_CHANGED);
533        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, userInfoFilter,
534                null, null);
535
536        try {
537            ActivityManagerNative.getDefault().registerUserSwitchObserver(
538                    new IUserSwitchObserver.Stub() {
539                        @Override
540                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
541                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHING,
542                                    newUserId, 0, reply));
543                            mSwitchingUser = true;
544                        }
545                        @Override
546                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
547                            mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
548                                    newUserId));
549                            mSwitchingUser = false;
550                        }
551                    });
552        } catch (RemoteException e) {
553            // TODO Auto-generated catch block
554            e.printStackTrace();
555        }
556    }
557
558    private boolean isDeviceProvisionedInSettingsDb() {
559        return Settings.Global.getInt(mContext.getContentResolver(),
560                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
561    }
562
563    private void watchForDeviceProvisioning() {
564        mDeviceProvisionedObserver = new ContentObserver(mHandler) {
565            @Override
566            public void onChange(boolean selfChange) {
567                super.onChange(selfChange);
568                mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
569                if (mDeviceProvisioned) {
570                    mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
571                }
572                if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
573            }
574        };
575
576        mContext.getContentResolver().registerContentObserver(
577                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
578                false, mDeviceProvisionedObserver);
579
580        // prevent a race condition between where we check the flag and where we register the
581        // observer by grabbing the value once again...
582        boolean provisioned = isDeviceProvisionedInSettingsDb();
583        if (provisioned != mDeviceProvisioned) {
584            mDeviceProvisioned = provisioned;
585            if (mDeviceProvisioned) {
586                mHandler.sendEmptyMessage(MSG_DEVICE_PROVISIONED);
587            }
588        }
589    }
590
591    /**
592     * Handle {@link #MSG_DPM_STATE_CHANGED}
593     */
594    protected void handleDevicePolicyManagerStateChanged() {
595        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
596            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
597            if (cb != null) {
598                cb.onDevicePolicyManagerStateChanged();
599            }
600        }
601    }
602
603    /**
604     * Handle {@link #MSG_USER_SWITCHING}
605     */
606    protected void handleUserSwitching(int userId, IRemoteCallback reply) {
607        for (int i = 0; i < mCallbacks.size(); i++) {
608            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
609            if (cb != null) {
610                cb.onUserSwitching(userId);
611            }
612        }
613        try {
614            reply.sendResult(null);
615        } catch (RemoteException e) {
616        }
617    }
618
619    /**
620     * Handle {@link #MSG_USER_SWITCH_COMPLETE}
621     */
622    protected void handleUserSwitchComplete(int userId) {
623        for (int i = 0; i < mCallbacks.size(); i++) {
624            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
625            if (cb != null) {
626                cb.onUserSwitchComplete(userId);
627            }
628        }
629    }
630
631    /**
632     * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
633     * keyguard crashes sometime after boot, then it will never receive this
634     * broadcast and hence not handle the event. This method is ultimately called by
635     * PhoneWindowManager in this case.
636     */
637    protected void dispatchBootCompleted() {
638        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
639    }
640
641    /**
642     * Handle {@link #MSG_BOOT_COMPLETED}
643     */
644    protected void handleBootCompleted() {
645        if (mBootCompleted) return;
646        mBootCompleted = true;
647        mAudioManager = new AudioManager(mContext);
648        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
649        for (int i = 0; i < mCallbacks.size(); i++) {
650            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
651            if (cb != null) {
652                cb.onBootCompleted();
653            }
654        }
655    }
656
657    /**
658     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
659     * destroyed.
660     */
661    public boolean hasBootCompleted() {
662        return mBootCompleted;
663    }
664
665    /**
666     * Handle {@link #MSG_USER_REMOVED}
667     */
668    protected void handleUserRemoved(int userId) {
669        for (int i = 0; i < mCallbacks.size(); i++) {
670            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
671            if (cb != null) {
672                cb.onUserRemoved(userId);
673            }
674        }
675    }
676
677    /**
678     * Handle {@link #MSG_DEVICE_PROVISIONED}
679     */
680    protected void handleDeviceProvisioned() {
681        for (int i = 0; i < mCallbacks.size(); i++) {
682            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
683            if (cb != null) {
684                cb.onDeviceProvisioned();
685            }
686        }
687        if (mDeviceProvisionedObserver != null) {
688            // We don't need the observer anymore...
689            mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
690            mDeviceProvisionedObserver = null;
691        }
692    }
693
694    /**
695     * Handle {@link #MSG_PHONE_STATE_CHANGED}
696     */
697    protected void handlePhoneStateChanged(String newState) {
698        if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
699        if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
700            mPhoneState = TelephonyManager.CALL_STATE_IDLE;
701        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
702            mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
703        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
704            mPhoneState = TelephonyManager.CALL_STATE_RINGING;
705        }
706        for (int i = 0; i < mCallbacks.size(); i++) {
707            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
708            if (cb != null) {
709                cb.onPhoneStateChanged(mPhoneState);
710            }
711        }
712    }
713
714    /**
715     * Handle {@link #MSG_RINGER_MODE_CHANGED}
716     */
717    protected void handleRingerModeChange(int mode) {
718        if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
719        mRingMode = mode;
720        for (int i = 0; i < mCallbacks.size(); i++) {
721            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
722            if (cb != null) {
723                cb.onRingerModeChanged(mode);
724            }
725        }
726    }
727
728    /**
729     * Handle {@link #MSG_TIME_UPDATE}
730     */
731    private void handleTimeUpdate() {
732        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
733        for (int i = 0; i < mCallbacks.size(); i++) {
734            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
735            if (cb != null) {
736                cb.onTimeChanged();
737            }
738        }
739    }
740
741    /**
742     * Handle {@link #MSG_BATTERY_UPDATE}
743     */
744    private void handleBatteryUpdate(BatteryStatus status) {
745        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
746        final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
747        mBatteryStatus = status;
748        if (batteryUpdateInteresting) {
749            for (int i = 0; i < mCallbacks.size(); i++) {
750                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
751                if (cb != null) {
752                    cb.onRefreshBatteryInfo(status);
753                }
754            }
755        }
756    }
757
758    /**
759     * Handle {@link #MSG_CARRIER_INFO_UPDATE}
760     */
761    private void handleCarrierInfoUpdate() {
762        if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
763            + ", spn = " + mTelephonySpn);
764
765        for (int i = 0; i < mCallbacks.size(); i++) {
766            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
767            if (cb != null) {
768                cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
769            }
770        }
771    }
772
773    /**
774     * Handle {@link #MSG_SIM_STATE_CHANGE}
775     */
776    private void handleSimStateChange(SimArgs simArgs) {
777        final IccCardConstants.State state = simArgs.simState;
778
779        if (DEBUG) {
780            Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
781                    + "state resolved to " + state.toString());
782        }
783
784        if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
785            mSimState = state;
786            for (int i = 0; i < mCallbacks.size(); i++) {
787                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
788                if (cb != null) {
789                    cb.onSimStateChanged(state);
790                }
791            }
792        }
793    }
794
795    /**
796     * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
797     */
798    private void handleClockVisibilityChanged() {
799        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
800        for (int i = 0; i < mCallbacks.size(); i++) {
801            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
802            if (cb != null) {
803                cb.onClockVisibilityChanged();
804            }
805        }
806    }
807
808    /**
809     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
810     */
811    private void handleKeyguardVisibilityChanged(int showing) {
812        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
813        boolean isShowing = (showing == 1);
814        mKeyguardIsVisible = isShowing;
815        for (int i = 0; i < mCallbacks.size(); i++) {
816            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
817            if (cb != null) {
818                cb.onKeyguardVisibilityChangedRaw(isShowing);
819            }
820        }
821    }
822
823    /**
824     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
825     */
826    private void handleReportEmergencyCallAction() {
827        for (int i = 0; i < mCallbacks.size(); i++) {
828            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
829            if (cb != null) {
830                cb.onEmergencyCallAction();
831            }
832        }
833    }
834
835    public boolean isKeyguardVisible() {
836        return mKeyguardIsVisible;
837    }
838
839    public boolean isSwitchingUser() {
840        return mSwitchingUser;
841    }
842
843    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
844        final boolean nowPluggedIn = current.isPluggedIn();
845        final boolean wasPluggedIn = old.isPluggedIn();
846        final boolean stateChangedWhilePluggedIn =
847            wasPluggedIn == true && nowPluggedIn == true
848            && (old.status != current.status);
849
850        // change in plug state is always interesting
851        if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
852            return true;
853        }
854
855        // change in battery level while plugged in
856        if (nowPluggedIn && old.level != current.level) {
857            return true;
858        }
859
860        // change where battery needs charging
861        if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
862            return true;
863        }
864        return false;
865    }
866
867    /**
868     * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
869     * @return The string to use for the plmn, or null if it should not be shown.
870     */
871    private CharSequence getTelephonyPlmnFrom(Intent intent) {
872        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
873            final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
874            return (plmn != null) ? plmn : getDefaultPlmn();
875        }
876        return null;
877    }
878
879    /**
880     * @return The default plmn (no service)
881     */
882    private CharSequence getDefaultPlmn() {
883        return mContext.getResources().getText(R.string.keyguard_carrier_default);
884    }
885
886    /**
887     * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
888     * @return The string to use for the plmn, or null if it should not be shown.
889     */
890    private CharSequence getTelephonySpnFrom(Intent intent) {
891        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
892            final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
893            if (spn != null) {
894                return spn;
895            }
896        }
897        return null;
898    }
899
900    /**
901     * Remove the given observer's callback.
902     *
903     * @param callback The callback to remove
904     */
905    public void removeCallback(KeyguardUpdateMonitorCallback callback) {
906        if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
907        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
908            if (mCallbacks.get(i).get() == callback) {
909                mCallbacks.remove(i);
910            }
911        }
912    }
913
914    /**
915     * Register to receive notifications about general keyguard information
916     * (see {@link InfoCallback}.
917     * @param callback The callback to register
918     */
919    public void registerCallback(KeyguardUpdateMonitorCallback callback) {
920        if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
921        // Prevent adding duplicate callbacks
922        for (int i = 0; i < mCallbacks.size(); i++) {
923            if (mCallbacks.get(i).get() == callback) {
924                if (DEBUG) Log.e(TAG, "Object tried to add another callback",
925                        new Exception("Called by"));
926                return;
927            }
928        }
929        mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
930        removeCallback(null); // remove unused references
931        sendUpdates(callback);
932    }
933
934    private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
935        // Notify listener of the current state
936        callback.onRefreshBatteryInfo(mBatteryStatus);
937        callback.onTimeChanged();
938        callback.onRingerModeChanged(mRingMode);
939        callback.onPhoneStateChanged(mPhoneState);
940        callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
941        callback.onClockVisibilityChanged();
942        callback.onSimStateChanged(mSimState);
943        callback.onMusicClientIdChanged(
944                mDisplayClientState.clientGeneration,
945                mDisplayClientState.clearing,
946                mDisplayClientState.intent);
947        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
948                mDisplayClientState.playbackEventTime);
949    }
950
951    public void sendKeyguardVisibilityChanged(boolean showing) {
952        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
953        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
954        message.arg1 = showing ? 1 : 0;
955        message.sendToTarget();
956    }
957
958    public void reportClockVisible(boolean visible) {
959        mClockVisible = visible;
960        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
961    }
962
963    public IccCardConstants.State getSimState() {
964        return mSimState;
965    }
966
967    /**
968     * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
969     * have the information earlier than waiting for the intent
970     * broadcast from the telephony code.
971     *
972     * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
973     * through mHandler, this *must* be called from the UI thread.
974     */
975    public void reportSimUnlocked() {
976        handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
977    }
978
979    /**
980     * Report that the emergency call button has been pressed and the emergency dialer is
981     * about to be displayed.
982     *
983     * @param bypassHandler runs immediately.
984     *
985     * NOTE: Must be called from UI thread if bypassHandler == true.
986     */
987    public void reportEmergencyCallAction(boolean bypassHandler) {
988        if (!bypassHandler) {
989            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
990        } else {
991            handleReportEmergencyCallAction();
992        }
993    }
994
995    public CharSequence getTelephonyPlmn() {
996        return mTelephonyPlmn;
997    }
998
999    public CharSequence getTelephonySpn() {
1000        return mTelephonySpn;
1001    }
1002
1003    /**
1004     * @return Whether the device is provisioned (whether they have gone through
1005     *   the setup wizard)
1006     */
1007    public boolean isDeviceProvisioned() {
1008        return mDeviceProvisioned;
1009    }
1010
1011    public int getFailedUnlockAttempts() {
1012        return mFailedAttempts;
1013    }
1014
1015    public void clearFailedUnlockAttempts() {
1016        mFailedAttempts = 0;
1017        mFailedBiometricUnlockAttempts = 0;
1018    }
1019
1020    public void reportFailedUnlockAttempt() {
1021        mFailedAttempts++;
1022    }
1023
1024    public boolean isClockVisible() {
1025        return mClockVisible;
1026    }
1027
1028    public int getPhoneState() {
1029        return mPhoneState;
1030    }
1031
1032    public void reportFailedBiometricUnlockAttempt() {
1033        mFailedBiometricUnlockAttempts++;
1034    }
1035
1036    public boolean getMaxBiometricUnlockAttemptsReached() {
1037        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
1038    }
1039
1040    public boolean isAlternateUnlockEnabled() {
1041        return mAlternateUnlockEnabled;
1042    }
1043
1044    public void setAlternateUnlockEnabled(boolean enabled) {
1045        mAlternateUnlockEnabled = enabled;
1046    }
1047
1048    public boolean isSimLocked() {
1049        return isSimLocked(mSimState);
1050    }
1051
1052    public static boolean isSimLocked(IccCardConstants.State state) {
1053        return state == IccCardConstants.State.PIN_REQUIRED
1054        || state == IccCardConstants.State.PUK_REQUIRED
1055        || state == IccCardConstants.State.PERM_DISABLED;
1056    }
1057
1058    public boolean isSimPinSecure() {
1059        return isSimPinSecure(mSimState);
1060    }
1061
1062    public static boolean isSimPinSecure(IccCardConstants.State state) {
1063        final IccCardConstants.State simState = state;
1064        return (simState == IccCardConstants.State.PIN_REQUIRED
1065                || simState == IccCardConstants.State.PUK_REQUIRED
1066                || simState == IccCardConstants.State.PERM_DISABLED);
1067    }
1068
1069    public DisplayClientState getCachedDisplayClientState() {
1070        return mDisplayClientState;
1071    }
1072
1073    // TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
1074    // (KeyguardViewMediator, KeyguardHostView)
1075    public void dispatchScreenTurnedOn() {
1076        synchronized (this) {
1077            mScreenOn = true;
1078        }
1079        mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON);
1080    }
1081
1082    public void dispatchScreenTurndOff(int why) {
1083        synchronized(this) {
1084            mScreenOn = false;
1085        }
1086        mHandler.sendMessage(mHandler.obtainMessage(MSG_SCREEN_TURNED_OFF, why, 0));
1087    }
1088
1089    public boolean isScreenOn() {
1090        return mScreenOn;
1091    }
1092}
1093