diff options
10 files changed, 344 insertions, 96 deletions
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml index a136acf..fbe3712 100644 --- a/packages/Keyguard/res/values/strings.xml +++ b/packages/Keyguard/res/values/strings.xml @@ -240,12 +240,16 @@ <string name="kg_pattern_instructions">Draw your pattern</string> <!-- Instructions for using the SIM PIN unlock screen --> <string name="kg_sim_pin_instructions">Enter SIM PIN</string> + <!-- Instructions for using the SIM PIN unlock screen when there's more than one SIM --> + <string name="kg_sim_pin_instructions_multi">Enter SIM PIN for \"<xliff:g id="carrier" example="CARD 1">%1$s</xliff:g>\"</string> <!-- Instructions for using the PIN unlock screen --> <string name="kg_pin_instructions">Enter PIN</string> <!-- Instructions for using the password unlock screen --> <string name="kg_password_instructions">Enter Password</string> <!-- Hint shown in the PUK screen that asks the user to enter the PUK code given to them by their provider --> <string name="kg_puk_enter_puk_hint">SIM is now disabled. Enter PUK code to continue. Contact carrier for details.</string> + <!-- Hint shown when there are multiple SIMs in the device to ask the user to enter the PUK code given to them by their provider --> + <string name="kg_puk_enter_puk_hint_multi">SIM \"<xliff:g id="carrier" example="CARD 1">%1$s</xliff:g>\" is now disabled. Enter PUK code to continue. Contact carrier for details.</string> <!-- Hint shown in the PUK unlock screen PIN TextView --> <string name="kg_puk_enter_pin_hint">Enter desired PIN code</string> <!-- Message shown when the user needs to confirm the PIN they just entered in the PUK screen --> diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java index ad07a7a..55bfe49 100644 --- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java +++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java @@ -48,7 +48,7 @@ public class CarrierText extends TextView { } @Override - public void onSimStateChanged(IccCardConstants.State simState) { + public void onSimStateChanged(int subId, int slotId, State simState) { mSimState = simState; updateCarrierText(mSimState, mPlmn, mSpn); } diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java index e0507a8..50ac261 100644 --- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java +++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java @@ -36,22 +36,18 @@ import com.android.internal.widget.LockPatternUtils; * allows the user to return to the call. */ public class EmergencyButton extends Button { - - private static final int EMERGENCY_CALL_TIMEOUT = 10000; // screen timeout after starting e.d. private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL"; KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { @Override - public void onSimStateChanged(State simState) { - int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState(); - updateEmergencyCallButton(simState, phoneState); + public void onSimStateChanged(int subId, int slotId, State simState) { + updateEmergencyCallButton(); } @Override public void onPhoneStateChanged(int phoneState) { - State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState(); - updateEmergencyCallButton(simState, phoneState); + updateEmergencyCallButton(); } }; private LockPatternUtils mLockPatternUtils; @@ -87,9 +83,7 @@ public class EmergencyButton extends Button { takeEmergencyCallAction(); } }); - int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState(); - State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState(); - updateEmergencyCallButton(simState, phoneState); + updateEmergencyCallButton(); } /** @@ -112,12 +106,12 @@ public class EmergencyButton extends Button { } } - private void updateEmergencyCallButton(State simState, int phoneState) { + private void updateEmergencyCallButton() { boolean enabled = false; if (mLockPatternUtils.isInCall()) { enabled = true; // always show "return to call" if phone is off-hook } else if (mLockPatternUtils.isEmergencyCallCapable()) { - boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimLocked(); + final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext).isSimPinVoiceSecure(); if (simLocked) { // Some countries can't handle emergency calls while SIM is locked. enabled = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked(); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java b/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java index 77643bd..10baf23 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardConstants.java @@ -25,5 +25,6 @@ public class KeyguardConstants { * Turns on debugging information for the whole Keyguard. This is very verbose and should only * be used temporarily for debugging. */ - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; + public static final boolean DEBUG_SIM_STATES = true; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java index 3166ad4..a5d260d 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java @@ -17,11 +17,15 @@ package com.android.keyguard; import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.telephony.IccCardConstants; import com.android.internal.widget.LockPatternUtils; +import java.util.List; + public class KeyguardSecurityModel { /** @@ -75,12 +79,13 @@ public class KeyguardSecurityModel { } SecurityMode getSecurityMode() { - KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); - final IccCardConstants.State simState = updateMonitor.getSimState(); + KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); SecurityMode mode = SecurityMode.None; - if (simState == IccCardConstants.State.PIN_REQUIRED) { + if (monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED) + != SubscriptionManager.INVALID_SUB_ID) { mode = SecurityMode.SimPin; - } else if (simState == IccCardConstants.State.PUK_REQUIRED + } else if (monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED) + != SubscriptionManager.INVALID_SUB_ID && mLockPatternUtils.isPukUnlockScreenEnable()) { mode = SecurityMode.SimPuk; } else { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java index 5a0fdb2..d8feaf8 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java @@ -17,15 +17,21 @@ package com.android.keyguard; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; import android.content.Context; +import android.content.res.Resources; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; import android.app.ProgressDialog; import android.os.RemoteException; import android.os.ServiceManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Log; import android.view.WindowManager; @@ -35,13 +41,22 @@ import android.view.WindowManager; */ public class KeyguardSimPinView extends KeyguardPinBasedInputView { private static final String LOG_TAG = "KeyguardSimPinView"; - private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES; public static final String TAG = "KeyguardSimPinView"; private ProgressDialog mSimUnlockProgressDialog = null; private CheckSimPin mCheckSimPinThread; private AlertDialog mRemainingAttemptsDialog; + private int mSubId; + + KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, State simState) { + if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")"); + resetState(); + }; + }; public KeyguardSimPinView(Context context) { this(context, null); @@ -53,7 +68,22 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { public void resetState() { super.resetState(); - mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true); + if (DEBUG) Log.v(TAG, "Resetting state"); + KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); + mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED); + if (mSubId != SubscriptionManager.INVALID_SUB_ID) { + int count = TelephonyManager.getDefault().getSimCount(); + Resources rez = getResources(); + final String msg; + if (count < 2) { + msg = rez.getString(R.string.kg_sim_pin_instructions); + } else { + SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId); + CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash + msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName); + } + mSecurityMessageDisplay.setMessage(msg, true); + } } private String getPinPasswordErrorMessage(int attemptsRemaining) { @@ -95,6 +125,18 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallback); + } + + @Override public void showUsabilityHint() { } @@ -113,9 +155,11 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { */ private abstract class CheckSimPin extends Thread { private final String mPin; + private int mSubId; - protected CheckSimPin(String pin) { + protected CheckSimPin(String pin, int subId) { mPin = pin; + mSubId = subId; } abstract void onSimCheckResponse(final int result, final int attemptsRemaining); @@ -123,10 +167,14 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { @Override public void run() { try { - Log.v(TAG, "call supplyPinReportResult()"); + if (DEBUG) { + Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")"); + } final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPinReportResult(mPin); - Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); + .checkService("phone")).supplyPinReportResultForSubscriber(mSubId, mPin); + if (DEBUG) { + Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { public void run() { onSimCheckResponse(result[0], result[1]); @@ -187,15 +235,17 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { getSimUnlockProgressDialog().show(); if (mCheckSimPinThread == null) { - mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText()) { + mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) { void onSimCheckResponse(final int result, final int attemptsRemaining) { post(new Runnable() { public void run() { if (mSimUnlockProgressDialog != null) { mSimUnlockProgressDialog.hide(); } + resetPasswordText(true /* animate */); if (result == PhoneConstants.PIN_RESULT_SUCCESS) { - KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(); + KeyguardUpdateMonitor.getInstance(getContext()) + .reportSimUnlocked(mSubId); mCallback.dismiss(true); } else { if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) { @@ -216,7 +266,6 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock " + " CheckSimPin.onSimCheckResponse: " + result + " attemptsRemaining=" + attemptsRemaining); - resetPasswordText(true /* animate */); } mCallback.userActivity(); mCheckSimPinThread = null; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java index f0c5805..c5d940c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java @@ -17,18 +17,24 @@ package com.android.keyguard; import android.content.Context; +import android.content.res.Resources; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.os.RemoteException; import android.os.ServiceManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.AttributeSet; import android.util.Log; import android.view.WindowManager; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.IccCardConstants.State; /** @@ -45,6 +51,23 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { private String mPinText; private StateMachine mStateMachine = new StateMachine(); private AlertDialog mRemainingAttemptsDialog; + private int mSubId; + + KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onSimStateChanged(int subId, int slotId, State simState) { + if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")"); + resetState(); + }; + }; + + public KeyguardSimPukView(Context context) { + this(context, null); + } + + public KeyguardSimPukView(Context context, AttributeSet attrs) { + super(context, attrs); + } private class StateMachine { final int ENTER_PUK = 0; @@ -89,7 +112,21 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { mPinText=""; mPukText=""; state = ENTER_PUK; - mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true); + KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); + mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED); + if (mSubId != SubscriptionManager.INVALID_SUB_ID) { + int count = TelephonyManager.getDefault().getSimCount(); + Resources rez = getResources(); + final String msg; + if (count < 2) { + msg = rez.getString(R.string.kg_puk_enter_puk_hint); + } else { + SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId); + CharSequence displayName = info != null ? info.getDisplayName() : ""; + msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName); + } + mSecurityMessageDisplay.setMessage(msg, true); + } mPasswordEntry.requestFocus(); } } @@ -111,14 +148,6 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { return displayMessage; } - public KeyguardSimPukView(Context context) { - this(context, null); - } - - public KeyguardSimPukView(Context context, AttributeSet attrs) { - super(context, attrs); - } - public void resetState() { super.resetState(); mStateMachine.reset(); @@ -146,6 +175,18 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallback); + } + + @Override public void showUsabilityHint() { } @@ -165,10 +206,12 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { private abstract class CheckSimPuk extends Thread { private final String mPin, mPuk; + private final int mSubId; - protected CheckSimPuk(String puk, String pin) { + protected CheckSimPuk(String puk, String pin, int subId) { mPuk = puk; mPin = pin; + mSubId = subId; } abstract void onSimLockChangedResponse(final int result, final int attemptsRemaining); @@ -176,10 +219,12 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { @Override public void run() { try { - Log.v(TAG, "call supplyPukReportResult()"); + if (DEBUG) Log.v(TAG, "call supplyPukReportResult()"); final int[] result = ITelephony.Stub.asInterface(ServiceManager - .checkService("phone")).supplyPukReportResult(mPuk, mPin); - Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); + .checkService("phone")).supplyPukReportResultForSubscriber(mSubId, mPuk, mPin); + if (DEBUG) { + Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]); + } post(new Runnable() { public void run() { onSimLockChangedResponse(result[0], result[1]); @@ -254,15 +299,17 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView { getSimUnlockProgressDialog().show(); if (mCheckSimPukThread == null) { - mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText) { + mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) { void onSimLockChangedResponse(final int result, final int attemptsRemaining) { post(new Runnable() { public void run() { if (mSimUnlockProgressDialog != null) { mSimUnlockProgressDialog.hide(); } + resetPasswordText(true /* animate */); if (result == PhoneConstants.PIN_RESULT_SUCCESS) { - KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(); + KeyguardUpdateMonitor.getInstance(getContext()) + .reportSimUnlocked(mSubId); mCallback.dismiss(true); } else { if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index aa5819e..48b2eac 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -51,11 +51,17 @@ import android.os.UserHandle; import android.provider.Settings; import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.IccCardConstants.State; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; import android.service.fingerprint.FingerprintManager; import android.service.fingerprint.FingerprintManagerReceiver; import android.service.fingerprint.FingerprintUtils; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionListener; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import android.util.SparseBooleanArray; @@ -64,6 +70,9 @@ import com.google.android.collect.Lists; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; /** * Watches for updates that may be interesting to the keyguard, and provides @@ -79,7 +88,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final String TAG = "KeyguardUpdateMonitor"; private static final boolean DEBUG = KeyguardConstants.DEBUG; - private static final boolean DEBUG_SIM_STATES = DEBUG || false; + private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES; private static final int FAILED_BIOMETRIC_UNLOCK_ATTEMPTS_BEFORE_BACKUP = 3; private static final int LOW_BATTERY_THRESHOLD = 20; @@ -113,13 +122,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final int MSG_FINGERPRINT_PROCESSED = 323; private static final int MSG_FINGERPRINT_ACQUIRED = 324; private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325; + private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326; private static KeyguardUpdateMonitor sInstance; private final Context mContext; + HashMap<Integer, SimData> mSimDatas = new HashMap<Integer, SimData>(); - // Telephony state - private IccCardConstants.State mSimState = IccCardConstants.State.READY; private CharSequence mTelephonyPlmn; private CharSequence mTelephonySpn; private int mRingMode; @@ -149,6 +158,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean mSwitchingUser; private boolean mScreenOn; + protected List<SubscriptionInfo> mSubscriptionInfo; private final Handler mHandler = new Handler() { @Override @@ -164,7 +174,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { handleCarrierInfoUpdate(); break; case MSG_SIM_STATE_CHANGE: - handleSimStateChange((SimArgs) msg.obj); + handleSimStateChange(msg.arg1, msg.arg2, (State) msg.obj); break; case MSG_RINGER_MODE_CHANGED: handleRingerModeChange(msg.arg1); @@ -220,10 +230,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { case MSG_FACE_UNLOCK_STATE_CHANGED: handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2); break; + case MSG_SIM_SUBSCRIPTION_INFO_CHANGED: + handleSimSubscriptionInfoChanged(); + break; } } }; + private SubscriptionListener mSubscriptionListener = new SubscriptionListener() { + @Override + public void onSubscriptionInfoChanged() { + mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED); + } + }; + private SparseBooleanArray mUserHasTrust = new SparseBooleanArray(); private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray(); private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray(); @@ -244,6 +264,40 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + protected void handleSimSubscriptionInfoChanged() { + if (DEBUG_SIM_STATES) { + Log.v(TAG, "onSubscriptionInfoChanged()"); + for (SubscriptionInfo subInfo : SubscriptionManager.getActiveSubscriptionInfoList()) { + Log.v(TAG, "SubInfo:" + subInfo); + } + } + List<SubscriptionInfo> subscriptionInfos = getSubscriptionInfo(true /* forceReload */); + + // Hack level over 9000: Because the subscription id is not yet valid when we see the + // first update in handleSimStateChange, we need to force refresh all all SIM states + // so the subscription id for them is consistent. + for (int i = 0; i < subscriptionInfos.size(); i++) { + SubscriptionInfo info = subscriptionInfos.get(i); + refreshSimState(info.getSubscriptionId(), info.getSimSlotIndex()); + } + for (int i = 0; i < subscriptionInfos.size(); i++) { + SimData data = mSimDatas.get(mSubscriptionInfo.get(i).getSubscriptionId()); + for (int j = 0; j < mCallbacks.size(); j++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get(); + if (cb != null) { + cb.onSimStateChanged(data.subId, data.slotId, data.simState); + } + } + } + } + + List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) { + if (mSubscriptionInfo == null || forceReload) { + mSubscriptionInfo = SubscriptionManager.getActiveSubscriptionInfoList(); + } + return mSubscriptionInfo; + } + @Override public void onTrustManagedChanged(boolean managed, int userId) { mUserTrustIsManaged.put(userId, managed); @@ -382,12 +436,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health)); mHandler.sendMessage(msg); } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) { + SimData args = SimData.fromIntent(intent); if (DEBUG_SIM_STATES) { - Log.v(TAG, "action " + action + " state" + - intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)); + Log.v(TAG, "action " + action + + " state: " + intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE) + + " slotId: " + args.slotId + " subid: " + args.subId); } - mHandler.sendMessage(mHandler.obtainMessage( - MSG_SIM_STATE_CHANGE, SimArgs.fromIntent(intent))); + mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState) + .sendToTarget(); } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); @@ -449,19 +505,26 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * we need a single object to pass to the handler. This class helps decode * the intent and provide a {@link SimCard.State} result. */ - private static class SimArgs { - public final IccCardConstants.State simState; + private static class SimData { + public State simState; + public int slotId; + public int subId; - SimArgs(IccCardConstants.State state) { + SimData(State state, int slot, int id) { simState = state; + slotId = slot; + subId = id; } - static SimArgs fromIntent(Intent intent) { - IccCardConstants.State state; + static SimData fromIntent(Intent intent) { + State state; if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); } String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); + int slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY, 0); + int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + SubscriptionManager.INVALID_SUB_ID); if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { final String absentReason = intent .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); @@ -494,11 +557,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } else { state = IccCardConstants.State.UNKNOWN; } - return new SimArgs(state); + return new SimData(state, slotId, subId); } public String toString() { - return simState.toString(); + return "SimData{state=" + simState + ",slotId=" + slotId + ",subId=" + subId + "}"; } } @@ -605,7 +668,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } // Take a guess at initial SIM state, battery status and PLMN until we get an update - mSimState = IccCardConstants.State.NOT_READY; mBatteryStatus = new BatteryStatus(BATTERY_STATUS_UNKNOWN, 100, 0, 0); mTelephonyPlmn = getDefaultPlmn(); @@ -636,6 +698,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter, null, null); + SubscriptionManager.register(mContext, mSubscriptionListener, + SubscriptionListener.LISTEN_SUBSCRIPTION_INFO_LIST_CHANGED); try { ActivityManagerNative.getDefault().registerUserSwitchObserver( new IUserSwitchObserver.Stub() { @@ -881,20 +945,35 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** * Handle {@link #MSG_SIM_STATE_CHANGE} */ - private void handleSimStateChange(SimArgs simArgs) { - final IccCardConstants.State state = simArgs.simState; + private void handleSimStateChange(int subId, int slotId, State state) { - if (DEBUG) { - Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " " - + "state resolved to " + state.toString()); + if (DEBUG_SIM_STATES) { + Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId=" + + slotId + ", state=" + state +")"); } - if (state != IccCardConstants.State.UNKNOWN && state != mSimState) { - mSimState = state; + if (subId == SubscriptionManager.INVALID_SUB_ID) { + Log.w(TAG, "invalid subId in handleSimStateChange()"); + return; + } + + SimData data = mSimDatas.get(subId); + final boolean changed; + if (data == null) { + data = new SimData(state, slotId, subId); + mSimDatas.put(subId, data); + changed = true; // no data yet; force update + } else { + changed = (data.simState != state || data.subId != subId || data.slotId != slotId); + data.simState = state; + data.subId = subId; + data.slotId = slotId; + } + if (changed && state != State.UNKNOWN) { for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onSimStateChanged(state); + cb.onSimStateChanged(subId, slotId, state); } } } @@ -1070,7 +1149,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { callback.onPhoneStateChanged(mPhoneState); callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn); callback.onClockVisibilityChanged(); - callback.onSimStateChanged(mSimState); + for (Entry<Integer, SimData> data : mSimDatas.entrySet()) { + final SimData state = data.getValue(); + callback.onSimStateChanged(state.subId, state.slotId, state.simState); + } } public void sendKeyguardVisibilityChanged(boolean showing) { @@ -1095,10 +1177,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mHandler.obtainMessage(MSG_CLOCK_VISIBILITY_CHANGED).sendToTarget(); } - public IccCardConstants.State getSimState() { - return mSimState; - } - /** * Report that the user successfully entered the SIM PIN or PUK/SIM PIN so we * have the information earlier than waiting for the intent @@ -1107,8 +1185,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * NOTE: Because handleSimStateChange() invokes callbacks immediately without going * through mHandler, this *must* be called from the UI thread. */ - public void reportSimUnlocked() { - handleSimStateChange(new SimArgs(IccCardConstants.State.READY)); + public void reportSimUnlocked(int subId) { + if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")"); + int slotId = SubscriptionManager.getSlotId(subId); + handleSimStateChange(subId, slotId, State.READY); } /** @@ -1184,18 +1264,44 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mAlternateUnlockEnabled = enabled; } - public boolean isSimLocked() { - return isSimLocked(mSimState); + public boolean isSimPinVoiceSecure() { + // TODO: only count SIMs that handle voice + return isSimPinSecure(); } - public static boolean isSimLocked(IccCardConstants.State state) { - return state == IccCardConstants.State.PIN_REQUIRED - || state == IccCardConstants.State.PUK_REQUIRED - || state == IccCardConstants.State.PERM_DISABLED; + public boolean isSimPinSecure() { + // True if any SIM is pin secure + for (SubscriptionInfo info : getSubscriptionInfo(false /* forceReload */)) { + if (isSimPinSecure(getSimState(info.getSubscriptionId()))) return true; + } + return false; } - public boolean isSimPinSecure() { - return isSimPinSecure(mSimState); + private State getSimState(int subId) { + if (mSimDatas.containsKey(subId)) { + return mSimDatas.get(subId).simState; + } else { + return State.UNKNOWN; + } + } + + private void refreshSimState(int subId, int slotId) { + + // This is awful. It exists because there are two APIs for getting the SIM status + // that don't return the complete set of values and have different types. In Keyguard we + // need IccCardConstants, but TelephonyManager would only give us + // TelephonyManager.SIM_STATE*, so we retrieve it manually. + final int phoneId = SubscriptionManager.getPhoneId(subId); + final String stateString = TelephonyManager.getTelephonyProperty(phoneId, + TelephonyProperties.PROPERTY_SIM_STATE, ""); + State state; + try { + state = State.valueOf(stateString); + } catch(IllegalArgumentException ex) { + Log.w(TAG, "Unknown sim state: " + stateString); + state = State.UNKNOWN; + } + mSimDatas.put(subId, new SimData(state, slotId, subId)); } public static boolean isSimPinSecure(IccCardConstants.State state) { @@ -1228,4 +1334,34 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { public boolean isScreenOn() { return mScreenOn; } + + /** + * Find the next SubscriptionId for a SIM in the given state, favoring lower slot numbers first. + * @param state + * @return subid or {@link SubscriptionManager#INVALID_SUB_ID} if none found + */ + public int getNextSubIdForState(State state) { + List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */); + int resultId = SubscriptionManager.INVALID_SUB_ID; + int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first + for (int i = 0; i < list.size(); i++) { + final SubscriptionInfo info = list.get(i); + final int id = info.getSubscriptionId(); + int slotId = SubscriptionManager.getSlotId(id); + if (state == getSimState(id) && bestSlotId > slotId ) { + resultId = id; + bestSlotId = slotId; + } + } + return resultId; + } + + public SubscriptionInfo getSubscriptionInfoForSubId(int subId) { + List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */); + for (int i = 0; i < list.size(); i++) { + SubscriptionInfo info = list.get(i); + if (subId == info.getSubscriptionId()) return info; + } + return null; // not found + } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 2b40903..de72ddd 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -121,9 +121,10 @@ public class KeyguardUpdateMonitorCallback { /** * Called when the SIM state changes. + * @param slotId * @param simState */ - public void onSimStateChanged(IccCardConstants.State simState) { } + public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { } /** * Called when a user is removed. diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 5f92dc6..8213127 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -43,6 +43,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -57,6 +58,7 @@ import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.telephony.IccCardConstants; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardDisplayManager; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; @@ -116,7 +118,8 @@ public class KeyguardViewMediator extends SystemUI { private static final int KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT = 30000; private static final long KEYGUARD_DONE_PENDING_TIMEOUT_MS = 3000; - final static boolean DEBUG = false; + private static final boolean DEBUG = KeyguardConstants.DEBUG; + private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES; private final static boolean DBG_WAKE = false; private final static String TAG = "KeyguardViewMediator"; @@ -360,8 +363,12 @@ public class KeyguardViewMediator extends SystemUI { } @Override - public void onSimStateChanged(IccCardConstants.State simState) { - if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState); + public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { + + if (DEBUG_SIM_STATES) { + Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId + + ",state=" + simState + ")"); + } switch (simState) { case NOT_READY: @@ -371,7 +378,7 @@ public class KeyguardViewMediator extends SystemUI { synchronized (this) { if (shouldWaitForProvisioning()) { if (!isShowing()) { - if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing," + if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing," + " we need to show the keyguard since the " + "device isn't provisioned yet."); doKeyguardLocked(null); @@ -385,7 +392,8 @@ public class KeyguardViewMediator extends SystemUI { case PUK_REQUIRED: synchronized (this) { if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't " + if (DEBUG_SIM_STATES) Log.d(TAG, + "INTENT_VALUE_ICC_LOCKED and keygaurd isn't " + "showing; need to show keyguard so user can enter sim pin"); doKeyguardLocked(null); } else { @@ -396,11 +404,11 @@ public class KeyguardViewMediator extends SystemUI { case PERM_DISABLED: synchronized (this) { if (!isShowing()) { - if (DEBUG) Log.d(TAG, "PERM_DISABLED and " + if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and " + "keygaurd isn't showing."); doKeyguardLocked(null); } else { - if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" + if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" + "show permanently disabled message in lockscreen."); resetStateLocked(); } @@ -413,6 +421,9 @@ public class KeyguardViewMediator extends SystemUI { } } break; + default: + if (DEBUG_SIM_STATES) Log.v(TAG, "Ignoring state: " + simState); + break; } } @@ -913,13 +924,13 @@ public class KeyguardViewMediator extends SystemUI { } // if the setup wizard hasn't run yet, don't show - final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", - false); - final IccCardConstants.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() - || ((state == IccCardConstants.State.ABSENT - || state == IccCardConstants.State.PERM_DISABLED) - && requireSim); + final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false); + final boolean absent = mUpdateMonitor.getNextSubIdForState( + IccCardConstants.State.ABSENT) != SubscriptionManager.INVALID_SUB_ID; + final boolean disabled = mUpdateMonitor.getNextSubIdForState( + IccCardConstants.State.PERM_DISABLED) != SubscriptionManager.INVALID_SUB_ID; + final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure() + || ((absent || disabled) && requireSim); if (!lockedOrMissing && shouldWaitForProvisioning()) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" |