diff options
author | Jim Miller <jaggies@google.com> | 2014-11-12 19:29:51 -0800 |
---|---|---|
committer | Jorim Jaggi <jjaggi@google.com> | 2014-11-20 21:36:52 +0100 |
commit | 52a6133f4ba8b1d08f5158d802790d6a1b16568d (patch) | |
tree | 80e4cf7088f82703f021a3b8b1ecc9861189b568 /packages/Keyguard/src/com/android | |
parent | 419754545ea0768a7fa715daddedef75b7b31bfa (diff) | |
download | frameworks_base-52a6133f4ba8b1d08f5158d802790d6a1b16568d.zip frameworks_base-52a6133f4ba8b1d08f5158d802790d6a1b16568d.tar.gz frameworks_base-52a6133f4ba8b1d08f5158d802790d6a1b16568d.tar.bz2 |
Add multi-sim support to keyguard
Use new telephony APIs.
Clean up SIM state machine code.
Use cached copy of SubscriptionInfo.
Make SIM PIN and SIM PUK work.
Tested on single and multi-SIM devices.
Fixes bug 18147652
Change-Id: Ic69a4d2898999a5438e6a70b5851705bc05443f1
Diffstat (limited to 'packages/Keyguard/src/com/android')
8 files changed, 315 insertions, 82 deletions
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. |