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