KeyguardUpdateMonitor.java revision 20daffd91e4a53054f8c4d7a66c2a68100abee03
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        if (!mBootCompleted) {
639            mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
640        }
641    }
642
643    /**
644     * Handle {@link #MSG_BOOT_COMPLETED}
645     */
646    protected void handleBootCompleted() {
647        mBootCompleted = true;
648        mAudioManager = new AudioManager(mContext);
649        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
650        for (int i = 0; i < mCallbacks.size(); i++) {
651            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
652            if (cb != null) {
653                cb.onBootCompleted();
654            }
655        }
656    }
657
658    /**
659     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
660     * destroyed.
661     */
662    public boolean hasBootCompleted() {
663        return mBootCompleted;
664    }
665
666    /**
667     * Handle {@link #MSG_USER_REMOVED}
668     */
669    protected void handleUserRemoved(int userId) {
670        for (int i = 0; i < mCallbacks.size(); i++) {
671            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
672            if (cb != null) {
673                cb.onUserRemoved(userId);
674            }
675        }
676    }
677
678    /**
679     * Handle {@link #MSG_DEVICE_PROVISIONED}
680     */
681    protected void handleDeviceProvisioned() {
682        for (int i = 0; i < mCallbacks.size(); i++) {
683            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
684            if (cb != null) {
685                cb.onDeviceProvisioned();
686            }
687        }
688        if (mDeviceProvisionedObserver != null) {
689            // We don't need the observer anymore...
690            mContext.getContentResolver().unregisterContentObserver(mDeviceProvisionedObserver);
691            mDeviceProvisionedObserver = null;
692        }
693    }
694
695    /**
696     * Handle {@link #MSG_PHONE_STATE_CHANGED}
697     */
698    protected void handlePhoneStateChanged(String newState) {
699        if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
700        if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
701            mPhoneState = TelephonyManager.CALL_STATE_IDLE;
702        } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
703            mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
704        } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
705            mPhoneState = TelephonyManager.CALL_STATE_RINGING;
706        }
707        for (int i = 0; i < mCallbacks.size(); i++) {
708            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
709            if (cb != null) {
710                cb.onPhoneStateChanged(mPhoneState);
711            }
712        }
713    }
714
715    /**
716     * Handle {@link #MSG_RINGER_MODE_CHANGED}
717     */
718    protected void handleRingerModeChange(int mode) {
719        if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
720        mRingMode = mode;
721        for (int i = 0; i < mCallbacks.size(); i++) {
722            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
723            if (cb != null) {
724                cb.onRingerModeChanged(mode);
725            }
726        }
727    }
728
729    /**
730     * Handle {@link #MSG_TIME_UPDATE}
731     */
732    private void handleTimeUpdate() {
733        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
734        for (int i = 0; i < mCallbacks.size(); i++) {
735            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
736            if (cb != null) {
737                cb.onTimeChanged();
738            }
739        }
740    }
741
742    /**
743     * Handle {@link #MSG_BATTERY_UPDATE}
744     */
745    private void handleBatteryUpdate(BatteryStatus status) {
746        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
747        final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
748        mBatteryStatus = status;
749        if (batteryUpdateInteresting) {
750            for (int i = 0; i < mCallbacks.size(); i++) {
751                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
752                if (cb != null) {
753                    cb.onRefreshBatteryInfo(status);
754                }
755            }
756        }
757    }
758
759    /**
760     * Handle {@link #MSG_CARRIER_INFO_UPDATE}
761     */
762    private void handleCarrierInfoUpdate() {
763        if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
764            + ", spn = " + mTelephonySpn);
765
766        for (int i = 0; i < mCallbacks.size(); i++) {
767            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
768            if (cb != null) {
769                cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
770            }
771        }
772    }
773
774    /**
775     * Handle {@link #MSG_SIM_STATE_CHANGE}
776     */
777    private void handleSimStateChange(SimArgs simArgs) {
778        final IccCardConstants.State state = simArgs.simState;
779
780        if (DEBUG) {
781            Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
782                    + "state resolved to " + state.toString());
783        }
784
785        if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
786            mSimState = state;
787            for (int i = 0; i < mCallbacks.size(); i++) {
788                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
789                if (cb != null) {
790                    cb.onSimStateChanged(state);
791                }
792            }
793        }
794    }
795
796    /**
797     * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
798     */
799    private void handleClockVisibilityChanged() {
800        if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
801        for (int i = 0; i < mCallbacks.size(); i++) {
802            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
803            if (cb != null) {
804                cb.onClockVisibilityChanged();
805            }
806        }
807    }
808
809    /**
810     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
811     */
812    private void handleKeyguardVisibilityChanged(int showing) {
813        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
814        boolean isShowing = (showing == 1);
815        mKeyguardIsVisible = isShowing;
816        for (int i = 0; i < mCallbacks.size(); i++) {
817            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
818            if (cb != null) {
819                cb.onKeyguardVisibilityChanged(isShowing);
820            }
821        }
822    }
823
824    /**
825     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
826     */
827    private void handleReportEmergencyCallAction() {
828        for (int i = 0; i < mCallbacks.size(); i++) {
829            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
830            if (cb != null) {
831                cb.onEmergencyCallAction();
832            }
833        }
834    }
835
836    public boolean isKeyguardVisible() {
837        return mKeyguardIsVisible;
838    }
839
840    public boolean isSwitchingUser() {
841        return mSwitchingUser;
842    }
843
844    private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
845        final boolean nowPluggedIn = current.isPluggedIn();
846        final boolean wasPluggedIn = old.isPluggedIn();
847        final boolean stateChangedWhilePluggedIn =
848            wasPluggedIn == true && nowPluggedIn == true
849            && (old.status != current.status);
850
851        // change in plug state is always interesting
852        if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
853            return true;
854        }
855
856        // change in battery level while plugged in
857        if (nowPluggedIn && old.level != current.level) {
858            return true;
859        }
860
861        // change where battery needs charging
862        if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
863            return true;
864        }
865        return false;
866    }
867
868    /**
869     * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
870     * @return The string to use for the plmn, or null if it should not be shown.
871     */
872    private CharSequence getTelephonyPlmnFrom(Intent intent) {
873        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
874            final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
875            return (plmn != null) ? plmn : getDefaultPlmn();
876        }
877        return null;
878    }
879
880    /**
881     * @return The default plmn (no service)
882     */
883    private CharSequence getDefaultPlmn() {
884        return mContext.getResources().getText(R.string.keyguard_carrier_default);
885    }
886
887    /**
888     * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
889     * @return The string to use for the plmn, or null if it should not be shown.
890     */
891    private CharSequence getTelephonySpnFrom(Intent intent) {
892        if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
893            final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
894            if (spn != null) {
895                return spn;
896            }
897        }
898        return null;
899    }
900
901    /**
902     * Remove the given observer's callback.
903     *
904     * @param callback The callback to remove
905     */
906    public void removeCallback(KeyguardUpdateMonitorCallback callback) {
907        if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
908        for (int i = mCallbacks.size() - 1; i >= 0; i--) {
909            if (mCallbacks.get(i).get() == callback) {
910                mCallbacks.remove(i);
911            }
912        }
913    }
914
915    /**
916     * Register to receive notifications about general keyguard information
917     * (see {@link InfoCallback}.
918     * @param callback The callback to register
919     */
920    public void registerCallback(KeyguardUpdateMonitorCallback callback) {
921        if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
922        // Prevent adding duplicate callbacks
923        for (int i = 0; i < mCallbacks.size(); i++) {
924            if (mCallbacks.get(i).get() == callback) {
925                if (DEBUG) Log.e(TAG, "Object tried to add another callback",
926                        new Exception("Called by"));
927                return;
928            }
929        }
930        mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
931        removeCallback(null); // remove unused references
932        sendUpdates(callback);
933    }
934
935    private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
936        // Notify listener of the current state
937        callback.onRefreshBatteryInfo(mBatteryStatus);
938        callback.onTimeChanged();
939        callback.onRingerModeChanged(mRingMode);
940        callback.onPhoneStateChanged(mPhoneState);
941        callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
942        callback.onClockVisibilityChanged();
943        callback.onSimStateChanged(mSimState);
944        callback.onMusicClientIdChanged(
945                mDisplayClientState.clientGeneration,
946                mDisplayClientState.clearing,
947                mDisplayClientState.intent);
948        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
949                mDisplayClientState.playbackEventTime);
950    }
951
952    public void sendKeyguardVisibilityChanged(boolean showing) {
953        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
954        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
955        message.arg1 = showing ? 1 : 0;
956        message.sendToTarget();
957    }
958
959    public void reportClockVisible(boolean visible) {
960        mClockVisible = visible;
961        mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
962    }
963
964    public IccCardConstants.State getSimState() {
965        return mSimState;
966    }
967
968    /**
969     * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
970     * have the information earlier than waiting for the intent
971     * broadcast from the telephony code.
972     *
973     * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
974     * through mHandler, this *must* be called from the UI thread.
975     */
976    public void reportSimUnlocked() {
977        handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
978    }
979
980    /**
981     * Report that the emergency call button has been pressed and the emergency dialer is
982     * about to be displayed.
983     *
984     * @param bypassHandler runs immediately.
985     *
986     * NOTE: Must be called from UI thread if bypassHandler == true.
987     */
988    public void reportEmergencyCallAction(boolean bypassHandler) {
989        if (!bypassHandler) {
990            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
991        } else {
992            handleReportEmergencyCallAction();
993        }
994    }
995
996    public CharSequence getTelephonyPlmn() {
997        return mTelephonyPlmn;
998    }
999
1000    public CharSequence getTelephonySpn() {
1001        return mTelephonySpn;
1002    }
1003
1004    /**
1005     * @return Whether the device is provisioned (whether they have gone through
1006     *   the setup wizard)
1007     */
1008    public boolean isDeviceProvisioned() {
1009        return mDeviceProvisioned;
1010    }
1011
1012    public int getFailedUnlockAttempts() {
1013        return mFailedAttempts;
1014    }
1015
1016    public void clearFailedUnlockAttempts() {
1017        mFailedAttempts = 0;
1018        mFailedBiometricUnlockAttempts = 0;
1019    }
1020
1021    public void reportFailedUnlockAttempt() {
1022        mFailedAttempts++;
1023    }
1024
1025    public boolean isClockVisible() {
1026        return mClockVisible;
1027    }
1028
1029    public int getPhoneState() {
1030        return mPhoneState;
1031    }
1032
1033    public void reportFailedBiometricUnlockAttempt() {
1034        mFailedBiometricUnlockAttempts++;
1035    }
1036
1037    public boolean getMaxBiometricUnlockAttemptsReached() {
1038        return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
1039    }
1040
1041    public boolean isAlternateUnlockEnabled() {
1042        return mAlternateUnlockEnabled;
1043    }
1044
1045    public void setAlternateUnlockEnabled(boolean enabled) {
1046        mAlternateUnlockEnabled = enabled;
1047    }
1048
1049    public boolean isSimLocked() {
1050        return isSimLocked(mSimState);
1051    }
1052
1053    public static boolean isSimLocked(IccCardConstants.State state) {
1054        return state == IccCardConstants.State.PIN_REQUIRED
1055        || state == IccCardConstants.State.PUK_REQUIRED
1056        || state == IccCardConstants.State.PERM_DISABLED;
1057    }
1058
1059    public boolean isSimPinSecure() {
1060        return isSimPinSecure(mSimState);
1061    }
1062
1063    public static boolean isSimPinSecure(IccCardConstants.State state) {
1064        final IccCardConstants.State simState = state;
1065        return (simState == IccCardConstants.State.PIN_REQUIRED
1066                || simState == IccCardConstants.State.PUK_REQUIRED
1067                || simState == IccCardConstants.State.PERM_DISABLED);
1068    }
1069
1070    public DisplayClientState getCachedDisplayClientState() {
1071        return mDisplayClientState;
1072    }
1073
1074    // TODO: use these callbacks elsewhere in place of the existing notifyScreen*()
1075    // (KeyguardViewMediator, KeyguardHostView)
1076    public void dispatchScreenTurnedOn() {
1077        synchronized (this) {
1078            mScreenOn = true;
1079        }
1080        mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_ON);
1081    }
1082
1083    public void dispatchScreenTurndOff(int why) {
1084        synchronized(this) {
1085            mScreenOn = false;
1086        }
1087        mHandler.sendMessage(mHandler.obtainMessage(MSG_SCREEN_TURNED_OFF, why, 0));
1088    }
1089
1090    public boolean isScreenOn() {
1091        return mScreenOn;
1092    }
1093}
1094