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