Loading src/java/com/android/internal/telephony/euicc/EuiccConnector.java +5 −4 Original line number Diff line number Diff line Loading @@ -493,13 +493,13 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously switch to the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void switchToSubscription(int cardId, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback) { public void switchToSubscription(int cardId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback) { SwitchRequest request = new SwitchRequest(); request.mIccid = iccid; request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, 0 /* arg2 */, request); sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, portIndex, request); } /** Asynchronously update the nickname of the given subscription. */ Loading Loading @@ -838,7 +838,8 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } case CMD_SWITCH_TO_SUBSCRIPTION: { SwitchRequest request = (SwitchRequest) message.obj; mEuiccService.switchToSubscription(slotId, request.mIccid, final int portIndex = message.arg2; mEuiccService.switchToSubscription(slotId, portIndex, request.mIccid, request.mForceDeactivateSim, new ISwitchToSubscriptionCallback.Stub() { @Override Loading src/java/com/android/internal/telephony/euicc/EuiccController.java +87 −31 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; import android.service.euicc.DownloadSubscriptionResult; import android.service.euicc.EuiccService; Loading Loading @@ -180,6 +181,9 @@ public class EuiccController extends IEuiccController.Stub { PendingIntent callbackIntent = resolutionIntent.getParcelableExtra( EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); int portIndex = resolutionIntent.getIntExtra( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolutionExtras.putInt(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex); op.continueOperation(cardId, resolutionExtras, callbackIntent); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -417,7 +421,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, Loading Loading @@ -568,7 +572,8 @@ public class EuiccController extends IEuiccController.Stub { Log.i(TAG, "Caller can't manage subscription on target SIM. " + "Ask user's consent first"); Intent extrasIntent = new Intent(); addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, callingPackage, 0 /* resolvableErrors */, false /* confirmationCodeRetried */, Loading Loading @@ -624,7 +629,8 @@ public class EuiccController extends IEuiccController.Stub { // The caller can manage the target SIM. Ask the user's consent to deactivate // the current SIM. Intent extrasIntent = new Intent(); addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, false /* confirmationCodeRetried */, Loading Loading @@ -706,7 +712,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, callingPackage, 0 /* resolvableErrors */, Loading @@ -727,7 +733,7 @@ public class EuiccController extends IEuiccController.Stub { retried = true; } if (result.getResolvableErrors() != 0) { addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS, callingPackage, result.getResolvableErrors(), Loading @@ -737,7 +743,7 @@ public class EuiccController extends IEuiccController.Stub { callingPackage, result.getResolvableErrors()), cardId); } else { // Deprecated case addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE, callingPackage, 0 /* resolvableErrors */, Loading Loading @@ -851,7 +857,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, Loading Loading @@ -959,12 +965,21 @@ public class EuiccController extends IEuiccController.Stub { @Override public void switchToSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent) { switchToSubscription(cardId, subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent); // convert PendingIntent to callback if no callback provided IResultCallback callback = getCallbackFromPendingIntent(callbackIntent); switchToSubscription(cardId, 0, subscriptionId, false /* forceDeactivateSim */, callingPackage, callback); } void switchToSubscription(int cardId, int subscriptionId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { @Override public void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId, String callingPackage, IResultCallback callback) { switchToSubscription(cardId, portIndex, subscriptionId, false /* forceDeactivateSim */, callingPackage, callback); } void switchToSubscription(int cardId, int portIndex, int subscriptionId, boolean forceDeactivateSim, String callingPackage, IResultCallback callback) { boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); Loading @@ -985,7 +1000,7 @@ public class EuiccController extends IEuiccController.Stub { passConsent = true; } else { Log.e(TAG, "Not permitted to switch to empty subscription"); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } iccid = null; Loading @@ -993,7 +1008,7 @@ public class EuiccController extends IEuiccController.Stub { SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); if (sub == null) { Log.e(TAG, "Cannot switch to nonexistent sub: " + subscriptionId); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } if (callerCanWriteEmbeddedSubscriptions) { Loading @@ -1001,7 +1016,7 @@ public class EuiccController extends IEuiccController.Stub { } else { if (!mSubscriptionManager.canManageSubscription(sub, callingPackage)) { Log.e(TAG, "Not permitted to switch to sub: " + subscriptionId); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } Loading @@ -1022,35 +1037,55 @@ public class EuiccController extends IEuiccController.Stub { false /* confirmationCodeRetried */, EuiccOperation.forSwitchNoPrivileges( token, subscriptionId, callingPackage), cardId); sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent); cardId, portIndex); callback.onComplete(RESOLVABLE_ERROR, extrasIntent); return; } switchToSubscriptionPrivileged(cardId, token, subscriptionId, iccid, forceDeactivateSim, callingPackage, callbackIntent); switchToSubscriptionPrivileged(cardId, portIndex, token, subscriptionId, iccid, forceDeactivateSim, callingPackage, callback); } catch (RemoteException e) { Log.e(TAG, "Cannot run callback.onComplete due to RemoteException e=" + e); } finally { Binder.restoreCallingIdentity(token); } } void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent) { /** * * Create callback object which sends a given PendingIntent in the onComplete method. * This is used for compatibility between the old API which uses PendingIntents, and the new * API which uses Executors and Callbacks. * @param pi the PendingIntent to send * @return the callback */ public IResultCallback getCallbackFromPendingIntent(PendingIntent pi) { return new IResultCallback.Stub() { @Override public void onComplete(int result, Intent resultIntent) { sendResult(pi, result, resultIntent); } }; } void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final IResultCallback callback) { String iccid = null; SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); if (sub != null) { iccid = sub.getIccId(); } switchToSubscriptionPrivileged(cardId, callingToken, subscriptionId, iccid, forceDeactivateSim, callingPackage, callbackIntent); switchToSubscriptionPrivileged(cardId, portIndex, callingToken, subscriptionId, iccid, forceDeactivateSim, callingPackage, callback); } void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent) { void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final IResultCallback callback) { mConnector.switchToSubscription( cardId, portIndex, iccid, forceDeactivateSim, new EuiccConnector.SwitchCommandCallback() { Loading @@ -1071,20 +1106,31 @@ public class EuiccController extends IEuiccController.Stub { false /* confirmationCodeRetried */, EuiccOperation.forSwitchDeactivateSim( callingToken, subscriptionId, callingPackage), cardId); cardId, portIndex); break; default: resultCode = ERROR; addExtrasToResultIntent(extrasIntent, result); break; } sendResult(callbackIntent, resultCode, extrasIntent); try { callback.onComplete(resultCode, extrasIntent); } catch (RemoteException e) { Log.e(TAG, "onSwitchComplete: " + "Cannot run callback.onComplete due to RemoteException e=" + e); } } @Override public void onEuiccServiceUnavailable() { sendResult(callbackIntent, ERROR, null /* extrasIntent */); try { callback.onComplete(ERROR, null); } catch (RemoteException e) { Log.e(TAG, "EuiccService is unavailable. " + "Cannot run callback.onComplete due to RemoteException e=" + e); } } }); } Loading Loading @@ -1279,11 +1325,20 @@ public class EuiccController extends IEuiccController.Stub { } } /** Add a resolution intent to the given extras intent with the default port index 0 */ public void addResolutionIntentForDefaultPort(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { // use the default port 0 when not specified addResolutionIntent(extrasIntent, resolutionAction, callingPackage, resolvableErrors, confirmationCodeRetried, op, cardId, TelephonyManager.DEFAULT_PORT_INDEX); } /** Add a resolution intent to the given extras intent. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void addResolutionIntent(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { EuiccOperation op, int cardId, int portIndex) { Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR); intent.setPackage(RESOLUTION_ACTIVITY_PACKAGE_NAME); intent.setComponent(new ComponentName( Loading @@ -1293,6 +1348,7 @@ public class EuiccController extends IEuiccController.Stub { intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage); intent.putExtra(EuiccService.EXTRA_RESOLVABLE_ERRORS, resolvableErrors); intent.putExtra(EuiccService.EXTRA_RESOLUTION_CARD_ID, cardId); intent.putExtra(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex); intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED, confirmationCodeRetried); intent.putExtra(EXTRA_OPERATION, op); Loading src/java/com/android/internal/telephony/euicc/EuiccOperation.java +24 −10 Original line number Diff line number Diff line Loading @@ -302,16 +302,26 @@ public class EuiccOperation implements Parcelable { resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_DEACTIVATE_SIM: resolvedSwitchDeactivateSim(cardId, case ACTION_SWITCH_DEACTIVATE_SIM: { // get portIndex from original operation final int portIndex = resolutionExtras.getInt( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolvedSwitchDeactivateSim(cardId, portIndex, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_NO_PRIVILEGES: resolvedSwitchNoPrivileges(cardId, } case ACTION_SWITCH_NO_PRIVILEGES: { // get portIndex from original operation final int portIndex = resolutionExtras.getInt( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolvedSwitchNoPrivileges(cardId, portIndex, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; } default: Log.wtf(TAG, "Unknown action: " + mAction); break; Loading Loading @@ -482,24 +492,26 @@ public class EuiccOperation implements Parcelable { } } private void resolvedSwitchDeactivateSim(int cardId, boolean consent, private void resolvedSwitchDeactivateSim(int cardId, int portIndex, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().switchToSubscription( EuiccController euiccController = EuiccController.get(); euiccController.switchToSubscription( cardId, portIndex, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); euiccController.getCallbackFromPendingIntent(callbackIntent)); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchNoPrivileges(int cardId, boolean consent, private void resolvedSwitchNoPrivileges(int cardId, int portIndex, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch with full privileges. Loading @@ -511,13 +523,15 @@ public class EuiccOperation implements Parcelable { // carrier. Also note that in practice, we'd need to deactivate the active SIM to // even reach this point, because we cannot fetch the metadata needed to check the // privileges without doing so. EuiccController.get().switchToSubscriptionPrivileged( EuiccController euiccController = EuiccController.get(); euiccController.switchToSubscriptionPrivileged( cardId, portIndex, token, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); euiccController.getCallbackFromPendingIntent(callbackIntent)); } finally { Binder.restoreCallingIdentity(token); } Loading tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ public class EuiccConnectorTest extends TelephonyTest { @Mock private IEuiccService.Stub mEuiccService; private static final int CARD_ID = 15; private static final int PORT_INDEX = 0; @Before public void setUp() throws Exception { Loading Loading @@ -137,7 +138,7 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.switchToSubscription(CARD_ID, "12345", true, new mConnector.switchToSubscription(CARD_ID, PORT_INDEX, "12345", true, new EuiccConnector.SwitchCommandCallback() { @Override public void onSwitchComplete(int result) { Loading tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +21 −17 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ public class EuiccControllerTest extends TelephonyTest { private static final int SUBSCRIPTION_ID = 12345; private static final String ICC_ID = "54321"; private static final int CARD_ID = 25; private static final int PORT_INDEX = 0; @Mock private EuiccConnector mMockConnector; private TestEuiccController mController; Loading Loading @@ -148,7 +149,7 @@ public class EuiccControllerTest extends TelephonyTest { public void addResolutionIntent( Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { int cardId, int portIndex) { mResolutionAction = resolutionAction; mOp = op; } Loading Loading @@ -765,8 +766,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading @@ -777,8 +778,8 @@ public class EuiccControllerTest extends TelephonyTest { 0 /* result */, "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading @@ -790,7 +791,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading Loading @@ -832,8 +834,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading Loading @@ -868,8 +870,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading @@ -885,8 +887,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading @@ -902,8 +904,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading Loading @@ -1383,7 +1385,7 @@ public class EuiccControllerTest extends TelephonyTest { @Override public Void answer(InvocationOnMock invocation) throws Exception { EuiccConnector.SwitchCommandCallback cb = invocation .getArgument(3 /* resultCallback */); .getArgument(4 /* resultCallback */); if (complete) { cb.onSwitchComplete(result); } else { Loading @@ -1391,8 +1393,10 @@ public class EuiccControllerTest extends TelephonyTest { } return null; } }).when(mMockConnector).switchToSubscription(anyInt(), eq(iccid), anyBoolean(), any()); mController.switchToSubscription(CARD_ID, subscriptionId, callingPackage, resultCallback); }).when(mMockConnector).switchToSubscription(anyInt(), anyInt(), eq(iccid), anyBoolean(), any()); mController.switchToSubscription(CARD_ID, subscriptionId, callingPackage, resultCallback); } private void callUpdateSubscriptionNickname(int subscriptionId, String iccid, String nickname, Loading Loading
src/java/com/android/internal/telephony/euicc/EuiccConnector.java +5 −4 Original line number Diff line number Diff line Loading @@ -493,13 +493,13 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously switch to the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void switchToSubscription(int cardId, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback) { public void switchToSubscription(int cardId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback) { SwitchRequest request = new SwitchRequest(); request.mIccid = iccid; request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, 0 /* arg2 */, request); sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, portIndex, request); } /** Asynchronously update the nickname of the given subscription. */ Loading Loading @@ -838,7 +838,8 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } case CMD_SWITCH_TO_SUBSCRIPTION: { SwitchRequest request = (SwitchRequest) message.obj; mEuiccService.switchToSubscription(slotId, request.mIccid, final int portIndex = message.arg2; mEuiccService.switchToSubscription(slotId, portIndex, request.mIccid, request.mForceDeactivateSim, new ISwitchToSubscriptionCallback.Stub() { @Override Loading
src/java/com/android/internal/telephony/euicc/EuiccController.java +87 −31 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; import android.service.euicc.DownloadSubscriptionResult; import android.service.euicc.EuiccService; Loading Loading @@ -180,6 +181,9 @@ public class EuiccController extends IEuiccController.Stub { PendingIntent callbackIntent = resolutionIntent.getParcelableExtra( EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); int portIndex = resolutionIntent.getIntExtra( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolutionExtras.putInt(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex); op.continueOperation(cardId, resolutionExtras, callbackIntent); } finally { Binder.restoreCallingIdentity(token); Loading Loading @@ -417,7 +421,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, Loading Loading @@ -568,7 +572,8 @@ public class EuiccController extends IEuiccController.Stub { Log.i(TAG, "Caller can't manage subscription on target SIM. " + "Ask user's consent first"); Intent extrasIntent = new Intent(); addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, callingPackage, 0 /* resolvableErrors */, false /* confirmationCodeRetried */, Loading Loading @@ -624,7 +629,8 @@ public class EuiccController extends IEuiccController.Stub { // The caller can manage the target SIM. Ask the user's consent to deactivate // the current SIM. Intent extrasIntent = new Intent(); addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, false /* confirmationCodeRetried */, Loading Loading @@ -706,7 +712,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, callingPackage, 0 /* resolvableErrors */, Loading @@ -727,7 +733,7 @@ public class EuiccController extends IEuiccController.Stub { retried = true; } if (result.getResolvableErrors() != 0) { addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_RESOLVABLE_ERRORS, callingPackage, result.getResolvableErrors(), Loading @@ -737,7 +743,7 @@ public class EuiccController extends IEuiccController.Stub { callingPackage, result.getResolvableErrors()), cardId); } else { // Deprecated case addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE, callingPackage, 0 /* resolvableErrors */, Loading Loading @@ -851,7 +857,7 @@ public class EuiccController extends IEuiccController.Stub { break; case EuiccService.RESULT_MUST_DEACTIVATE_SIM: resultCode = RESOLVABLE_ERROR; addResolutionIntent(extrasIntent, addResolutionIntentForDefaultPort(extrasIntent, EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, mCallingPackage, 0 /* resolvableErrors */, Loading Loading @@ -959,12 +965,21 @@ public class EuiccController extends IEuiccController.Stub { @Override public void switchToSubscription(int cardId, int subscriptionId, String callingPackage, PendingIntent callbackIntent) { switchToSubscription(cardId, subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent); // convert PendingIntent to callback if no callback provided IResultCallback callback = getCallbackFromPendingIntent(callbackIntent); switchToSubscription(cardId, 0, subscriptionId, false /* forceDeactivateSim */, callingPackage, callback); } void switchToSubscription(int cardId, int subscriptionId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { @Override public void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId, String callingPackage, IResultCallback callback) { switchToSubscription(cardId, portIndex, subscriptionId, false /* forceDeactivateSim */, callingPackage, callback); } void switchToSubscription(int cardId, int portIndex, int subscriptionId, boolean forceDeactivateSim, String callingPackage, IResultCallback callback) { boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); Loading @@ -985,7 +1000,7 @@ public class EuiccController extends IEuiccController.Stub { passConsent = true; } else { Log.e(TAG, "Not permitted to switch to empty subscription"); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } iccid = null; Loading @@ -993,7 +1008,7 @@ public class EuiccController extends IEuiccController.Stub { SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); if (sub == null) { Log.e(TAG, "Cannot switch to nonexistent sub: " + subscriptionId); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } if (callerCanWriteEmbeddedSubscriptions) { Loading @@ -1001,7 +1016,7 @@ public class EuiccController extends IEuiccController.Stub { } else { if (!mSubscriptionManager.canManageSubscription(sub, callingPackage)) { Log.e(TAG, "Not permitted to switch to sub: " + subscriptionId); sendResult(callbackIntent, ERROR, null /* extrasIntent */); callback.onComplete(ERROR, null); return; } Loading @@ -1022,35 +1037,55 @@ public class EuiccController extends IEuiccController.Stub { false /* confirmationCodeRetried */, EuiccOperation.forSwitchNoPrivileges( token, subscriptionId, callingPackage), cardId); sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent); cardId, portIndex); callback.onComplete(RESOLVABLE_ERROR, extrasIntent); return; } switchToSubscriptionPrivileged(cardId, token, subscriptionId, iccid, forceDeactivateSim, callingPackage, callbackIntent); switchToSubscriptionPrivileged(cardId, portIndex, token, subscriptionId, iccid, forceDeactivateSim, callingPackage, callback); } catch (RemoteException e) { Log.e(TAG, "Cannot run callback.onComplete due to RemoteException e=" + e); } finally { Binder.restoreCallingIdentity(token); } } void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent) { /** * * Create callback object which sends a given PendingIntent in the onComplete method. * This is used for compatibility between the old API which uses PendingIntents, and the new * API which uses Executors and Callbacks. * @param pi the PendingIntent to send * @return the callback */ public IResultCallback getCallbackFromPendingIntent(PendingIntent pi) { return new IResultCallback.Stub() { @Override public void onComplete(int result, Intent resultIntent) { sendResult(pi, result, resultIntent); } }; } void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, boolean forceDeactivateSim, final String callingPackage, final IResultCallback callback) { String iccid = null; SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); if (sub != null) { iccid = sub.getIccId(); } switchToSubscriptionPrivileged(cardId, callingToken, subscriptionId, iccid, forceDeactivateSim, callingPackage, callbackIntent); switchToSubscriptionPrivileged(cardId, portIndex, callingToken, subscriptionId, iccid, forceDeactivateSim, callingPackage, callback); } void switchToSubscriptionPrivileged(int cardId, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final PendingIntent callbackIntent) { void switchToSubscriptionPrivileged(int cardId, int portIndex, final long callingToken, int subscriptionId, @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, final IResultCallback callback) { mConnector.switchToSubscription( cardId, portIndex, iccid, forceDeactivateSim, new EuiccConnector.SwitchCommandCallback() { Loading @@ -1071,20 +1106,31 @@ public class EuiccController extends IEuiccController.Stub { false /* confirmationCodeRetried */, EuiccOperation.forSwitchDeactivateSim( callingToken, subscriptionId, callingPackage), cardId); cardId, portIndex); break; default: resultCode = ERROR; addExtrasToResultIntent(extrasIntent, result); break; } sendResult(callbackIntent, resultCode, extrasIntent); try { callback.onComplete(resultCode, extrasIntent); } catch (RemoteException e) { Log.e(TAG, "onSwitchComplete: " + "Cannot run callback.onComplete due to RemoteException e=" + e); } } @Override public void onEuiccServiceUnavailable() { sendResult(callbackIntent, ERROR, null /* extrasIntent */); try { callback.onComplete(ERROR, null); } catch (RemoteException e) { Log.e(TAG, "EuiccService is unavailable. " + "Cannot run callback.onComplete due to RemoteException e=" + e); } } }); } Loading Loading @@ -1279,11 +1325,20 @@ public class EuiccController extends IEuiccController.Stub { } } /** Add a resolution intent to the given extras intent with the default port index 0 */ public void addResolutionIntentForDefaultPort(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { // use the default port 0 when not specified addResolutionIntent(extrasIntent, resolutionAction, callingPackage, resolvableErrors, confirmationCodeRetried, op, cardId, TelephonyManager.DEFAULT_PORT_INDEX); } /** Add a resolution intent to the given extras intent. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void addResolutionIntent(Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { EuiccOperation op, int cardId, int portIndex) { Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR); intent.setPackage(RESOLUTION_ACTIVITY_PACKAGE_NAME); intent.setComponent(new ComponentName( Loading @@ -1293,6 +1348,7 @@ public class EuiccController extends IEuiccController.Stub { intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage); intent.putExtra(EuiccService.EXTRA_RESOLVABLE_ERRORS, resolvableErrors); intent.putExtra(EuiccService.EXTRA_RESOLUTION_CARD_ID, cardId); intent.putExtra(EuiccService.EXTRA_RESOLUTION_PORT_INDEX, portIndex); intent.putExtra(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED, confirmationCodeRetried); intent.putExtra(EXTRA_OPERATION, op); Loading
src/java/com/android/internal/telephony/euicc/EuiccOperation.java +24 −10 Original line number Diff line number Diff line Loading @@ -302,16 +302,26 @@ public class EuiccOperation implements Parcelable { resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_DEACTIVATE_SIM: resolvedSwitchDeactivateSim(cardId, case ACTION_SWITCH_DEACTIVATE_SIM: { // get portIndex from original operation final int portIndex = resolutionExtras.getInt( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolvedSwitchDeactivateSim(cardId, portIndex, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_NO_PRIVILEGES: resolvedSwitchNoPrivileges(cardId, } case ACTION_SWITCH_NO_PRIVILEGES: { // get portIndex from original operation final int portIndex = resolutionExtras.getInt( EuiccService.EXTRA_RESOLUTION_PORT_INDEX, 0); resolvedSwitchNoPrivileges(cardId, portIndex, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; } default: Log.wtf(TAG, "Unknown action: " + mAction); break; Loading Loading @@ -482,24 +492,26 @@ public class EuiccOperation implements Parcelable { } } private void resolvedSwitchDeactivateSim(int cardId, boolean consent, private void resolvedSwitchDeactivateSim(int cardId, int portIndex, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().switchToSubscription( EuiccController euiccController = EuiccController.get(); euiccController.switchToSubscription( cardId, portIndex, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); euiccController.getCallbackFromPendingIntent(callbackIntent)); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchNoPrivileges(int cardId, boolean consent, private void resolvedSwitchNoPrivileges(int cardId, int portIndex, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch with full privileges. Loading @@ -511,13 +523,15 @@ public class EuiccOperation implements Parcelable { // carrier. Also note that in practice, we'd need to deactivate the active SIM to // even reach this point, because we cannot fetch the metadata needed to check the // privileges without doing so. EuiccController.get().switchToSubscriptionPrivileged( EuiccController euiccController = EuiccController.get(); euiccController.switchToSubscriptionPrivileged( cardId, portIndex, token, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); euiccController.getCallbackFromPendingIntent(callbackIntent)); } finally { Binder.restoreCallingIdentity(token); } Loading
tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ public class EuiccConnectorTest extends TelephonyTest { @Mock private IEuiccService.Stub mEuiccService; private static final int CARD_ID = 15; private static final int PORT_INDEX = 0; @Before public void setUp() throws Exception { Loading Loading @@ -137,7 +138,7 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.switchToSubscription(CARD_ID, "12345", true, new mConnector.switchToSubscription(CARD_ID, PORT_INDEX, "12345", true, new EuiccConnector.SwitchCommandCallback() { @Override public void onSwitchComplete(int result) { Loading
tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +21 −17 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ public class EuiccControllerTest extends TelephonyTest { private static final int SUBSCRIPTION_ID = 12345; private static final String ICC_ID = "54321"; private static final int CARD_ID = 25; private static final int PORT_INDEX = 0; @Mock private EuiccConnector mMockConnector; private TestEuiccController mController; Loading Loading @@ -148,7 +149,7 @@ public class EuiccControllerTest extends TelephonyTest { public void addResolutionIntent( Intent extrasIntent, String resolutionAction, String callingPackage, int resolvableErrors, boolean confirmationCodeRetried, EuiccOperation op, int cardId) { int cardId, int portIndex) { mResolutionAction = resolutionAction; mOp = op; } Loading Loading @@ -765,8 +766,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading @@ -777,8 +778,8 @@ public class EuiccControllerTest extends TelephonyTest { 0 /* result */, "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading @@ -790,7 +791,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading Loading @@ -832,8 +834,8 @@ public class EuiccControllerTest extends TelephonyTest { "whatever" /* callingPackage */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); } @Test Loading Loading @@ -868,8 +870,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading @@ -885,8 +887,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading @@ -902,8 +904,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION_ID, ICC_ID, false /* complete */, 0 /* result */, PACKAGE_NAME); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0 /* detailedCode */); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyString(), anyBoolean(), any()); verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(), anyBoolean(), any()); verifyResolutionIntent(EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, EuiccOperation.ACTION_SWITCH_NO_PRIVILEGES); } Loading Loading @@ -1383,7 +1385,7 @@ public class EuiccControllerTest extends TelephonyTest { @Override public Void answer(InvocationOnMock invocation) throws Exception { EuiccConnector.SwitchCommandCallback cb = invocation .getArgument(3 /* resultCallback */); .getArgument(4 /* resultCallback */); if (complete) { cb.onSwitchComplete(result); } else { Loading @@ -1391,8 +1393,10 @@ public class EuiccControllerTest extends TelephonyTest { } return null; } }).when(mMockConnector).switchToSubscription(anyInt(), eq(iccid), anyBoolean(), any()); mController.switchToSubscription(CARD_ID, subscriptionId, callingPackage, resultCallback); }).when(mMockConnector).switchToSubscription(anyInt(), anyInt(), eq(iccid), anyBoolean(), any()); mController.switchToSubscription(CARD_ID, subscriptionId, callingPackage, resultCallback); } private void callUpdateSubscriptionNickname(int subscriptionId, String iccid, String nickname, Loading