FileDocCategorySizeDatePackage
KeyguardUpdateMonitor.javaAPI DocAndroid 1.5 API20418Wed May 06 22:42:06 BST 2009com.android.internal.policy.impl

KeyguardUpdateMonitor

public class KeyguardUpdateMonitor extends Object
Watches for updates that may be interesting to the keyguard, and provides the up to date information as well as a registration for callbacks that care to be updated. Note: under time crunch, this has been extended to include some stuff that doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()} and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'...

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
private static final int
LOW_BATTERY_THRESHOLD
private final android.content.Context
mContext
private SimCard.State
mSimState
private boolean
mInPortrait
private boolean
mKeyboardOpen
private boolean
mDevicePluggedIn
private boolean
mDeviceProvisioned
private int
mBatteryLevel
private CharSequence
mTelephonyPlmn
private CharSequence
mTelephonySpn
private int
mFailedAttempts
private android.os.Handler
mHandler
private ArrayList
mConfigurationChangeCallbacks
private ArrayList
mInfoCallbacks
private ArrayList
mSimStateCallbacks
private android.database.ContentObserver
mContentObserver
private static final int
MSG_CONFIGURATION_CHANGED
private static final int
MSG_TIME_UPDATE
private static final int
MSG_BATTERY_UPDATE
private static final int
MSG_CARRIER_INFO_UPDATE
private static final int
MSG_SIM_STATE_CHANGE
Constructors Summary
public KeyguardUpdateMonitor(android.content.Context context)

        mContext = context;
        
        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_CONFIGURATION_CHANGED:
                        handleConfigurationChange();
                        break;
                    case MSG_TIME_UPDATE:
                        handleTimeUpdate();
                        break;
                    case MSG_BATTERY_UPDATE:
                        handleBatteryUpdate(msg.arg1,  msg.arg2);
                        break;
                    case MSG_CARRIER_INFO_UPDATE:
                        handleCarrierInfoUpdate();
                        break;
                    case MSG_SIM_STATE_CHANGE:
                        handleSimStateChange((SimArgs) msg.obj);
                        break;
                }
            }
        };

        mDeviceProvisioned = Settings.Secure.getInt(
                mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
     
        // Since device can't be un-provisioned, we only need to register a content observer
        // to update mDeviceProvisioned when we are...
        if (!mDeviceProvisioned) {
            mContentObserver = new ContentObserver(mHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    super.onChange(selfChange);
                    mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), 
                        Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
                    if (mDeviceProvisioned && mContentObserver != null) {
                        // We don't need the observer anymore...
                        mContext.getContentResolver().unregisterContentObserver(mContentObserver);
                        mContentObserver = null;
                    }
                    if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
                }
            };
            
            mContext.getContentResolver().registerContentObserver(
                    Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED),
                    false, mContentObserver);
            
            // prevent a race condition between where we check the flag and where we register the
            // observer by grabbing the value once again...
            mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), 
                Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
        }
        
        mInPortrait = queryInPortrait();
        mKeyboardOpen = queryKeyboardOpen();

        // take a guess to start
        mSimState = SimCard.State.READY;
        mDevicePluggedIn = true;
        mBatteryLevel = 100;

        mTelephonyPlmn = getDefaultPlmn();

        // setup receiver
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(SPN_STRINGS_UPDATED_ACTION);
        context.registerReceiver(new BroadcastReceiver() {

            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (DEBUG) Log.d(TAG, "received broadcast " + action);

                if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED));
                } else if (Intent.ACTION_TIME_TICK.equals(action)
                        || Intent.ACTION_TIME_CHANGED.equals(action)
                        || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
                } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) {
                    mTelephonyPlmn = getTelephonyPlmnFrom(intent);
                    mTelephonySpn = getTelephonySpnFrom(intent);
                    mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
                } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
                    final int pluggedInStatus = intent
                            .getIntExtra("status", BATTERY_STATUS_UNKNOWN);
                    int batteryLevel = intent.getIntExtra("level", 0);
                    final Message msg = mHandler.obtainMessage(
                            MSG_BATTERY_UPDATE,
                            pluggedInStatus,
                            batteryLevel);
                    mHandler.sendMessage(msg);
                } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
                    mHandler.sendMessage(mHandler.obtainMessage(
                            MSG_SIM_STATE_CHANGE,
                            new SimArgs(intent)));
                }
            }
        }, filter);
    
