Loading src/java/com/android/internal/telephony/euicc/EuiccConnector.java +49 −28 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; import android.service.euicc.ISwitchToSubscriptionCallback; import android.service.euicc.IUpdateSubscriptionNicknameCallback; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccInfo; import android.telephony.euicc.EuiccManager; Loading Loading @@ -219,7 +221,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { @VisibleForTesting(visibility = PACKAGE) public interface GetMetadataCommandCallback extends BaseEuiccCommandCallback { /** Called when the metadata lookup has completed (though it may have failed). */ void onGetMetadataComplete(GetDownloadableSubscriptionMetadataResult result); void onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result); } static class DownloadRequest { Loading Loading @@ -394,37 +396,38 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously fetch the EID. */ @VisibleForTesting(visibility = PACKAGE) public void getEid(GetEidCommandCallback callback) { sendMessage(CMD_GET_EID, callback); public void getEid(int cardId, GetEidCommandCallback callback) { sendMessage(CMD_GET_EID, cardId, 0 /* arg2 */, callback); } /** Asynchronously get OTA status. */ @VisibleForTesting(visibility = PACKAGE) public void getOtaStatus(GetOtaStatusCommandCallback callback) { sendMessage(CMD_GET_OTA_STATUS, callback); public void getOtaStatus(int cardId, GetOtaStatusCommandCallback callback) { sendMessage(CMD_GET_OTA_STATUS, cardId, 0 /* arg2 */, callback); } /** Asynchronously perform OTA update. */ @VisibleForTesting(visibility = PACKAGE) public void startOtaIfNecessary(OtaStatusChangedCallback callback) { sendMessage(CMD_START_OTA_IF_NECESSARY, callback); public void startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback) { sendMessage(CMD_START_OTA_IF_NECESSARY, cardId, 0 /* arg2 */, callback); } /** Asynchronously fetch metadata for the given downloadable subscription. */ @VisibleForTesting(visibility = PACKAGE) public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, public void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, GetMetadataCommandCallback callback) { GetMetadataRequest request = new GetMetadataRequest(); request.mSubscription = subscription; request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, request); sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request); } /** Asynchronously download the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void downloadSubscription(DownloadableSubscription subscription, public void downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback) { DownloadRequest request = new DownloadRequest(); Loading @@ -433,7 +436,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { request.mForceDeactivateSim = forceDeactivateSim; request.mResolvedBundle = resolvedBundle; request.mCallback = callback; sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, request); sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } void getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback) { Loading @@ -442,61 +445,61 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously fetch the default downloadable subscription list. */ @VisibleForTesting(visibility = PACKAGE) public void getDefaultDownloadableSubscriptionList( public void getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, GetDefaultListCommandCallback callback) { GetDefaultListRequest request = new GetDefaultListRequest(); request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, request); sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, cardId, 0 /* arg2 */, request); } /** Asynchronously fetch the {@link EuiccInfo}. */ @VisibleForTesting(visibility = PACKAGE) public void getEuiccInfo(GetEuiccInfoCommandCallback callback) { sendMessage(CMD_GET_EUICC_INFO, callback); public void getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback) { sendMessage(CMD_GET_EUICC_INFO, cardId, 0 /* arg2 */, callback); } /** Asynchronously delete the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void deleteSubscription(String iccid, DeleteCommandCallback callback) { public void deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback) { DeleteRequest request = new DeleteRequest(); request.mIccid = iccid; request.mCallback = callback; sendMessage(CMD_DELETE_SUBSCRIPTION, request); sendMessage(CMD_DELETE_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } /** Asynchronously switch to the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void switchToSubscription(@Nullable String iccid, boolean forceDeactivateSim, public void switchToSubscription(int cardId, @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, request); sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } /** Asynchronously update the nickname of the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void updateSubscriptionNickname( public void updateSubscriptionNickname(int cardId, String iccid, String nickname, UpdateNicknameCommandCallback callback) { UpdateNicknameRequest request = new UpdateNicknameRequest(); request.mIccid = iccid; request.mNickname = nickname; request.mCallback = callback; sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, request); sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, cardId, 0 /* arg2 */, request); } /** Asynchronously erase all profiles on the eUICC. */ @VisibleForTesting(visibility = PACKAGE) public void eraseSubscriptions(EraseCommandCallback callback) { sendMessage(CMD_ERASE_SUBSCRIPTIONS, callback); public void eraseSubscriptions(int cardId, EraseCommandCallback callback) { sendMessage(CMD_ERASE_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); } /** Asynchronously ensure that all profiles will be retained on the next factory reset. */ @VisibleForTesting(visibility = PACKAGE) public void retainSubscriptions(RetainSubscriptionsCommandCallback callback) { sendMessage(CMD_RETAIN_SUBSCRIPTIONS, callback); public void retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback) { sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); } /** Loading Loading @@ -671,8 +674,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } else if (isEuiccCommand(message.what)) { final BaseEuiccCommandCallback callback = getCallback(message); onCommandStart(callback); // TODO(b/36260308): Plumb through an actual SIM slot ID. int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; final int slotId = getSlotIdFromCardId(message.arg1); try { switch (message.what) { case CMD_GET_EID: { Loading Loading @@ -700,7 +702,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { GetDownloadableSubscriptionMetadataResult result) { sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { ((GetMetadataCommandCallback) callback) .onGetMetadataComplete(result); .onGetMetadataComplete(slotId, result); onCommandEnd(callback); }); } Loading Loading @@ -946,6 +948,25 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } } /** * Gets the slot ID from the card ID. */ private int getSlotIdFromCardId(int cardId) { TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); UiccCardInfo[] infos = tm.getUiccCardsInfo(); if (infos == null) { return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; for (UiccCardInfo info : infos) { if (info.getCardId() == cardId) { slotId = info.getSlotIndex(); } } return slotId; } /** Call this at the beginning of the execution of any command. */ private void onCommandStart(BaseEuiccCommandCallback callback) { mActiveCommandCallbacks.add(callback); Loading src/java/com/android/internal/telephony/euicc/EuiccController.java +74 −56 File changed.Preview size limit exceeded, changes collapsed. Show changes src/java/com/android/internal/telephony/euicc/EuiccOperation.java +35 −22 Original line number Diff line number Diff line Loading @@ -245,7 +245,8 @@ public class EuiccOperation implements Parcelable { * {@link EuiccManager#continueOperation}. * @param callbackIntent The callback intent to trigger after the operation completes. */ public void continueOperation(Bundle resolutionExtras, PendingIntent callbackIntent) { public void continueOperation(int cardId, Bundle resolutionExtras, PendingIntent callbackIntent) { // Restore the identity of the caller. We should err on the side of caution and redo any // permission checks before continuing with the operation in case the caller state has // changed. Resolution flows can re-clear the identity if required. Loading @@ -253,40 +254,40 @@ public class EuiccOperation implements Parcelable { switch (mAction) { case ACTION_GET_METADATA_DEACTIVATE_SIM: resolvedGetMetadataDeactivateSim( resolvedGetMetadataDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_DEACTIVATE_SIM: resolvedDownloadDeactivateSim( resolvedDownloadDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_NO_PRIVILEGES: resolvedDownloadNoPrivileges( resolvedDownloadNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_CONFIRMATION_CODE: // Deprecated case resolvedDownloadConfirmationCode( resolvedDownloadConfirmationCode(cardId, resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE), callbackIntent); break; case ACTION_DOWNLOAD_RESOLVABLE_ERRORS: resolvedDownloadResolvableErrors(resolutionExtras, callbackIntent); resolvedDownloadResolvableErrors(cardId, resolutionExtras, callbackIntent); break; case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM: resolvedGetDefaultListDeactivateSim( resolvedGetDefaultListDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_DEACTIVATE_SIM: resolvedSwitchDeactivateSim( resolvedSwitchDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_NO_PRIVILEGES: resolvedSwitchNoPrivileges( resolvedSwitchNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; Loading @@ -296,12 +297,13 @@ public class EuiccOperation implements Parcelable { } } private void resolvedGetMetadataDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedGetMetadataDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDownloadableSubscriptionMetadata( cardId, mDownloadableSubscription, true /* forceDeactivateSim */, mCallingPackage, Loading @@ -312,12 +314,13 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedDownloadDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the download, but this time, tell the LPA to deactivate // any required active SIMs. EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -330,7 +333,8 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadNoPrivileges(boolean consent, PendingIntent callbackIntent) { private void resolvedDownloadNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the download with full privileges. long token = Binder.clearCallingIdentity(); Loading @@ -340,6 +344,7 @@ public class EuiccOperation implements Parcelable { // the privilege prompt makes it clear that we're switching from the current // carrier. EuiccController.get().downloadSubscriptionPrivileged( cardId, token, mDownloadableSubscription, mSwitchAfterDownload, Loading @@ -361,13 +366,14 @@ public class EuiccOperation implements Parcelable { * {@link #resolvedDownloadResolvableErrors(Bundle, PendingIntent)} from Q. */ @Deprecated private void resolvedDownloadConfirmationCode(String confirmationCode, private void resolvedDownloadConfirmationCode(int cardId, String confirmationCode, PendingIntent callbackIntent) { if (TextUtils.isEmpty(confirmationCode)) { fail(callbackIntent); } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -377,7 +383,7 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadResolvableErrors(Bundle resolvedBundle, private void resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, PendingIntent callbackIntent) { boolean pass = true; String confirmationCode = null; Loading @@ -401,6 +407,7 @@ public class EuiccOperation implements Parcelable { } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -410,25 +417,29 @@ public class EuiccOperation implements Parcelable { } } private void resolvedGetDefaultListDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDefaultDownloadableSubscriptionList( true /* forceDeactivateSim */, mCallingPackage, callbackIntent); cardId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedSwitchDeactivateSim(int cardId, 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( cardId, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, Loading @@ -439,7 +450,8 @@ public class EuiccOperation implements Parcelable { } } private void resolvedSwitchNoPrivileges(boolean consent, PendingIntent callbackIntent) { private void resolvedSwitchNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch with full privileges. long token = Binder.clearCallingIdentity(); Loading @@ -451,6 +463,7 @@ public class EuiccOperation implements Parcelable { // even reach this point, because we cannot fetch the metadata needed to check the // privileges without doing so. EuiccController.get().switchToSubscriptionPrivileged( cardId, token, mSubscriptionId, true /* forceDeactivateSim */, Loading tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; Loading Loading @@ -82,7 +83,7 @@ public class EuiccCardControllerTest extends TelephonyTest { mOtaStarted = false; mOtaLatch = new CountDownLatch(1); when(mEuiccController.getOtaStatus()).thenReturn(EuiccManager.EUICC_OTA_SUCCEEDED); when(mEuiccController.getOtaStatus(anyInt())).thenReturn(EuiccManager.EUICC_OTA_SUCCEEDED); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Loading tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java +11 −8 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ public class EuiccConnectorTest extends TelephonyTest { private EuiccConnector mConnector; @Mock private IEuiccService.Stub mEuiccService; private static final int CARD_ID = 15; @Before public void setUp() throws Exception { super.setUp("EuiccConnectorTest"); Loading Loading @@ -114,7 +116,7 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Command should have failed"); Loading @@ -135,7 +137,8 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.switchToSubscription("12345", true, new EuiccConnector.SwitchCommandCallback() { mConnector.switchToSubscription(CARD_ID, "12345", true, new EuiccConnector.SwitchCommandCallback() { @Override public void onSwitchComplete(int result) { fail("Command should have failed"); Loading Loading @@ -210,7 +213,7 @@ public class EuiccConnectorTest extends TelephonyTest { } }).when(mEuiccService).getEid(anyInt(), Mockito.<IGetEidCallback>any()); final AtomicReference<String> eidRef = new AtomicReference<>(); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { if (eidRef.get() != null) { Loading @@ -236,7 +239,7 @@ public class EuiccConnectorTest extends TelephonyTest { doThrow(new RemoteException("failure")) .when(mEuiccService).getEid(anyInt(), Mockito.<IGetEidCallback>any()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Command should have failed"); Loading @@ -258,7 +261,7 @@ public class EuiccConnectorTest extends TelephonyTest { true /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Unexpected command success callback"); Loading Loading @@ -288,7 +291,7 @@ public class EuiccConnectorTest extends TelephonyTest { ArgumentCaptor<IGetEidCallback> callbackCaptor = ArgumentCaptor.forClass(IGetEidCallback.class); doNothing().when(mEuiccService).getEid(anyInt(), callbackCaptor.capture()); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); Loading Loading @@ -316,11 +319,11 @@ public class EuiccConnectorTest extends TelephonyTest { ArgumentCaptor<IGetEidCallback> callbackCaptor = ArgumentCaptor.forClass(IGetEidCallback.class); doNothing().when(mEuiccService).getEid(anyInt(), callbackCaptor.capture()); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); Loading Loading
src/java/com/android/internal/telephony/euicc/EuiccConnector.java +49 −28 Original line number Diff line number Diff line Loading @@ -55,6 +55,8 @@ import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; import android.service.euicc.ISwitchToSubscriptionCallback; import android.service.euicc.IUpdateSubscriptionNicknameCallback; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccInfo; import android.telephony.euicc.EuiccManager; Loading Loading @@ -219,7 +221,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { @VisibleForTesting(visibility = PACKAGE) public interface GetMetadataCommandCallback extends BaseEuiccCommandCallback { /** Called when the metadata lookup has completed (though it may have failed). */ void onGetMetadataComplete(GetDownloadableSubscriptionMetadataResult result); void onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result); } static class DownloadRequest { Loading Loading @@ -394,37 +396,38 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously fetch the EID. */ @VisibleForTesting(visibility = PACKAGE) public void getEid(GetEidCommandCallback callback) { sendMessage(CMD_GET_EID, callback); public void getEid(int cardId, GetEidCommandCallback callback) { sendMessage(CMD_GET_EID, cardId, 0 /* arg2 */, callback); } /** Asynchronously get OTA status. */ @VisibleForTesting(visibility = PACKAGE) public void getOtaStatus(GetOtaStatusCommandCallback callback) { sendMessage(CMD_GET_OTA_STATUS, callback); public void getOtaStatus(int cardId, GetOtaStatusCommandCallback callback) { sendMessage(CMD_GET_OTA_STATUS, cardId, 0 /* arg2 */, callback); } /** Asynchronously perform OTA update. */ @VisibleForTesting(visibility = PACKAGE) public void startOtaIfNecessary(OtaStatusChangedCallback callback) { sendMessage(CMD_START_OTA_IF_NECESSARY, callback); public void startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback) { sendMessage(CMD_START_OTA_IF_NECESSARY, cardId, 0 /* arg2 */, callback); } /** Asynchronously fetch metadata for the given downloadable subscription. */ @VisibleForTesting(visibility = PACKAGE) public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, public void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, GetMetadataCommandCallback callback) { GetMetadataRequest request = new GetMetadataRequest(); request.mSubscription = subscription; request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, request); sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request); } /** Asynchronously download the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void downloadSubscription(DownloadableSubscription subscription, public void downloadSubscription(int cardId, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback) { DownloadRequest request = new DownloadRequest(); Loading @@ -433,7 +436,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { request.mForceDeactivateSim = forceDeactivateSim; request.mResolvedBundle = resolvedBundle; request.mCallback = callback; sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, request); sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } void getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback) { Loading @@ -442,61 +445,61 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously fetch the default downloadable subscription list. */ @VisibleForTesting(visibility = PACKAGE) public void getDefaultDownloadableSubscriptionList( public void getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, GetDefaultListCommandCallback callback) { GetDefaultListRequest request = new GetDefaultListRequest(); request.mForceDeactivateSim = forceDeactivateSim; request.mCallback = callback; sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, request); sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, cardId, 0 /* arg2 */, request); } /** Asynchronously fetch the {@link EuiccInfo}. */ @VisibleForTesting(visibility = PACKAGE) public void getEuiccInfo(GetEuiccInfoCommandCallback callback) { sendMessage(CMD_GET_EUICC_INFO, callback); public void getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback) { sendMessage(CMD_GET_EUICC_INFO, cardId, 0 /* arg2 */, callback); } /** Asynchronously delete the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void deleteSubscription(String iccid, DeleteCommandCallback callback) { public void deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback) { DeleteRequest request = new DeleteRequest(); request.mIccid = iccid; request.mCallback = callback; sendMessage(CMD_DELETE_SUBSCRIPTION, request); sendMessage(CMD_DELETE_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } /** Asynchronously switch to the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void switchToSubscription(@Nullable String iccid, boolean forceDeactivateSim, public void switchToSubscription(int cardId, @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, request); sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, 0 /* arg2 */, request); } /** Asynchronously update the nickname of the given subscription. */ @VisibleForTesting(visibility = PACKAGE) public void updateSubscriptionNickname( public void updateSubscriptionNickname(int cardId, String iccid, String nickname, UpdateNicknameCommandCallback callback) { UpdateNicknameRequest request = new UpdateNicknameRequest(); request.mIccid = iccid; request.mNickname = nickname; request.mCallback = callback; sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, request); sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, cardId, 0 /* arg2 */, request); } /** Asynchronously erase all profiles on the eUICC. */ @VisibleForTesting(visibility = PACKAGE) public void eraseSubscriptions(EraseCommandCallback callback) { sendMessage(CMD_ERASE_SUBSCRIPTIONS, callback); public void eraseSubscriptions(int cardId, EraseCommandCallback callback) { sendMessage(CMD_ERASE_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); } /** Asynchronously ensure that all profiles will be retained on the next factory reset. */ @VisibleForTesting(visibility = PACKAGE) public void retainSubscriptions(RetainSubscriptionsCommandCallback callback) { sendMessage(CMD_RETAIN_SUBSCRIPTIONS, callback); public void retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback) { sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback); } /** Loading Loading @@ -671,8 +674,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } else if (isEuiccCommand(message.what)) { final BaseEuiccCommandCallback callback = getCallback(message); onCommandStart(callback); // TODO(b/36260308): Plumb through an actual SIM slot ID. int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; final int slotId = getSlotIdFromCardId(message.arg1); try { switch (message.what) { case CMD_GET_EID: { Loading Loading @@ -700,7 +702,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { GetDownloadableSubscriptionMetadataResult result) { sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> { ((GetMetadataCommandCallback) callback) .onGetMetadataComplete(result); .onGetMetadataComplete(slotId, result); onCommandEnd(callback); }); } Loading Loading @@ -946,6 +948,25 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } } /** * Gets the slot ID from the card ID. */ private int getSlotIdFromCardId(int cardId) { TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); UiccCardInfo[] infos = tm.getUiccCardsInfo(); if (infos == null) { return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; for (UiccCardInfo info : infos) { if (info.getCardId() == cardId) { slotId = info.getSlotIndex(); } } return slotId; } /** Call this at the beginning of the execution of any command. */ private void onCommandStart(BaseEuiccCommandCallback callback) { mActiveCommandCallbacks.add(callback); Loading
src/java/com/android/internal/telephony/euicc/EuiccController.java +74 −56 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/java/com/android/internal/telephony/euicc/EuiccOperation.java +35 −22 Original line number Diff line number Diff line Loading @@ -245,7 +245,8 @@ public class EuiccOperation implements Parcelable { * {@link EuiccManager#continueOperation}. * @param callbackIntent The callback intent to trigger after the operation completes. */ public void continueOperation(Bundle resolutionExtras, PendingIntent callbackIntent) { public void continueOperation(int cardId, Bundle resolutionExtras, PendingIntent callbackIntent) { // Restore the identity of the caller. We should err on the side of caution and redo any // permission checks before continuing with the operation in case the caller state has // changed. Resolution flows can re-clear the identity if required. Loading @@ -253,40 +254,40 @@ public class EuiccOperation implements Parcelable { switch (mAction) { case ACTION_GET_METADATA_DEACTIVATE_SIM: resolvedGetMetadataDeactivateSim( resolvedGetMetadataDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_DEACTIVATE_SIM: resolvedDownloadDeactivateSim( resolvedDownloadDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_NO_PRIVILEGES: resolvedDownloadNoPrivileges( resolvedDownloadNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_DOWNLOAD_CONFIRMATION_CODE: // Deprecated case resolvedDownloadConfirmationCode( resolvedDownloadConfirmationCode(cardId, resolutionExtras.getString(EuiccService.EXTRA_RESOLUTION_CONFIRMATION_CODE), callbackIntent); break; case ACTION_DOWNLOAD_RESOLVABLE_ERRORS: resolvedDownloadResolvableErrors(resolutionExtras, callbackIntent); resolvedDownloadResolvableErrors(cardId, resolutionExtras, callbackIntent); break; case ACTION_GET_DEFAULT_LIST_DEACTIVATE_SIM: resolvedGetDefaultListDeactivateSim( resolvedGetDefaultListDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_DEACTIVATE_SIM: resolvedSwitchDeactivateSim( resolvedSwitchDeactivateSim(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; case ACTION_SWITCH_NO_PRIVILEGES: resolvedSwitchNoPrivileges( resolvedSwitchNoPrivileges(cardId, resolutionExtras.getBoolean(EuiccService.EXTRA_RESOLUTION_CONSENT), callbackIntent); break; Loading @@ -296,12 +297,13 @@ public class EuiccOperation implements Parcelable { } } private void resolvedGetMetadataDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedGetMetadataDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDownloadableSubscriptionMetadata( cardId, mDownloadableSubscription, true /* forceDeactivateSim */, mCallingPackage, Loading @@ -312,12 +314,13 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedDownloadDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the download, but this time, tell the LPA to deactivate // any required active SIMs. EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -330,7 +333,8 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadNoPrivileges(boolean consent, PendingIntent callbackIntent) { private void resolvedDownloadNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the download with full privileges. long token = Binder.clearCallingIdentity(); Loading @@ -340,6 +344,7 @@ public class EuiccOperation implements Parcelable { // the privilege prompt makes it clear that we're switching from the current // carrier. EuiccController.get().downloadSubscriptionPrivileged( cardId, token, mDownloadableSubscription, mSwitchAfterDownload, Loading @@ -361,13 +366,14 @@ public class EuiccOperation implements Parcelable { * {@link #resolvedDownloadResolvableErrors(Bundle, PendingIntent)} from Q. */ @Deprecated private void resolvedDownloadConfirmationCode(String confirmationCode, private void resolvedDownloadConfirmationCode(int cardId, String confirmationCode, PendingIntent callbackIntent) { if (TextUtils.isEmpty(confirmationCode)) { fail(callbackIntent); } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -377,7 +383,7 @@ public class EuiccOperation implements Parcelable { } } private void resolvedDownloadResolvableErrors(Bundle resolvedBundle, private void resolvedDownloadResolvableErrors(int cardId, Bundle resolvedBundle, PendingIntent callbackIntent) { boolean pass = true; String confirmationCode = null; Loading @@ -401,6 +407,7 @@ public class EuiccOperation implements Parcelable { } else { mDownloadableSubscription.setConfirmationCode(confirmationCode); EuiccController.get().downloadSubscription( cardId, mDownloadableSubscription, mSwitchAfterDownload, mCallingPackage, Loading @@ -410,25 +417,29 @@ public class EuiccOperation implements Parcelable { } } private void resolvedGetDefaultListDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedGetDefaultListDeactivateSim(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the lookup, but this time, tell the LPA to deactivate any // required active SIMs. EuiccController.get().getDefaultDownloadableSubscriptionList( true /* forceDeactivateSim */, mCallingPackage, callbackIntent); cardId, true /* forceDeactivateSim */, mCallingPackage, callbackIntent); } else { // User has not consented; fail the operation. fail(callbackIntent); } } private void resolvedSwitchDeactivateSim( boolean consent, PendingIntent callbackIntent) { private void resolvedSwitchDeactivateSim(int cardId, 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( cardId, mSubscriptionId, true /* forceDeactivateSim */, mCallingPackage, Loading @@ -439,7 +450,8 @@ public class EuiccOperation implements Parcelable { } } private void resolvedSwitchNoPrivileges(boolean consent, PendingIntent callbackIntent) { private void resolvedSwitchNoPrivileges(int cardId, boolean consent, PendingIntent callbackIntent) { if (consent) { // User has consented; perform the switch with full privileges. long token = Binder.clearCallingIdentity(); Loading @@ -451,6 +463,7 @@ public class EuiccOperation implements Parcelable { // even reach this point, because we cannot fetch the metadata needed to check the // privileges without doing so. EuiccController.get().switchToSubscriptionPrivileged( cardId, token, mSubscriptionId, true /* forceDeactivateSim */, Loading
tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccCardControllerTest.java +2 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.when; Loading Loading @@ -82,7 +83,7 @@ public class EuiccCardControllerTest extends TelephonyTest { mOtaStarted = false; mOtaLatch = new CountDownLatch(1); when(mEuiccController.getOtaStatus()).thenReturn(EuiccManager.EUICC_OTA_SUCCEEDED); when(mEuiccController.getOtaStatus(anyInt())).thenReturn(EuiccManager.EUICC_OTA_SUCCEEDED); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { Loading
tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java +11 −8 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ public class EuiccConnectorTest extends TelephonyTest { private EuiccConnector mConnector; @Mock private IEuiccService.Stub mEuiccService; private static final int CARD_ID = 15; @Before public void setUp() throws Exception { super.setUp("EuiccConnectorTest"); Loading Loading @@ -114,7 +116,7 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Command should have failed"); Loading @@ -135,7 +137,8 @@ public class EuiccConnectorTest extends TelephonyTest { false /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.switchToSubscription("12345", true, new EuiccConnector.SwitchCommandCallback() { mConnector.switchToSubscription(CARD_ID, "12345", true, new EuiccConnector.SwitchCommandCallback() { @Override public void onSwitchComplete(int result) { fail("Command should have failed"); Loading Loading @@ -210,7 +213,7 @@ public class EuiccConnectorTest extends TelephonyTest { } }).when(mEuiccService).getEid(anyInt(), Mockito.<IGetEidCallback>any()); final AtomicReference<String> eidRef = new AtomicReference<>(); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { if (eidRef.get() != null) { Loading @@ -236,7 +239,7 @@ public class EuiccConnectorTest extends TelephonyTest { doThrow(new RemoteException("failure")) .when(mEuiccService).getEid(anyInt(), Mockito.<IGetEidCallback>any()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Command should have failed"); Loading @@ -258,7 +261,7 @@ public class EuiccConnectorTest extends TelephonyTest { true /* hasPriority */); mConnector = new EuiccConnector(mContext, mLooper.getLooper()); final AtomicBoolean called = new AtomicBoolean(false); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) { fail("Unexpected command success callback"); Loading Loading @@ -288,7 +291,7 @@ public class EuiccConnectorTest extends TelephonyTest { ArgumentCaptor<IGetEidCallback> callbackCaptor = ArgumentCaptor.forClass(IGetEidCallback.class); doNothing().when(mEuiccService).getEid(anyInt(), callbackCaptor.capture()); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); Loading Loading @@ -316,11 +319,11 @@ public class EuiccConnectorTest extends TelephonyTest { ArgumentCaptor<IGetEidCallback> callbackCaptor = ArgumentCaptor.forClass(IGetEidCallback.class); doNothing().when(mEuiccService).getEid(anyInt(), callbackCaptor.capture()); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { @Override public void onGetEidComplete(String eid) {} @Override public void onEuiccServiceUnavailable() {} }); Loading