Home | History | Annotate | Download | only in keyguard
      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 
     17 package com.android.internal.policy.impl.keyguard;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.IUserSwitchObserver;
     21 import android.app.admin.DevicePolicyManager;
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.database.ContentObserver;
     27 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
     28 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
     29 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
     30 import static android.os.BatteryManager.EXTRA_STATUS;
     31 import static android.os.BatteryManager.EXTRA_PLUGGED;
     32 import static android.os.BatteryManager.EXTRA_LEVEL;
     33 import static android.os.BatteryManager.EXTRA_HEALTH;
     34 import android.media.AudioManager;
     35 import android.os.BatteryManager;
     36 import android.os.Handler;
     37 import android.os.IRemoteCallback;
     38 import android.os.Message;
     39 import android.os.RemoteException;
     40 import android.provider.Settings;
     41 
     42 import com.android.internal.telephony.IccCardConstants;
     43 import com.android.internal.telephony.TelephonyIntents;
     44 
     45 import android.telephony.TelephonyManager;
     46 import android.util.Log;
     47 import com.android.internal.R;
     48 import com.google.android.collect.Lists;
     49 
     50 import java.lang.ref.WeakReference;
     51 import java.util.ArrayList;
     52 
     53 /**
     54  * Watches for updates that may be interesting to the keyguard, and provides
     55  * the up to date information as well as a registration for callbacks that care
     56  * to be updated.
     57  *
     58  * Note: under time crunch, this has been extended to include some stuff that
     59  * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
     60  * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
     61  * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
     62  */
     63 public class KeyguardUpdateMonitor {
     64 
     65     private static final String TAG = "KeyguardUpdateMonitor";
     66     private static final boolean DEBUG = false;
     67     private static final boolean DEBUG_SIM_STATES = DEBUG || false;
     68     private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3;
     69     private static final int LOW_BATTERY_THRESHOLD = 20;
     70 
     71     // Callback messages
     72     private static final int MSG_TIME_UPDATE = 301;
     73     private static final int MSG_BATTERY_UPDATE = 302;
     74     private static final int MSG_CARRIER_INFO_UPDATE = 303;
     75     private static final int MSG_SIM_STATE_CHANGE = 304;
     76     private static final int MSG_RINGER_MODE_CHANGED = 305;
     77     private static final int MSG_PHONE_STATE_CHANGED = 306;
     78     private static final int MSG_CLOCK_VISIBILITY_CHANGED = 307;
     79     private static final int MSG_DEVICE_PROVISIONED = 308;
     80     private static final int MSG_DPM_STATE_CHANGED = 309;
     81     private static final int MSG_USER_SWITCHED = 310;
     82     private static final int MSG_USER_REMOVED = 311;
     83     private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
     84     protected static final int MSG_BOOT_COMPLETED = 313;
     85 
     86 
     87     private static KeyguardUpdateMonitor sInstance;
     88 
     89     private final Context mContext;
     90 
     91     // Telephony state
     92     private IccCardConstants.State mSimState = IccCardConstants.State.READY;
     93     private CharSequence mTelephonyPlmn;
     94     private CharSequence mTelephonySpn;
     95     private int mRingMode;
     96     private int mPhoneState;
     97     private boolean mKeyguardIsVisible;
     98     private boolean mBootCompleted;
     99 
    100     // Device provisioning state
    101     private boolean mDeviceProvisioned;
    102 
    103     // Battery status
    104     private BatteryStatus mBatteryStatus;
    105 
    106     // Password attempts
    107     private int mFailedAttempts = 0;
    108     private int mFailedBiometricUnlockAttempts = 0;
    109 
    110     private boolean mAlternateUnlockEnabled;
    111 
    112     private boolean mClockVisible;
    113 
    114     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
    115             mCallbacks = Lists.newArrayList();
    116     private ContentObserver mContentObserver;
    117 
    118     private final Handler mHandler = new Handler() {
    119         @Override
    120         public void handleMessage(Message msg) {
    121             switch (msg.what) {
    122                 case MSG_TIME_UPDATE:
    123                     handleTimeUpdate();
    124                     break;
    125                 case MSG_BATTERY_UPDATE:
    126                     handleBatteryUpdate((BatteryStatus) msg.obj);
    127                     break;
    128                 case MSG_CARRIER_INFO_UPDATE:
    129                     handleCarrierInfoUpdate();
    130                     break;
    131                 case MSG_SIM_STATE_CHANGE:
    132                     handleSimStateChange((SimArgs) msg.obj);
    133                     break;
    134                 case MSG_RINGER_MODE_CHANGED:
    135                     handleRingerModeChange(msg.arg1);
    136                     break;
    137                 case MSG_PHONE_STATE_CHANGED:
    138                     handlePhoneStateChanged((String)msg.obj);
    139                     break;
    140                 case MSG_CLOCK_VISIBILITY_CHANGED:
    141                     handleClockVisibilityChanged();
    142                     break;
    143                 case MSG_DEVICE_PROVISIONED:
    144                     handleDeviceProvisioned();
    145                     break;
    146                 case MSG_DPM_STATE_CHANGED:
    147                     handleDevicePolicyManagerStateChanged();
    148                     break;
    149                 case MSG_USER_SWITCHED:
    150                     handleUserSwitched(msg.arg1, (IRemoteCallback)msg.obj);
    151                     break;
    152                 case MSG_USER_REMOVED:
    153                     handleUserRemoved(msg.arg1);
    154                     break;
    155                 case MSG_KEYGUARD_VISIBILITY_CHANGED:
    156                     handleKeyguardVisibilityChanged(msg.arg1);
    157                     break;
    158                 case MSG_BOOT_COMPLETED:
    159                     handleBootCompleted();
    160                     break;
    161 
    162             }
    163         }
    164     };
    165 
    166     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    167 
    168         public void onReceive(Context context, Intent intent) {
    169             final String action = intent.getAction();
    170             if (DEBUG) Log.d(TAG, "received broadcast " + action);
    171 
    172             if (Intent.ACTION_TIME_TICK.equals(action)
    173                     || Intent.ACTION_TIME_CHANGED.equals(action)
    174                     || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
    175                 mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
    176             } else if (TelephonyIntents.SPN_STRINGS_UPDATED_ACTION.equals(action)) {
    177                 mTelephonyPlmn = getTelephonyPlmnFrom(intent);
    178                 mTelephonySpn = getTelephonySpnFrom(intent);
    179                 mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
    180             } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
    181                 final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
    182                 final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
    183                 final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
    184                 final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
    185                 final Message msg = mHandler.obtainMessage(
    186                         MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
    187                 mHandler.sendMessage(msg);
    188             } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
    189                 if (DEBUG_SIM_STATES) {
    190                     Log.v(TAG, "action " + action + " state" +
    191                         intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE));
    192                 }
    193                 mHandler.sendMessage(mHandler.obtainMessage(
    194                         MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent)));
    195             } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
    196                 mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED,
    197                         intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0));
    198             } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
    199                 String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
    200                 mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
    201             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
    202                     .equals(action)) {
    203                 mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
    204             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
    205                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
    206                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
    207             } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
    208                 mHandler.sendMessage(mHandler.obtainMessage(MSG_BOOT_COMPLETED));
    209             }
    210         }
    211     };
    212 
    213     /**
    214      * When we receive a
    215      * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
    216      * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
    217      * we need a single object to pass to the handler.  This class helps decode
    218      * the intent and provide a {@link SimCard.State} result.
    219      */
    220     private static class SimArgs {
    221         public final IccCardConstants.State simState;
    222 
    223         SimArgs(IccCardConstants.State state) {
    224             simState = state;
    225         }
    226 
    227         static SimArgs fromIntent(Intent intent) {
    228             IccCardConstants.State state;
    229             if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
    230                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
    231             }
    232             String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
    233             if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
    234                 final String absentReason = intent
    235                     .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
    236 
    237                 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
    238                         absentReason)) {
    239                     state = IccCardConstants.State.PERM_DISABLED;
    240                 } else {
    241                     state = IccCardConstants.State.ABSENT;
    242                 }
    243             } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
    244                 state = IccCardConstants.State.READY;
    245             } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
    246                 final String lockedReason = intent
    247                         .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
    248                 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
    249                     state = IccCardConstants.State.PIN_REQUIRED;
    250                 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
    251                     state = IccCardConstants.State.PUK_REQUIRED;
    252                 } else {
    253                     state = IccCardConstants.State.UNKNOWN;
    254                 }
    255             } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
    256                 state = IccCardConstants.State.NETWORK_LOCKED;
    257             } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
    258                         || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
    259                 // This is required because telephony doesn't return to "READY" after
    260                 // these state transitions. See bug 7197471.
    261                 state = IccCardConstants.State.READY;
    262             } else {
    263                 state = IccCardConstants.State.UNKNOWN;
    264             }
    265             return new SimArgs(state);
    266         }
    267 
    268         public String toString() {
    269             return simState.toString();
    270         }
    271     }
    272 
    273     /* package */ static class BatteryStatus {
    274         public final int status;
    275         public final int level;
    276         public final int plugged;
    277         public final int health;
    278         public BatteryStatus(int status, int level, int plugged, int health) {
    279             this.status = status;
    280             this.level = level;
    281             this.plugged = plugged;
    282             this.health = health;
    283         }
    284 
    285         /**
    286          * Determine whether the device is plugged in (USB, power, or wireless).
    287          * @return true if the device is plugged in.
    288          */
    289         boolean isPluggedIn() {
    290             return plugged == BatteryManager.BATTERY_PLUGGED_AC
    291                     || plugged == BatteryManager.BATTERY_PLUGGED_USB
    292                     || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
    293         }
    294 
    295         /**
    296          * Whether or not the device is charged. Note that some devices never return 100% for
    297          * battery level, so this allows either battery level or status to determine if the
    298          * battery is charged.
    299          * @return true if the device is charged
    300          */
    301         public boolean isCharged() {
    302             return status == BATTERY_STATUS_FULL || level >= 100;
    303         }
    304 
    305         /**
    306          * Whether battery is low and needs to be charged.
    307          * @return true if battery is low
    308          */
    309         public boolean isBatteryLow() {
    310             return level < LOW_BATTERY_THRESHOLD;
    311         }
    312 
    313     }
    314 
    315     public static KeyguardUpdateMonitor getInstance(Context context) {
    316         if (sInstance == null) {
    317             sInstance = new KeyguardUpdateMonitor(context);
    318         }
    319         return sInstance;
    320     }
    321 
    322     private KeyguardUpdateMonitor(Context context) {
    323         mContext = context;
    324 
    325         mDeviceProvisioned = Settings.Global.getInt(
    326                 mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
    327 
    328         // Since device can't be un-provisioned, we only need to register a content observer
    329         // to update mDeviceProvisioned when we are...
    330         if (!mDeviceProvisioned) {
    331             watchForDeviceProvisioning();
    332         }
    333 
    334         // Take a guess at initial SIM state, battery status and PLMN until we get an update
    335         mSimState = IccCardConstants.State.NOT_READY;
    336         mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0);
    337         mTelephonyPlmn = getDefaultPlmn();
    338 
    339         // Watch for interesting updates
    340         final IntentFilter filter = new IntentFilter();
    341         filter.addAction(Intent.ACTION_TIME_TICK);
    342         filter.addAction(Intent.ACTION_TIME_CHANGED);
    343         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
    344         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
    345         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
    346         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
    347         filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
    348         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
    349         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    350         filter.addAction(Intent.ACTION_USER_REMOVED);
    351         context.registerReceiver(mBroadcastReceiver, filter);
    352 
    353         final IntentFilter bootCompleteFilter = new IntentFilter();
    354         bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
    355         bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
    356         context.registerReceiver(mBroadcastReceiver, bootCompleteFilter);
    357 
    358         try {
    359             ActivityManagerNative.getDefault().registerUserSwitchObserver(
    360                     new IUserSwitchObserver.Stub() {
    361                         @Override
    362                         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
    363                             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
    364                                     newUserId, 0, reply));
    365                         }
    366                         @Override
    367                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
    368                         }
    369                     });
    370         } catch (RemoteException e) {
    371             // TODO Auto-generated catch block
    372             e.printStackTrace();
    373         }
    374     }
    375 
    376     private void watchForDeviceProvisioning() {
    377         mContentObserver = new ContentObserver(mHandler) {
    378             @Override
    379             public void onChange(boolean selfChange) {
    380                 super.onChange(selfChange);
    381                 mDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
    382                     Settings.Global.DEVICE_PROVISIONED, 0) != 0;
    383                 if (mDeviceProvisioned) {
    384                     mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
    385                 }
    386                 if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
    387             }
    388         };
    389 
    390         mContext.getContentResolver().registerContentObserver(
    391                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
    392                 false, mContentObserver);
    393 
    394         // prevent a race condition between where we check the flag and where we register the
    395         // observer by grabbing the value once again...
    396         boolean provisioned = Settings.Global.getInt(mContext.getContentResolver(),
    397             Settings.Global.DEVICE_PROVISIONED, 0) != 0;
    398         if (provisioned != mDeviceProvisioned) {
    399             mDeviceProvisioned = provisioned;
    400             if (mDeviceProvisioned) {
    401                 mHandler.sendMessage(mHandler.obtainMessage(MSG_DEVICE_PROVISIONED));
    402             }
    403         }
    404     }
    405 
    406     /**
    407      * Handle {@link #MSG_DPM_STATE_CHANGED}
    408      */
    409     protected void handleDevicePolicyManagerStateChanged() {
    410         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
    411             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    412             if (cb != null) {
    413                 cb.onDevicePolicyManagerStateChanged();
    414             }
    415         }
    416     }
    417 
    418     /**
    419      * Handle {@link #MSG_USER_SWITCHED}
    420      */
    421     protected void handleUserSwitched(int userId, IRemoteCallback reply) {
    422         for (int i = 0; i < mCallbacks.size(); i++) {
    423             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    424             if (cb != null) {
    425                 cb.onUserSwitched(userId);
    426             }
    427         }
    428         setAlternateUnlockEnabled(false);
    429         try {
    430             reply.sendResult(null);
    431         } catch (RemoteException e) {
    432         }
    433     }
    434 
    435     /**
    436      * Handle {@link #MSG_BOOT_COMPLETED}
    437      */
    438     protected void handleBootCompleted() {
    439         mBootCompleted = true;
    440         for (int i = 0; i < mCallbacks.size(); i++) {
    441             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    442             if (cb != null) {
    443                 cb.onBootCompleted();
    444             }
    445         }
    446     }
    447 
    448     /**
    449      * We need to store this state in the KeyguardUpdateMonitor since this class will not be
    450      * destroyed.
    451      */
    452     public boolean hasBootCompleted() {
    453         return mBootCompleted;
    454     }
    455 
    456     /**
    457      * Handle {@link #MSG_USER_SWITCHED}
    458      */
    459     protected void handleUserRemoved(int userId) {
    460         for (int i = 0; i < mCallbacks.size(); i++) {
    461             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    462             if (cb != null) {
    463                 cb.onUserRemoved(userId);
    464             }
    465         }
    466     }
    467 
    468     /**
    469      * Handle {@link #MSG_DEVICE_PROVISIONED}
    470      */
    471     protected void handleDeviceProvisioned() {
    472         for (int i = 0; i < mCallbacks.size(); i++) {
    473             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    474             if (cb != null) {
    475                 cb.onDeviceProvisioned();
    476             }
    477         }
    478         if (mContentObserver != null) {
    479             // We don't need the observer anymore...
    480             mContext.getContentResolver().unregisterContentObserver(mContentObserver);
    481             mContentObserver = null;
    482         }
    483     }
    484 
    485     /**
    486      * Handle {@link #MSG_PHONE_STATE_CHANGED}
    487      */
    488     protected void handlePhoneStateChanged(String newState) {
    489         if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")");
    490         if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) {
    491             mPhoneState = TelephonyManager.CALL_STATE_IDLE;
    492         } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) {
    493             mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK;
    494         } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) {
    495             mPhoneState = TelephonyManager.CALL_STATE_RINGING;
    496         }
    497         for (int i = 0; i < mCallbacks.size(); i++) {
    498             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    499             if (cb != null) {
    500                 cb.onPhoneStateChanged(mPhoneState);
    501             }
    502         }
    503     }
    504 
    505     /**
    506      * Handle {@link #MSG_RINGER_MODE_CHANGED}
    507      */
    508     protected void handleRingerModeChange(int mode) {
    509         if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")");
    510         mRingMode = mode;
    511         for (int i = 0; i < mCallbacks.size(); i++) {
    512             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    513             if (cb != null) {
    514                 cb.onRingerModeChanged(mode);
    515             }
    516         }
    517     }
    518 
    519     /**
    520      * Handle {@link #MSG_TIME_UPDATE}
    521      */
    522     private void handleTimeUpdate() {
    523         if (DEBUG) Log.d(TAG, "handleTimeUpdate");
    524         for (int i = 0; i < mCallbacks.size(); i++) {
    525             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    526             if (cb != null) {
    527                 cb.onTimeChanged();
    528             }
    529         }
    530     }
    531 
    532     /**
    533      * Handle {@link #MSG_BATTERY_UPDATE}
    534      */
    535     private void handleBatteryUpdate(BatteryStatus status) {
    536         if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
    537         final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
    538         mBatteryStatus = status;
    539         if (batteryUpdateInteresting) {
    540             for (int i = 0; i < mCallbacks.size(); i++) {
    541                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    542                 if (cb != null) {
    543                     cb.onRefreshBatteryInfo(status);
    544                 }
    545             }
    546         }
    547     }
    548 
    549     /**
    550      * Handle {@link #MSG_CARRIER_INFO_UPDATE}
    551      */
    552     private void handleCarrierInfoUpdate() {
    553         if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
    554             + ", spn = " + mTelephonySpn);
    555 
    556         for (int i = 0; i < mCallbacks.size(); i++) {
    557             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    558             if (cb != null) {
    559                 cb.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
    560             }
    561         }
    562     }
    563 
    564     /**
    565      * Handle {@link #MSG_SIM_STATE_CHANGE}
    566      */
    567     private void handleSimStateChange(SimArgs simArgs) {
    568         final IccCardConstants.State state = simArgs.simState;
    569 
    570         if (DEBUG) {
    571             Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
    572                     + "state resolved to " + state.toString());
    573         }
    574 
    575         if (state != IccCardConstants.State.UNKNOWN && state != mSimState) {
    576             mSimState = state;
    577             for (int i = 0; i < mCallbacks.size(); i++) {
    578                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    579                 if (cb != null) {
    580                     cb.onSimStateChanged(state);
    581                 }
    582             }
    583         }
    584     }
    585 
    586     /**
    587      * Handle {@link #MSG_CLOCK_VISIBILITY_CHANGED}
    588      */
    589     private void handleClockVisibilityChanged() {
    590         if (DEBUG) Log.d(TAG, "handleClockVisibilityChanged()");
    591         for (int i = 0; i < mCallbacks.size(); i++) {
    592             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    593             if (cb != null) {
    594                 cb.onClockVisibilityChanged();
    595             }
    596         }
    597     }
    598 
    599     /**
    600      * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
    601      */
    602     private void handleKeyguardVisibilityChanged(int showing) {
    603         if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
    604         boolean isShowing = (showing == 1);
    605         mKeyguardIsVisible = isShowing;
    606         for (int i = 0; i < mCallbacks.size(); i++) {
    607             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
    608             if (cb != null) {
    609                 cb.onKeyguardVisibilityChanged(isShowing);
    610             }
    611         }
    612     }
    613 
    614     public boolean isKeyguardVisible() {
    615         return mKeyguardIsVisible;
    616     }
    617 
    618     private static boolean isBatteryUpdateInteresting(BatteryStatus old, BatteryStatus current) {
    619         final boolean nowPluggedIn = current.isPluggedIn();
    620         final boolean wasPluggedIn = old.isPluggedIn();
    621         final boolean stateChangedWhilePluggedIn =
    622             wasPluggedIn == true && nowPluggedIn == true
    623             && (old.status != current.status);
    624 
    625         // change in plug state is always interesting
    626         if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
    627             return true;
    628         }
    629 
    630         // change in battery level while plugged in
    631         if (nowPluggedIn && old.level != current.level) {
    632             return true;
    633         }
    634 
    635         // change where battery needs charging
    636         if (!nowPluggedIn && current.isBatteryLow() && current.level != old.level) {
    637             return true;
    638         }
    639         return false;
    640     }
    641 
    642     /**
    643      * @param intent The intent with action {@link TelephonyIntents#SPN_STRINGS_UPDATED_ACTION}
    644      * @return The string to use for the plmn, or null if it should not be shown.
    645      */
    646     private CharSequence getTelephonyPlmnFrom(Intent intent) {
    647         if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
    648             final String plmn = intent.getStringExtra(TelephonyIntents.EXTRA_PLMN);
    649             return (plmn != null) ? plmn : getDefaultPlmn();
    650         }
    651         return null;
    652     }
    653 
    654     /**
    655      * @return The default plmn (no service)
    656      */
    657     private CharSequence getDefaultPlmn() {
    658         return mContext.getResources().getText(R.string.lockscreen_carrier_default);
    659     }
    660 
    661     /**
    662      * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
    663      * @return The string to use for the plmn, or null if it should not be shown.
    664      */
    665     private CharSequence getTelephonySpnFrom(Intent intent) {
    666         if (intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
    667             final String spn = intent.getStringExtra(TelephonyIntents.EXTRA_SPN);
    668             if (spn != null) {
    669                 return spn;
    670             }
    671         }
    672         return null;
    673     }
    674 
    675     /**
    676      * Remove the given observer's callback.
    677      *
    678      * @param callback The callback to remove
    679      */
    680     public void removeCallback(KeyguardUpdateMonitorCallback callback) {
    681         if (DEBUG) Log.v(TAG, "*** unregister callback for " + callback);
    682         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
    683             if (mCallbacks.get(i).get() == callback) {
    684                 mCallbacks.remove(i);
    685             }
    686         }
    687     }
    688 
    689     /**
    690      * Register to receive notifications about general keyguard information
    691      * (see {@link InfoCallback}.
    692      * @param callback The callback to register
    693      */
    694     public void registerCallback(KeyguardUpdateMonitorCallback callback) {
    695         if (DEBUG) Log.v(TAG, "*** register callback for " + callback);
    696         // Prevent adding duplicate callbacks
    697         for (int i = 0; i < mCallbacks.size(); i++) {
    698             if (mCallbacks.get(i).get() == callback) {
    699                 if (DEBUG) Log.e(TAG, "Object tried to add another callback",
    700                         new Exception("Called by"));
    701                 return;
    702             }
    703         }
    704         mCallbacks.add(new WeakReference<KeyguardUpdateMonitorCallback>(callback));
    705         removeCallback(null); // remove unused references
    706         sendUpdates(callback);
    707     }
    708 
    709     private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
    710         // Notify listener of the current state
    711         callback.onRefreshBatteryInfo(mBatteryStatus);
    712         callback.onTimeChanged();
    713         callback.onRingerModeChanged(mRingMode);
    714         callback.onPhoneStateChanged(mPhoneState);
    715         callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
    716         callback.onClockVisibilityChanged();
    717         callback.onSimStateChanged(mSimState);
    718     }
    719 
    720     public void sendKeyguardVisibilityChanged(boolean showing) {
    721         if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
    722         Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
    723         message.arg1 = showing ? 1 : 0;
    724         message.sendToTarget();
    725     }
    726 
    727     public void reportClockVisible(boolean visible) {
    728         mClockVisible = visible;
    729         mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget();
    730     }
    731 
    732     public IccCardConstants.State getSimState() {
    733         return mSimState;
    734     }
    735 
    736     /**
    737      * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we
    738      * have the information earlier than waiting for the intent
    739      * broadcast from the telephony code.
    740      *
    741      * NOTE: Because handleSimStateChange() invokes callbacks immediately without going
    742      * through mHandler, this *must* be called from the UI thread.
    743      */
    744     public void reportSimUnlocked() {
    745         handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
    746     }
    747 
    748     public CharSequence getTelephonyPlmn() {
    749         return mTelephonyPlmn;
    750     }
    751 
    752     public CharSequence getTelephonySpn() {
    753         return mTelephonySpn;
    754     }
    755 
    756     /**
    757      * @return Whether the device is provisioned (whether they have gone through
    758      *   the setup wizard)
    759      */
    760     public boolean isDeviceProvisioned() {
    761         return mDeviceProvisioned;
    762     }
    763 
    764     public int getFailedUnlockAttempts() {
    765         return mFailedAttempts;
    766     }
    767 
    768     public void clearFailedUnlockAttempts() {
    769         mFailedAttempts = 0;
    770         mFailedBiometricUnlockAttempts = 0;
    771     }
    772 
    773     public void reportFailedUnlockAttempt() {
    774         mFailedAttempts++;
    775     }
    776 
    777     public boolean isClockVisible() {
    778         return mClockVisible;
    779     }
    780 
    781     public int getPhoneState() {
    782         return mPhoneState;
    783     }
    784 
    785     public void reportFailedBiometricUnlockAttempt() {
    786         mFailedBiometricUnlockAttempts++;
    787     }
    788 
    789     public boolean getMaxBiometricUnlockAttemptsReached() {
    790         return mFailedBiometricUnlockAttempts >= FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP;
    791     }
    792 
    793     public boolean isAlternateUnlockEnabled() {
    794         return mAlternateUnlockEnabled;
    795     }
    796 
    797     public void setAlternateUnlockEnabled(boolean enabled) {
    798         mAlternateUnlockEnabled = enabled;
    799     }
    800 
    801     public boolean isSimLocked() {
    802         return isSimLocked(mSimState);
    803     }
    804 
    805     public static boolean isSimLocked(IccCardConstants.State state) {
    806         return state == IccCardConstants.State.PIN_REQUIRED
    807         || state == IccCardConstants.State.PUK_REQUIRED
    808         || state == IccCardConstants.State.PERM_DISABLED;
    809     }
    810 
    811     public boolean isSimPinSecure() {
    812         return isSimPinSecure(mSimState);
    813     }
    814 
    815     public static boolean isSimPinSecure(IccCardConstants.State state) {
    816         final IccCardConstants.State simState = state;
    817         return (simState == IccCardConstants.State.PIN_REQUIRED
    818                 || simState == IccCardConstants.State.PUK_REQUIRED
    819                 || simState == IccCardConstants.State.PERM_DISABLED);
    820     }
    821 }
    822