Methods Summary
public voidclearFailedAttempts()

        mFailedAttempts = 0;
    
public intgetBatteryLevel()

        return mBatteryLevel;
    
private java.lang.CharSequencegetDefaultPlmn()

return
The default plmn (no service)

        return mContext.getResources().getText(
                        R.string.lockscreen_carrier_default);
    
public intgetFailedAttempts()

        return mFailedAttempts;
    
public SimCard.StategetSimState()

        return mSimState;
    
public java.lang.CharSequencegetTelephonyPlmn()

        return mTelephonyPlmn;
    
private java.lang.CharSequencegetTelephonyPlmnFrom(android.content.Intent intent)

param
intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
return
The string to use for the plmn, or null if it should not be shown.

        if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) {
            final String plmn = intent.getStringExtra(EXTRA_PLMN);
            if (plmn != null) {
                return plmn;
            } else {
                return getDefaultPlmn();
            }
        }
        return null;
    
public java.lang.CharSequencegetTelephonySpn()

        return mTelephonySpn;
    
private java.lang.CharSequencegetTelephonySpnFrom(android.content.Intent intent)

param
intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
return
The string to use for the plmn, or null if it should not be shown.

        if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) {
            final String spn = intent.getStringExtra(EXTRA_SPN);
            if (spn != null) {
                return spn;
            }
        }
        return null;
    
private voidhandleBatteryUpdate(int pluggedInStatus, int batteryLevel)
Handle {@link #MSG_BATTERY_UPDATE}

        if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
        final boolean pluggedIn = isPluggedIn(pluggedInStatus);

        if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) {
            mBatteryLevel = batteryLevel;
            mDevicePluggedIn = pluggedIn;
            for (int i = 0; i < mInfoCallbacks.size(); i++) {
                mInfoCallbacks.get(i).onRefreshBatteryInfo(
                        shouldShowBatteryInfo(), pluggedIn, batteryLevel);
            }
        }

        // shut down gracefully if our battery is critically low and we are not powered
        if (batteryLevel == 0 &&
                pluggedInStatus != BATTERY_STATUS_CHARGING &&
                pluggedInStatus != BATTERY_STATUS_UNKNOWN) {
            ShutdownThread.shutdownAfterDisablingRadio(mContext, false);
        }
    
private voidhandleCarrierInfoUpdate()
Handle {@link #MSG_CARRIER_INFO_UPDATE}

        if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
            + ", spn = " + mTelephonySpn);

        for (int i = 0; i < mInfoCallbacks.size(); i++) {
            mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
        }
    
private voidhandleConfigurationChange()
Handle {@link #MSG_CONFIGURATION_CHANGED}

        if (DEBUG) Log.d(TAG, "handleConfigurationChange");

        final boolean inPortrait = queryInPortrait();
        if (mInPortrait != inPortrait) {
            mInPortrait = inPortrait;
            for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
                mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait);
            }
        }

        final boolean keyboardOpen = queryKeyboardOpen();
        if (mKeyboardOpen != keyboardOpen) {
            mKeyboardOpen = keyboardOpen;
            for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
                mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen);
            }
        }
    
private voidhandleSimStateChange(com.android.internal.policy.impl.KeyguardUpdateMonitor$SimArgs simArgs)
Handle {@link #MSG_SIM_STATE_CHANGE}

        final SimCard.State state = simArgs.simState;

        if (DEBUG) {
            Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
                    + "state resolved to " + state.toString());
        }

        if (state != SimCard.State.UNKNOWN && state != mSimState) {
            mSimState = state;
            for (int i = 0; i < mSimStateCallbacks.size(); i++) {
                mSimStateCallbacks.get(i).onSimStateChanged(state);
            }
        }
    
