From 3f5f83b54fad4c797f5dbd75f050e4980e839122 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Mon, 26 Sep 2011 15:17:05 -0700 Subject: [PATCH] Fix 5326463: rework sim state handling in lockscreen Previously it was possible to get an inconsistent state because there were two paths that updated the lock screen sim state. This reworks the data flow to ensure the same path is always used to update the state. KeyguardUpdateMonitor now correctly updates the entire state of the callee whenever a new callback is registered. In addition, KeyguardUpdateMonitor now caches the phone state in order to avoid a round-trip binder call in updateEmergencyCallButtonState(). This avoids a condition that could make lockscreen unresponsive while updating the emergency call button state. KeyguardStatusViewManager also ensures the TransportControlView is hidden when created to ensure we don't inappropriately update the carrier line while waiting for the first callbacks to update the status lines. Change-Id: I6b3975b703a7d90bac8d0fe29fbc0f1d9c5e0e7d --- .../internal/widget/LockPatternUtils.java | 28 ++----- .../impl/KeyguardStatusViewManager.java | 84 +++++++++++++------ .../policy/impl/KeyguardUpdateMonitor.java | 26 ++++-- .../policy/impl/KeyguardViewMediator.java | 6 +- 4 files changed, 88 insertions(+), 56 deletions(-) diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index e3a4df9358f90..c6b2cc7b00f07 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -936,10 +936,15 @@ public class LockPatternUtils { * * If there's currently a call in progress, the button will take them to the call * @param button the button to update + * @param the phone state: + * {@link TelephonyManager#CALL_STATE_IDLE} + * {@link TelephonyManager#CALL_STATE_RINGING} + * {@link TelephonyManager#CALL_STATE_OFFHOOK} * @param showIfCapable indicates whether the button should be shown if emergency calls are * possible on the device */ - public void updateEmergencyCallButtonState(Button button, boolean showIfCapable) { + public void updateEmergencyCallButtonState(Button button, int phoneState, + boolean showIfCapable) { if (isEmergencyCallCapable() && showIfCapable) { button.setVisibility(View.VISIBLE); } else { @@ -947,9 +952,8 @@ public class LockPatternUtils { return; } - int newState = TelephonyManager.getDefault().getCallState(); int textId; - if (newState == TelephonyManager.CALL_STATE_OFFHOOK) { + if (phoneState == TelephonyManager.CALL_STATE_OFFHOOK) { // show "return to call" text and show phone icon textId = R.string.lockscreen_return_to_call; int phoneCallIcon = R.drawable.stat_sys_phone_call; @@ -979,22 +983,4 @@ public class LockPatternUtils { } return false; } - - /** - * Performs concentenation of PLMN/SPN - * @param plmn - * @param spn - * @return - */ - public static CharSequence getCarrierString(CharSequence plmn, CharSequence spn) { - if (plmn != null && spn == null) { - return plmn; - } else if (plmn != null && spn != null) { - return plmn + "|" + spn; - } else if (plmn == null && spn != null) { - return spn; - } else { - return ""; - } - } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java index 61e30bfba05c4..24dce1a0dd791 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java @@ -58,6 +58,7 @@ class KeyguardStatusViewManager implements OnClickListener { private static final int CARRIER_HELP_TEXT = 12; private static final int HELP_MESSAGE_TEXT = 13; private static final int OWNER_INFO = 14; + private static final int BATTERY_INFO = 15; private StatusMode mStatus; private String mDateFormatString; @@ -84,6 +85,9 @@ class KeyguardStatusViewManager implements OnClickListener { // last known battery level private int mBatteryLevel = 100; + // last known SIM state + protected State mSimState; + private LockPatternUtils mLockPatternUtils; private KeyguardUpdateMonitor mUpdateMonitor; private Button mEmergencyCallButton; @@ -98,6 +102,8 @@ class KeyguardStatusViewManager implements OnClickListener { private boolean mShowingStatus; private KeyguardScreenCallback mCallback; private final boolean mShowEmergencyButtonByDefault; + private CharSequence mPlmn; + private CharSequence mSpn; private class TransientTextManager { private TextView mTextView; @@ -151,6 +157,7 @@ class KeyguardStatusViewManager implements OnClickListener { public KeyguardStatusViewManager(View view, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils, KeyguardScreenCallback callback, boolean showEmergencyButtonByDefault) { + if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()"); mContainer = view; mDateFormatString = getContext().getString(R.string.full_wday_month_day_no_year); mLockPatternUtils = lockPatternUtils; @@ -165,6 +172,12 @@ class KeyguardStatusViewManager implements OnClickListener { mTransportView = (TransportControlView) findViewById(R.id.transport); mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton); mShowEmergencyButtonByDefault = showEmergencyButtonByDefault; + + // Hide transport control view until we know we need to show it. + if (mTransportView != null) { + mTransportView.setVisibility(View.GONE); + } + if (mEmergencyCallButton != null) { mEmergencyCallButton.setText(R.string.lockscreen_emergency_call); mEmergencyCallButton.setOnClickListener(this); @@ -173,8 +186,6 @@ class KeyguardStatusViewManager implements OnClickListener { mTransientTextManager = new TransientTextManager(mCarrierView); - updateEmergencyCallButtonState(); - resetStatusInfo(); refreshDate(); updateOwnerInfo(); @@ -187,10 +198,6 @@ class KeyguardStatusViewManager implements OnClickListener { v.setSelected(true); } } - - // until we get an update... - setCarrierText(LockPatternUtils.getCarrierString( - mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn())); } private boolean inWidgetMode() { @@ -248,6 +255,7 @@ class KeyguardStatusViewManager implements OnClickListener { case INSTRUCTION_TEXT: case CARRIER_HELP_TEXT: case HELP_MESSAGE_TEXT: + case BATTERY_INFO: mTransientTextManager.post(string, 0, INSTRUCTION_RESET_DELAY); break; @@ -262,15 +270,16 @@ class KeyguardStatusViewManager implements OnClickListener { } public void onPause() { + if (DEBUG) Log.v(TAG, "onPause()"); mUpdateMonitor.removeCallback(mInfoCallback); mUpdateMonitor.removeCallback(mSimStateCallback); } /** {@inheritDoc} */ public void onResume() { + if (DEBUG) Log.v(TAG, "onResume()"); mUpdateMonitor.registerInfoCallback(mInfoCallback); mUpdateMonitor.registerSimStateCallback(mSimStateCallback); - updateEmergencyCallButtonState(); resetStatusInfo(); } @@ -399,7 +408,12 @@ class KeyguardStatusViewManager implements OnClickListener { * Determine the current status of the lock screen given the sim state and other stuff. */ public StatusMode getStatusForIccState(IccCard.State simState) { - boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() + // Since reading the SIM may take a while, we assume it is present until told otherwise. + if (simState == null) { + return StatusMode.Normal; + } + + final boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned() && (simState == IccCard.State.ABSENT || simState == IccCard.State.PERM_DISABLED)); // Assume we're NETWORK_LOCKED if not provisioned @@ -435,22 +449,21 @@ class KeyguardStatusViewManager implements OnClickListener { * * @param simState */ - private void updateWithSimStatus(State simState) { - // The emergency call button no longer appears on this screen. - if (DEBUG) Log.d(TAG, "updateLayout: status=" + mStatus); + private void updateCarrierTextWithSimStatus(State simState) { + if (DEBUG) Log.d(TAG, "updateCarrierTextWithSimStatus(), simState = " + simState); CharSequence carrierText = null; int carrierHelpTextId = 0; mUnlockDisabledDueToSimState = false; mStatus = getStatusForIccState(simState); + mSimState = simState; switch (mStatus) { case Normal: - carrierText = LockPatternUtils.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), - mUpdateMonitor.getTelephonySpn()); + carrierText = makeCarierString(mPlmn, mSpn); break; case NetworkLocked: - carrierText = LockPatternUtils.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + carrierText = makeCarierString(mPlmn, getContext().getText(R.string.lockscreen_network_locked_message)); carrierHelpTextId = R.string.lockscreen_instructions_when_pattern_disabled; break; @@ -467,19 +480,19 @@ class KeyguardStatusViewManager implements OnClickListener { break; case SimMissingLocked: - carrierText = LockPatternUtils.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + carrierText = makeCarierString(mPlmn, getContext().getText(R.string.lockscreen_missing_sim_message_short)); carrierHelpTextId = R.string.lockscreen_missing_sim_instructions; mUnlockDisabledDueToSimState = true; break; case SimLocked: - carrierText = LockPatternUtils.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + carrierText = makeCarierString(mPlmn, getContext().getText(R.string.lockscreen_sim_locked_message)); break; case SimPukLocked: - carrierText = LockPatternUtils.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + carrierText = makeCarierString(mPlmn, getContext().getText(R.string.lockscreen_sim_puk_locked_message)); if (!mLockPatternUtils.isPukUnlockScreenEnable()) { mUnlockDisabledDueToSimState = true; @@ -489,7 +502,6 @@ class KeyguardStatusViewManager implements OnClickListener { setCarrierText(carrierText); setCarrierHelpText(carrierHelpTextId); - updateEmergencyCallButtonState(); } private View findViewById(int id) { @@ -552,10 +564,11 @@ class KeyguardStatusViewManager implements OnClickListener { } } - private void updateEmergencyCallButtonState() { + private void updateEmergencyCallButtonState(int phoneState) { if (mEmergencyCallButton != null) { boolean showIfCapable = mShowEmergencyButtonByDefault || mUnlockDisabledDueToSimState; - mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton, showIfCapable); + mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton, + phoneState, showIfCapable); } } @@ -567,7 +580,8 @@ class KeyguardStatusViewManager implements OnClickListener { mShowingBatteryInfo = showBatteryInfo; mPluggedIn = pluggedIn; mBatteryLevel = batteryLevel; - updateStatusLines(true); + final MutableInt tmpIcon = new MutableInt(0); + update(BATTERY_INFO, getAltTextMessage(tmpIcon)); } public void onTimeChanged() { @@ -575,15 +589,17 @@ class KeyguardStatusViewManager implements OnClickListener { } public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { - setCarrierText(LockPatternUtils.getCarrierString(plmn, spn)); + mPlmn = plmn; + mSpn = spn; + updateCarrierTextWithSimStatus(mSimState); } public void onRingerModeChanged(int state) { } - public void onPhoneStateChanged(String newState) { - updateEmergencyCallButtonState(); + public void onPhoneStateChanged(int phoneState) { + updateEmergencyCallButtonState(phoneState); } /** {@inheritDoc} */ @@ -595,7 +611,7 @@ class KeyguardStatusViewManager implements OnClickListener { private SimStateCallback mSimStateCallback = new SimStateCallback() { public void onSimStateChanged(State simState) { - updateWithSimStatus(simState); + updateCarrierTextWithSimStatus(simState); } }; @@ -604,4 +620,22 @@ class KeyguardStatusViewManager implements OnClickListener { mCallback.takeEmergencyCallAction(); } } + + /** + * Performs concentenation of PLMN/SPN + * @param plmn + * @param spn + * @return + */ + private static CharSequence makeCarierString(CharSequence plmn, CharSequence spn) { + if (plmn != null && spn == null) { + return plmn; + } else if (plmn != null && spn != null) { + return plmn + "|" + spn; + } else if (plmn == null && spn != null) { + return spn; + } else { + return ""; + } + } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 2a23709503041..ec24f97a1a8c0 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -88,6 +88,8 @@ public class KeyguardUpdateMonitor { private ArrayList mInfoCallbacks = Lists.newArrayList(); private ArrayList mSimStateCallbacks = Lists.newArrayList(); private ContentObserver mContentObserver; + private int mRingMode; + private int mPhoneState; // messages for the handler private static final int MSG_TIME_UPDATE = 301; @@ -271,13 +273,21 @@ public class KeyguardUpdateMonitor { protected void handlePhoneStateChanged(String newState) { if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); + if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { + mPhoneState = TelephonyManager.CALL_STATE_IDLE; + } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(newState)) { + mPhoneState = TelephonyManager.CALL_STATE_OFFHOOK; + } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(newState)) { + mPhoneState = TelephonyManager.CALL_STATE_RINGING; + } for (int i = 0; i < mInfoCallbacks.size(); i++) { - mInfoCallbacks.get(i).onPhoneStateChanged(newState); + mInfoCallbacks.get(i).onPhoneStateChanged(mPhoneState); } } protected void handleRingerModeChange(int mode) { if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); + mRingMode = mode; for (int i = 0; i < mInfoCallbacks.size(); i++) { mInfoCallbacks.get(i).onRingerModeChanged(mode); } @@ -459,7 +469,7 @@ public class KeyguardUpdateMonitor { * {@link TelephonyManager@EXTRA_STATE_RINGING} * {@link TelephonyManager#EXTRA_STATE_OFFHOOK */ - void onPhoneStateChanged(String newState); + void onPhoneStateChanged(int phoneState); /** * Called when visibility of lockscreen clock changes, such as when @@ -484,8 +494,12 @@ public class KeyguardUpdateMonitor { public void registerInfoCallback(InfoCallback callback) { if (!mInfoCallbacks.contains(callback)) { mInfoCallbacks.add(callback); - // notify the register the current state right away - // TODO: need call other callback methods + // Notify listener of the current state + callback.onRefreshBatteryInfo(shouldShowBatteryInfo(), isPluggedIn(mBatteryStatus), + mBatteryLevel); + callback.onTimeChanged(); + callback.onRingerModeChanged(mRingMode); + callback.onPhoneStateChanged(mPhoneState); callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); } else { if (DEBUG) Log.e(TAG, "Object tried to add another INFO callback", @@ -500,9 +514,7 @@ public class KeyguardUpdateMonitor { public void registerSimStateCallback(SimStateCallback callback) { if (!mSimStateCallbacks.contains(callback)) { mSimStateCallbacks.add(callback); - // notify the register the current sim state right away, - // otherwise the register won't receive any state until - // sim state gets changed again. + // Notify listener of the current state callback.onSimStateChanged(mSimState); } else { if (DEBUG) Log.e(TAG, "Object tried to add another SIM callback", diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 64a9677ed9b54..ab8187518bd62 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -782,7 +782,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // Don't play lockscreen SFX if the screen went off due to // timeout. mSuppressNextLockSound = true; - + doKeyguardLocked(); } } @@ -793,7 +793,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState) // call ending && !mScreenOn // screen off && mExternallyEnabled) { // not disabled by any app - + // note: this is a way to gracefully reenable the keyguard when the call // ends and the screen is off without always reenabling the keyguard // each time the screen turns off while in call (and having an occasional ugly @@ -1297,7 +1297,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** {@inheritDoc} */ - public void onPhoneStateChanged(String newState) { + public void onPhoneStateChanged(int phoneState) { // ignored }