/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.uicc.euicc; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.service.carrier.CarrierIdentifier; import android.service.euicc.EuiccProfileInfo; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccNotification; import android.telephony.euicc.EuiccRulesAuthTable; import android.util.ExceptionUtils; import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.asn1.Asn1Node; import com.android.internal.telephony.uicc.euicc.apdu.LogicalChannelMocker; import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class EuiccCardTest extends TelephonyTest { private static final long WAIT_TIMEOUT_MLLIS = 5000; private static class ResultCaptor extends AsyncResultCallback { public T result; public Throwable exception; private CountDownLatch mLatch; private ResultCaptor() { mLatch = new CountDownLatch(1); } public void await() { try { mLatch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { fail("Execution is interrupted: " + e); } } @Override public void onResult(T r) { result = r; mLatch.countDown(); } @Override public void onException(Throwable e) { exception = e; mLatch.countDown(); } } private class UiccCardHandlerThread extends HandlerThread { private UiccCardHandlerThread(String name) { super(name); } @Override public void onLooperPrepared() { mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus, 0 /* phoneId */) { @Override protected byte[] getDeviceId() { return IccUtils.bcdToBytes("987654321012345"); } @Override protected void loadEidAndNotifyRegistrants() {} }; mHandler = new Handler(mTestHandlerThread.getLooper()); setReady(true); } } @Mock private CommandsInterface mMockCi; @Mock private IccCardStatus mMockIccCardStatus; private UiccCardHandlerThread mTestHandlerThread; private Handler mHandler; private EuiccCard mEuiccCard; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mMockIccCardStatus.mApplications = new IccCardApplicationStatus[]{}; mMockIccCardStatus.mCdmaSubscriptionAppIndex = mMockIccCardStatus.mImsSubscriptionAppIndex = mMockIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1; mMockIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT; mTestHandlerThread = new UiccCardHandlerThread(getClass().getSimpleName()); mTestHandlerThread.start(); waitUntilReady(); } @After public void tearDown() throws Exception { mTestHandlerThread.quit(); super.tearDown(); } private void assertUnexpectedException(Throwable e) { if (e != null) { fail("Unexpected exception: " + ExceptionUtils.getCompleteMessage(e) + "\n-----\n" + Log.getStackTraceString(e.getCause()) + "-----"); } } @Test public void testLoadEidAndNotifyRegistrants() throws InterruptedException { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); { final CountDownLatch latch = new CountDownLatch(1); mHandler.post(() -> { mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus, 0 /* phoneId */); latch.countDown(); }); assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS)); } final int eventEidReady = 0; final CountDownLatch latch = new CountDownLatch(1); Handler handler = new Handler(mTestHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == eventEidReady) { assertEquals("1A2B3C4D", mEuiccCard.getEid()); latch.countDown(); } } }; mEuiccCard.registerForEidReady(handler, eventEidReady, null /* obj */); assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS)); verifyStoreData(channel, "BF3E035C015A"); } @Test public void testGetAllProfiles() { int channel = mockLogicalChannelResponses( "BF2D14A012E3105A0A896700000000004523019F7001019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getAllProfiles(resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); EuiccProfileInfo[] profiles = resultCaptor.result; assertEquals(1, profiles.length); assertEquals("98760000000000543210", profiles[0].getIccid()); assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState()); verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76"); } @Test public void testFSuffix() { // iccID is 987600000000005432FF. int channel = mockLogicalChannelResponses( "BF2D14A012E3105A0A896700000000004523FF9F7001019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getAllProfiles(resultCaptor, mHandler); resultCaptor.await(); EuiccProfileInfo[] profiles = resultCaptor.result; assertEquals(1, profiles.length); assertEquals("987600000000005432", profiles[0].getIccid()); assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState()); verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76"); } @Test public void testGetProfile() { int channel = mockLogicalChannelResponses("BF2D8184A08181E37F" + "5A0A89670000000000452301" // ICCID + "90046E69636B" // Nickname + "9103746D6F" // Service provider name + "92027031" // Profile name + "B70F800312F34581030102038203040506" // Operator id + "9F700101" // Profile state + "950101" // Profile class + "990206C0" // Policy rules + "BF7645E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4" + "CA1D636F6D2E676F6F676C652E616E64726F69642E617070732E6D79617070" + "E30ADB080000000000000001" // Carrier privilege rules + "9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getProfile("98760000000000543210", resultCaptor, mHandler); resultCaptor.await(); EuiccProfileInfo profile = resultCaptor.result; assertEquals("98760000000000543210", profile.getIccid()); assertEquals("nick", profile.getNickname()); assertEquals("tmo", profile.getServiceProviderName()); assertEquals("p1", profile.getProfileName()); assertEquals("213", profile.getCarrierIdentifier().getMcc()); assertEquals("54", profile.getCarrierIdentifier().getMnc()); assertEquals("010203", profile.getCarrierIdentifier().getGid1()); assertEquals("040506", profile.getCarrierIdentifier().getGid2()); assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profile.getState()); assertEquals(EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, profile.getProfileClass()); assertEquals( EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE | EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, profile.getPolicyRules()); assertArrayEquals( new UiccAccessRule[] { new UiccAccessRule( IccUtils.hexStringToBytes( "ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4"), "com.google.android.apps.myapp", 1) }, profile.getUiccAccessRules().toArray()); verifyStoreData(channel, "BF2D195A0A896700000000004523015C0B5A909192B79F709599BF76"); } @Test public void testDisableProfile() { int channel = mockLogicalChannelResponses("BF32038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF"); } @Test public void testDisableProfile_SimRefresh() { int channel = mockLogicalChannelResponses("6106", "6f00"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF"); } @Test public void testDisableProfile_Error() { int channel = mockLogicalChannelResponses("BF32038001039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF"); } @Test public void testSwitchToProfile() { int channel = mockLogicalChannelResponses("BF31038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF"); } @Test public void testSwitchToProfile_SimRefresh() { int channel = mockLogicalChannelResponses("6106", "6f00"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF"); } @Test public void testSwitchToProfile_Error() { int channel = mockLogicalChannelResponses("BF31038001039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF"); } @Test public void testGetEid() { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getEid(resultCaptor, mHandler); resultCaptor.await(); assertEquals("1A2B3C4D", resultCaptor.result); verifyStoreData(channel, "BF3E035C015A"); } @Test public void testSetNickname() { int channel = mockLogicalChannelResponses("BF29038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.setNickname("98760000000000543210", "new nickname", resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF291A5A0A89670000000000452301900C6E6577206E69636B6E616D65"); } @Test public void testDeleteProfile() { int channel = mockLogicalChannelResponses("BF33038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.deleteProfile("98760000000000543210", resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF330C5A0A89670000000000452301"); } @Test public void testDeleteProfile_Error() { int channel = mockLogicalChannelResponses("BF33038001039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.deleteProfile("98760000000000543210", resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF330C5A0A89670000000000452301"); } @Test public void testGetDefaultSmdpAddress() { int channel = mockLogicalChannelResponses( "BF3C148008534D44502E434F4D8108736D64732E636F6D9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getDefaultSmdpAddress(resultCaptor, mHandler); resultCaptor.await(); assertEquals("SMDP.COM", resultCaptor.result); verifyStoreData(channel, "BF3C00"); } @Test public void testGetSmdsAddress() { int channel = mockLogicalChannelResponses( "BF3C148008534D44502E434F4D8108736D64732E636F6D9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getSmdsAddress(resultCaptor, mHandler); resultCaptor.await(); assertEquals("smds.com", resultCaptor.result); verifyStoreData(channel, "BF3C00"); } @Test public void testSetDefaultSmdpAddress() { int channel = mockLogicalChannelResponses("BF3F038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.setDefaultSmdpAddress("smdp.gsma.com", resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3F0F800D736D64702E67736D612E636F6D"); } @Test public void testGetRulesAuthTable() { int channel = mockLogicalChannelResponses("BF4347" + "A021" // Rule #1 + "800206C0" // Policy rules: DO_NOT_DELETE | DO_NOT_DISABLE + "A118" // Operator IDs + "B70A800312F3458103010203" // ID #1: 213, 54, [1,2,3], null + "B70A800312F3458203040506" // ID #2: 213, 54, null, [4,5,6] + "820108" // Flag (no user consent) + "A022" // Rule #2 + "80020780" // Policy rules: DO_NOT_DISABLE + "A118" // Operator IDs + "B70A800312E3458103010203" // ID #1: 213, 54E, [1,2,3], null + "B70A8003EEEE458203040506" // ID #2: EEE, 54E, null, [4,5,6] + "82020780" // Flag (user consent) + "9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getRulesAuthTable(resultCaptor, mHandler); resultCaptor.await(); EuiccRulesAuthTable rat = resultCaptor.result; assertEquals(-1, rat.findIndex(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, new CarrierIdentifier(new byte[] {0x12, (byte) 0xF3, 0x45}, null, null))); assertEquals(1, rat.findIndex(EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, new CarrierIdentifier(new byte[] {0x23, 0x67, 0x45}, null, "040506"))); assertFalse(rat.hasPolicyRuleFlag(0, EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED)); assertTrue(rat.hasPolicyRuleFlag(1, EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED)); verifyStoreData(channel, "BF4300"); } @Test public void testResetMemory() { int channel = mockLogicalChannelResponses("BF34038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.resetMemory(EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF340482020640"); } @Test public void testResetMemory_SimRefresh() { int channel = mockLogicalChannelResponses("6106", "6f00"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.resetMemory(EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF340482020640"); } @Test public void testGetEuiccChallenge() { int channel = mockLogicalChannelResponses("BF2E0580030102039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getEuiccChallenge(resultCaptor, mHandler); resultCaptor.await(); assertArrayEquals(new byte[] {1, 2, 3}, resultCaptor.result); verifyStoreData(channel, "BF2E00"); } @Test public void testGetEuiccInfo1() { int channel = mockLogicalChannelResponses("BF20030102039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getEuiccInfo1(resultCaptor, mHandler); resultCaptor.await(); assertEquals("BF2003010203", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF2000"); } @Test public void testGetEuiccInfo2() { int channel = mockLogicalChannelResponses("BF22030102039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.getEuiccInfo2(resultCaptor, mHandler); resultCaptor.await(); assertEquals("BF2203010203", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF2200"); } @Test public void testAuthenticateServer() { int channel = mockLogicalChannelResponses("BF3802A0009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.authenticateServer("A1B2C3-X4Y5Z6", // Matching id Asn1Node.newBuilder(0xA0).build().toBytes(), Asn1Node.newBuilder(0xA1).build().toBytes(), Asn1Node.newBuilder(0xA2).build().toBytes(), Asn1Node.newBuilder(0xA3).build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); assertEquals("BF3802A000", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF382D" + "A000" + "A100" + "A200" + "A300" + "A023" + "800D4131423243332D583459355A36" // Matching id + "A112800489674523" // TAC + "A100" // Device capabilities + "82088967452301214305"); // IMEI } @Test public void testAuthenticateServer_Error() { int channel = mockLogicalChannelResponses("BF38038101039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.authenticateServer("A1B2C3-X4Y5Z6", // Matching id Asn1Node.newBuilder(0xA0).build().toBytes(), Asn1Node.newBuilder(0xA1).build().toBytes(), Asn1Node.newBuilder(0xA2).build().toBytes(), Asn1Node.newBuilder(0xA3).build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF382D" + "A000" + "A100" + "A200" + "A300" + "A023" + "800D4131423243332D583459355A36" // Matching id + "A112800489674523" // TAC + "A100" // Device capabilities + "82088967452301214305"); // IMEI } @Test public void testPrepareDownload() { int channel = mockLogicalChannelResponses("BF2102A0009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.prepareDownload( IccUtils.hexStringToBytes("4131423243332D583459355A36"), // hashCc Asn1Node.newBuilder(0xA0).build().toBytes(), Asn1Node.newBuilder(0xA1).build().toBytes(), Asn1Node.newBuilder(0xA2).build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertEquals("BF2102A000", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF2115" + "A000" + "A100" + "040D4131423243332D583459355A36" // hashCc + "A200"); } @Test public void testPrepareDownload_Error() { int channel = mockLogicalChannelResponses("BF2105A1030201039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.prepareDownload( IccUtils.hexStringToBytes("4131423243332D583459355A36"), // hashCc Asn1Node.newBuilder(0xA0).build().toBytes(), Asn1Node.newBuilder(0xA1).build().toBytes(), Asn1Node.newBuilder(0xA2).build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF2115" + "A000" + "A100" + "040D4131423243332D583459355A36" // hashCc + "A200"); } @Test public void testLoadBoundProfilePackage() { int channel = mockLogicalChannelResponses( // For boundProfilePackage head + initialiseSecureChannelRequest // (ES8+.InitialiseSecureChannel) "9000", // For firstSequenceOf87 (ES8+.ConfigureISDP) "9000", // For head of sequenceOf88 (ES8+.StoreMetadata) "9000", // For body (element 1) of sequenceOf88 (ES8+.StoreMetadata) "9000", "9000", // For head of sequenceOf86 (ES8+.LoadProfileElements) "9000", // For body (element 1) of sequenceOf86 (ES8+.LoadProfileElements) "9000", // Profile installation result (element 2 of sequenceOf86) "BF37009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.loadBoundProfilePackage( Asn1Node.newBuilder(0xBF36) .addChild(Asn1Node.newBuilder(0xBF23)) .addChild(Asn1Node.newBuilder(0xA0) .addChildAsBytes(0x87, new byte[] {1, 2, 3})) .addChild(Asn1Node.newBuilder(0xA1) .addChildAsBytes(0x88, new byte[] {4, 5, 6})) .addChild(Asn1Node.newBuilder(0xA2)) .addChild(Asn1Node.newBuilder(0xA3) .addChildAsBytes(0x86, new byte[] {7, 8, 9}) .addChildAsBytes(0x86, new byte[] {0xA, 0xB, 0xC})) .build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertEquals("BF3700", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF361FBF2300"); // ES8+.InitialiseSecureChannel verifyStoreData(channel, "A0058703010203"); // ES8+.ConfigureISDP verifyStoreData(channel, "A105"); // ES8+.StoreMetadata verifyStoreData(channel, "8803040506"); // ES8+.StoreMetadata verifyStoreData(channel, "A200"); verifyStoreData(channel, "A30A"); // ES8+.LoadProfileElements verifyStoreData(channel, "8603070809"); // ES8+.LoadProfileElements verifyStoreData(channel, "86030A0B0C"); // ES8+.LoadProfileElements } @Test public void testLoadBoundProfilePackage_Error() { int channel = mockLogicalChannelResponses( // For boundProfilePackage head + initialiseSecureChannelRequest // (ES8+.InitialiseSecureChannel) "9000", // For firstSequenceOf87 (ES8+.ConfigureISDP) "9000", // For head of sequenceOf88 (ES8+.StoreMetadata) "9000", // For body (element 1) of sequenceOf88 (ES8+.StoreMetadata) "9000", "9000", // For head of sequenceOf86 (ES8+.LoadProfileElements) "9000", // For body (element 1) of sequenceOf86 (ES8+.LoadProfileElements) "9000", // Profile installation result (element 2 of sequenceOf86) "BF370ABF2707A205A1038101039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.loadBoundProfilePackage( Asn1Node.newBuilder(0xBF36) .addChild(Asn1Node.newBuilder(0xBF23)) .addChild(Asn1Node.newBuilder(0xA0) .addChildAsBytes(0x87, new byte[] {1, 2, 3})) .addChild(Asn1Node.newBuilder(0xA1) .addChildAsBytes(0x88, new byte[] {4, 5, 6})) .addChild(Asn1Node.newBuilder(0xA2)) .addChild(Asn1Node.newBuilder(0xA3) .addChildAsBytes(0x86, new byte[] {7, 8, 9}) .addChildAsBytes(0x86, new byte[] {0xA, 0xB, 0xC})) .build().toBytes(), resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF361FBF2300"); // ES8+.InitialiseSecureChannel verifyStoreData(channel, "A0058703010203"); // ES8+.ConfigureISDP verifyStoreData(channel, "A105"); // ES8+.StoreMetadata verifyStoreData(channel, "8803040506"); // ES8+.StoreMetadata verifyStoreData(channel, "A200"); verifyStoreData(channel, "A30A"); // ES8+.LoadProfileElements verifyStoreData(channel, "8603070809"); // ES8+.LoadProfileElements verifyStoreData(channel, "86030A0B0C"); // ES8+.LoadProfileElements } @Test public void testCancelSession() { int channel = mockLogicalChannelResponses("BF41009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.cancelSession(IccUtils.hexStringToBytes("A1B2C3"), EuiccCardManager.CANCEL_REASON_POSTPONED, resultCaptor, mHandler); resultCaptor.await(); assertEquals("BF4100", IccUtils.bytesToHexString(resultCaptor.result)); verifyStoreData(channel, "BF41088003A1B2C3810101"); } @Test public void testCancelSession_Error() { int channel = mockLogicalChannelResponses("BF41038101039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.cancelSession(IccUtils.hexStringToBytes("A1B2C3"), EuiccCardManager.CANCEL_REASON_POSTPONED, resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF41088003A1B2C3810101"); } @Test public void testListNotifications() { int channel = mockLogicalChannelResponses("BF282BA029" + "BF2F118001010C08736D64702E636F6D81020410" // Notification #1 + "BF2F128001020C09736D6470322E636F6D81020420" // Notification #2 + "9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.listNotifications( EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE, resultCaptor, mHandler); resultCaptor.await(); assertArrayEquals( new EuiccNotification[] { new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE, null), new EuiccNotification(2, "smdp2.com", EuiccNotification.EVENT_DISABLE, null) }, resultCaptor.result); verifyStoreData(channel, "BF280481020430"); } @Test public void testListNotifications_Error() { int channel = mockLogicalChannelResponses("BF28038101039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.listNotifications( EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE, resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF280481020430"); } @Test public void testRetrieveNotificationList() { int channel = mockLogicalChannelResponses("BF2B2FA02D" // Notification #1 + "3014BF2F118001010C08736D64702E636F6D81020410" // Notification #2 + "3015BF2F128001020C09736D6470322E636F6D81020420" + "9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.retrieveNotificationList( EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE, resultCaptor, mHandler); resultCaptor.await(); assertArrayEquals( new EuiccNotification[] { new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE, IccUtils.hexStringToBytes( "3014BF2F118001010C08736D64702E636F6D81020410")), new EuiccNotification(2, "smdp2.com", EuiccNotification.EVENT_DISABLE, IccUtils.hexStringToBytes( "3015BF2F128001020C09736D6470322E636F6D81020420")) }, resultCaptor.result); verifyStoreData(channel, "BF2B06A00481020430"); } @Test public void testRetrieveNotificationList_Empty() { int channel = mockLogicalChannelResponses("BF2B038101019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.retrieveNotificationList( EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE, resultCaptor, mHandler); resultCaptor.await(); assertArrayEquals(new EuiccNotification[0], resultCaptor.result); verifyStoreData(channel, "BF2B06A00481020430"); } @Test public void testRetrieveNotificationList_Error() { int channel = mockLogicalChannelResponses("BF2B038101039000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.retrieveNotificationList( EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE, resultCaptor, mHandler); resultCaptor.await(); assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF2B06A00481020430"); } @Test public void testRetrieveNotification() { int channel = mockLogicalChannelResponses("BF2B18A016" + "3014BF2F118001010C08736D64702E636F6D81020410" // Notification + "9000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.retrieveNotification(5, resultCaptor, mHandler); resultCaptor.await(); assertEquals( new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE, IccUtils.hexStringToBytes("3014BF2F118001010C08736D64702E636F6D81020410")), resultCaptor.result); verifyStoreData(channel, "BF2B05A003800105"); } @Test public void testRetrieveNotification_Error() { int channel = mockLogicalChannelResponses("BF2B038101019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.retrieveNotification(5, resultCaptor, mHandler); resultCaptor.await(); assertEquals(1, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); verifyStoreData(channel, "BF2B05A003800105"); } @Test public void testRemoveNotificationFromList() { int channel = mockLogicalChannelResponses("BF30038001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); mEuiccCard.removeNotificationFromList(5, resultCaptor, mHandler); resultCaptor.await(); assertUnexpectedException(resultCaptor.exception); verifyStoreData(channel, "BF3003800105"); } private void verifyStoreData(int channel, String command) { verify(mMockCi, times(1)) .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91), eq(0), eq(command.length() / 2), eq(command), any()); } private int mockLogicalChannelResponses(Object... responses) { int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "E00582030200009000"); LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, responses); LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel); return channel; } }