private voidhandleTimeUpdate()
Handle {@link #MSG_TIME_UPDATE}

        if (DEBUG) Log.d(TAG, "handleTimeUpdate");
        for (int i = 0; i < mInfoCallbacks.size(); i++) {
            mInfoCallbacks.get(i).onTimeChanged();
        }
    
private booleanisBatteryUpdateInteresting(boolean pluggedIn, int batteryLevel)

        // change in plug is always interesting
        if (mDevicePluggedIn != pluggedIn) {
            return true;
        }

        // change in battery level while plugged in
        if (pluggedIn && mBatteryLevel != batteryLevel) {
            return true;
        }

        if (!pluggedIn) {
            // not plugged in and going below threshold
            if (batteryLevel < LOW_BATTERY_THRESHOLD
                    && mBatteryLevel >= LOW_BATTERY_THRESHOLD) {
                return true;
            }
            // not plugged in and going above threshold (sounds impossible, but, meh...)
            if (mBatteryLevel < LOW_BATTERY_THRESHOLD
                    && batteryLevel >= LOW_BATTERY_THRESHOLD) {
                return true;
            }
        }
        return false;
    
public booleanisDevicePluggedIn()

        return mDevicePluggedIn;
    
public booleanisDeviceProvisioned()

return
Whether the device is provisioned (whether they have gone through the setup wizard)

        return mDeviceProvisioned;
    
public booleanisInPortrait()

        return mInPortrait;
    
public booleanisKeyboardOpen()

        return mKeyboardOpen;
    
private booleanisPluggedIn(int status)

param
status One of the statuses of {@link android.os.BatteryManager}
return
Whether the status maps to a status for being plugged in.

        return status == BATTERY_STATUS_CHARGING || status == BATTERY_STATUS_FULL;
    
booleanqueryInPortrait()
What is the current orientation?

        final Configuration configuration = mContext.getResources().getConfiguration();
        return configuration.orientation == Configuration.ORIENTATION_PORTRAIT;
    
booleanqueryKeyboardOpen()
Is the (hard) keyboard currently open?

        final Configuration configuration = mContext.getResources().getConfiguration();

        return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
    
public voidregisterConfigurationChangeCallback(com.android.internal.policy.impl.KeyguardUpdateMonitor$ConfigurationChangeCallback callback)
Register to receive notifications about configuration changes.

param
callback The callback.

        mConfigurationChangeCallbacks.add(callback);
    
public voidregisterInfoCallback(com.android.internal.policy.impl.KeyguardUpdateMonitor$InfoCallback callback)
Register to receive notifications about general keyguard information (see {@link InfoCallback}.

param
callback The callback.

        mInfoCallbacks.add(callback);
    
public voidregisterSimStateCallback(com.android.internal.policy.impl.KeyguardUpdateMonitor$SimStateCallback callback)
Register to be notified of sim state changes.

param
callback The callback.

        mSimStateCallbacks.add(callback);
    
public voidremoveCallback(java.lang.Object observer)
Remove the given observer from being registered from any of the kinds of callbacks.

param
observer The observer to remove (an instance of {@link ConfigurationChangeCallback}, {@link InfoCallback} or {@link SimStateCallback}

        mConfigurationChangeCallbacks.remove(observer);
        mInfoCallbacks.remove(observer);
        mSimStateCallbacks.remove(observer);
    
public voidreportFailedAttempt()

        mFailedAttempts++;
    
public voidreportSimPinUnlocked()
Report that the user succesfully entered the sim pin so we have the information earlier than waiting for the intent broadcast from the telephony code.

        mSimState = SimCard.State.READY;
    
public booleanshouldShowBatteryInfo()

        return mDevicePluggedIn || mBatteryLevel < LOW_BATTERY_THRESHOLD;