EuiccCardTest.java revision d828468595f5483da81732d7e321c8204b0fa2b7
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony.uicc.euicc;
18
19import static org.junit.Assert.assertArrayEquals;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertTrue;
23import static org.junit.Assert.fail;
24import static org.mockito.ArgumentMatchers.any;
25import static org.mockito.ArgumentMatchers.eq;
26import static org.mockito.Mockito.times;
27import static org.mockito.Mockito.verify;
28
29import android.os.Handler;
30import android.os.HandlerThread;
31import android.os.Message;
32import android.service.carrier.CarrierIdentifier;
33import android.service.euicc.EuiccProfileInfo;
34import android.telephony.UiccAccessRule;
35import android.telephony.euicc.EuiccCardManager;
36import android.telephony.euicc.EuiccNotification;
37import android.telephony.euicc.EuiccRulesAuthTable;
38import android.util.ExceptionUtils;
39import android.util.Log;
40
41import com.android.internal.telephony.CommandsInterface;
42import com.android.internal.telephony.TelephonyTest;
43import com.android.internal.telephony.uicc.IccCardApplicationStatus;
44import com.android.internal.telephony.uicc.IccCardStatus;
45import com.android.internal.telephony.uicc.IccUtils;
46import com.android.internal.telephony.uicc.asn1.Asn1Node;
47import com.android.internal.telephony.uicc.euicc.apdu.LogicalChannelMocker;
48import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
49
50import org.junit.After;
51import org.junit.Before;
52import org.junit.Test;
53import org.mockito.Mock;
54
55import java.util.concurrent.CountDownLatch;
56import java.util.concurrent.TimeUnit;
57
58public class EuiccCardTest extends TelephonyTest {
59    private static final long WAIT_TIMEOUT_MLLIS = 5000;
60
61    private static class ResultCaptor<T> extends AsyncResultCallback<T> {
62        public T result;
63        public Throwable exception;
64
65        private CountDownLatch mLatch;
66
67        private ResultCaptor() {
68            mLatch = new CountDownLatch(1);
69        }
70
71        public void await() {
72            try {
73                mLatch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS);
74            } catch (InterruptedException e) {
75                fail("Execution is interrupted: " + e);
76            }
77        }
78
79        @Override
80        public void onResult(T r) {
81            result = r;
82            mLatch.countDown();
83        }
84
85        @Override
86        public void onException(Throwable e) {
87            exception = e;
88            mLatch.countDown();
89        }
90    }
91
92    private class UiccCardHandlerThread extends HandlerThread {
93        private UiccCardHandlerThread(String name) {
94            super(name);
95        }
96
97        @Override
98        public void onLooperPrepared() {
99            mEuiccCard =
100                    new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus,
101                            0 /* phoneId */) {
102                        @Override
103                        protected byte[] getDeviceId() {
104                            return IccUtils.bcdToBytes("987654321012345");
105                        }
106
107                        @Override
108                        protected void loadEidAndNotifyRegistrants() {}
109                    };
110            mHandler = new Handler(mTestHandlerThread.getLooper());
111            setReady(true);
112        }
113    }
114
115    @Mock
116    private CommandsInterface mMockCi;
117    @Mock
118    private IccCardStatus mMockIccCardStatus;
119
120    private UiccCardHandlerThread mTestHandlerThread;
121    private Handler mHandler;
122
123    private EuiccCard mEuiccCard;
124
125    @Before
126    public void setUp() throws Exception {
127        super.setUp(getClass().getSimpleName());
128
129        mMockIccCardStatus.mApplications = new IccCardApplicationStatus[]{};
130        mMockIccCardStatus.mCdmaSubscriptionAppIndex =
131                mMockIccCardStatus.mImsSubscriptionAppIndex =
132                        mMockIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1;
133        mMockIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
134
135        mTestHandlerThread = new UiccCardHandlerThread(getClass().getSimpleName());
136        mTestHandlerThread.start();
137
138        waitUntilReady();
139    }
140
141    @After
142    public void tearDown() throws Exception {
143        mTestHandlerThread.quit();
144        super.tearDown();
145    }
146
147    private void assertUnexpectedException(Throwable e) {
148        if (e != null) {
149            fail("Unexpected exception: " + ExceptionUtils.getCompleteMessage(e) + "\n-----\n"
150                    + Log.getStackTraceString(e.getCause()) + "-----");
151        }
152    }
153
154    @Test
155    public void testLoadEidAndNotifyRegistrants() throws InterruptedException {
156        int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000");
157
158        {
159            final CountDownLatch latch = new CountDownLatch(1);
160            mHandler.post(() -> {
161                mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi,
162                        mMockIccCardStatus, 0 /* phoneId */);
163                latch.countDown();
164            });
165            assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS));
166        }
167
168        final int eventEidReady = 0;
169        final CountDownLatch latch = new CountDownLatch(1);
170        Handler handler = new Handler(mTestHandlerThread.getLooper()) {
171            @Override
172            public void handleMessage(Message msg) {
173                if (msg.what == eventEidReady) {
174                    assertEquals("1A2B3C4D", mEuiccCard.getEid());
175                    latch.countDown();
176                }
177            }
178        };
179
180        mEuiccCard.registerForEidReady(handler, eventEidReady, null /* obj */);
181        assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS));
182
183        verifyStoreData(channel, "BF3E035C015A");
184    }
185
186    @Test
187    public void testGetAllProfiles() {
188        int channel = mockLogicalChannelResponses(
189                "BF2D14A012E3105A0A896700000000004523019F7001019000");
190
191        ResultCaptor<EuiccProfileInfo[]> resultCaptor = new ResultCaptor<>();
192        mEuiccCard.getAllProfiles(resultCaptor, mHandler);
193        resultCaptor.await();
194
195        assertUnexpectedException(resultCaptor.exception);
196        EuiccProfileInfo[] profiles = resultCaptor.result;
197        assertEquals(1, profiles.length);
198        assertEquals("98760000000000543210", profiles[0].getIccid());
199        assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState());
200        verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76");
201    }
202
203    @Test
204    public void testFSuffix() {
205        // iccID is 987600000000005432FF.
206        int channel = mockLogicalChannelResponses(
207                "BF2D14A012E3105A0A896700000000004523FF9F7001019000");
208
209        ResultCaptor<EuiccProfileInfo[]> resultCaptor = new ResultCaptor<>();
210        mEuiccCard.getAllProfiles(resultCaptor, mHandler);
211        resultCaptor.await();
212
213        EuiccProfileInfo[] profiles = resultCaptor.result;
214        assertEquals(1, profiles.length);
215        assertEquals("987600000000005432", profiles[0].getIccid());
216        assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profiles[0].getState());
217        verifyStoreData(channel, "BF2D0D5C0B5A909192B79F709599BF76");
218    }
219
220    @Test
221    public void testGetProfile() {
222        int channel = mockLogicalChannelResponses("BF2D8184A08181E37F"
223                + "5A0A89670000000000452301" // ICCID
224                + "90046E69636B" // Nickname
225                + "9103746D6F" // Service provider name
226                + "92027031" // Profile name
227                + "B70F800312F34581030102038203040506" // Operator id
228                + "9F700101" // Profile state
229                + "950101" // Profile class
230                + "990206C0" // Policy rules
231                + "BF7645E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4"
232                + "CA1D636F6D2E676F6F676C652E616E64726F69642E617070732E6D79617070"
233                + "E30ADB080000000000000001" // Carrier privilege rules
234                + "9000");
235
236        ResultCaptor<EuiccProfileInfo> resultCaptor = new ResultCaptor<>();
237        mEuiccCard.getProfile("98760000000000543210", resultCaptor, mHandler);
238        resultCaptor.await();
239
240        EuiccProfileInfo profile = resultCaptor.result;
241        assertEquals("98760000000000543210", profile.getIccid());
242        assertEquals("nick", profile.getNickname());
243        assertEquals("tmo", profile.getServiceProviderName());
244        assertEquals("p1", profile.getProfileName());
245        assertEquals("213", profile.getCarrierIdentifier().getMcc());
246        assertEquals("54", profile.getCarrierIdentifier().getMnc());
247        assertEquals("010203", profile.getCarrierIdentifier().getGid1());
248        assertEquals("040506", profile.getCarrierIdentifier().getGid2());
249        assertEquals(EuiccProfileInfo.PROFILE_STATE_ENABLED, profile.getState());
250        assertEquals(EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, profile.getProfileClass());
251        assertEquals(
252                EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE
253                        | EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE,
254                profile.getPolicyRules());
255        assertArrayEquals(
256                new UiccAccessRule[] {
257                        new UiccAccessRule(
258                                IccUtils.hexStringToBytes(
259                                        "ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4"),
260                                "com.google.android.apps.myapp", 1)
261                },
262                profile.getUiccAccessRules().toArray());
263        verifyStoreData(channel, "BF2D195A0A896700000000004523015C0B5A909192B79F709599BF76");
264    }
265
266    @Test
267    public void testDisableProfile() {
268        int channel = mockLogicalChannelResponses("BF32038001009000");
269
270        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
271        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
272        resultCaptor.await();
273
274        assertUnexpectedException(resultCaptor.exception);
275        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
276    }
277
278    @Test
279    public void testDisableProfile_SimRefresh() {
280        int channel = mockLogicalChannelResponses("6106", "6f00");
281
282        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
283        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
284        resultCaptor.await();
285
286        assertUnexpectedException(resultCaptor.exception);
287        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
288    }
289
290    @Test
291    public void testDisableProfile_Error() {
292        int channel = mockLogicalChannelResponses("BF32038001039000");
293
294        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
295        mEuiccCard.disableProfile("98760000000000543210", true, resultCaptor, mHandler);
296        resultCaptor.await();
297
298        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
299        verifyStoreData(channel, "BF3211A00C5A0A896700000000004523018101FF");
300    }
301
302    @Test
303    public void testSwitchToProfile() {
304        int channel = mockLogicalChannelResponses("BF31038001009000");
305
306        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
307        mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler);
308        resultCaptor.await();
309
310        assertUnexpectedException(resultCaptor.exception);
311        verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF");
312    }
313
314    @Test
315    public void testSwitchToProfile_SimRefresh() {
316        int channel = mockLogicalChannelResponses("6106", "6f00");
317
318        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
319        mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler);
320        resultCaptor.await();
321
322        assertUnexpectedException(resultCaptor.exception);
323        verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF");
324    }
325
326    @Test
327    public void testSwitchToProfile_Error() {
328        int channel = mockLogicalChannelResponses("BF31038001039000");
329
330        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
331        mEuiccCard.switchToProfile("98760000000000543210", true, resultCaptor, mHandler);
332        resultCaptor.await();
333
334        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
335        verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF");
336    }
337
338    @Test
339    public void testGetEid() {
340        int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000");
341
342        ResultCaptor<String> resultCaptor = new ResultCaptor<>();
343        mEuiccCard.getEid(resultCaptor, mHandler);
344        resultCaptor.await();
345
346        assertEquals("1A2B3C4D", resultCaptor.result);
347        verifyStoreData(channel, "BF3E035C015A");
348    }
349
350    @Test
351    public void testSetNickname() {
352        int channel = mockLogicalChannelResponses("BF29038001009000");
353
354        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
355        mEuiccCard.setNickname("98760000000000543210", "new nickname", resultCaptor, mHandler);
356        resultCaptor.await();
357
358        assertUnexpectedException(resultCaptor.exception);
359        verifyStoreData(channel, "BF291A5A0A89670000000000452301900C6E6577206E69636B6E616D65");
360    }
361
362    @Test
363    public void testDeleteProfile() {
364        int channel = mockLogicalChannelResponses("BF33038001009000");
365
366        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
367        mEuiccCard.deleteProfile("98760000000000543210", resultCaptor, mHandler);
368        resultCaptor.await();
369
370        assertUnexpectedException(resultCaptor.exception);
371        verifyStoreData(channel, "BF330C5A0A89670000000000452301");
372    }
373
374    @Test
375    public void testDeleteProfile_Error() {
376        int channel = mockLogicalChannelResponses("BF33038001039000");
377
378        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
379        mEuiccCard.deleteProfile("98760000000000543210", resultCaptor, mHandler);
380        resultCaptor.await();
381
382        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
383        verifyStoreData(channel, "BF330C5A0A89670000000000452301");
384    }
385
386    @Test
387    public void testGetDefaultSmdpAddress() {
388        int channel = mockLogicalChannelResponses(
389                "BF3C148008534D44502E434F4D8108736D64732E636F6D9000");
390
391        ResultCaptor<String> resultCaptor = new ResultCaptor<>();
392        mEuiccCard.getDefaultSmdpAddress(resultCaptor, mHandler);
393        resultCaptor.await();
394
395        assertEquals("SMDP.COM", resultCaptor.result);
396        verifyStoreData(channel, "BF3C00");
397    }
398
399    @Test
400    public void testGetSmdsAddress() {
401        int channel = mockLogicalChannelResponses(
402                "BF3C148008534D44502E434F4D8108736D64732E636F6D9000");
403
404        ResultCaptor<String> resultCaptor = new ResultCaptor<>();
405        mEuiccCard.getSmdsAddress(resultCaptor, mHandler);
406        resultCaptor.await();
407
408        assertEquals("smds.com", resultCaptor.result);
409        verifyStoreData(channel, "BF3C00");
410    }
411
412    @Test
413    public void testSetDefaultSmdpAddress() {
414        int channel = mockLogicalChannelResponses("BF3F038001009000");
415
416        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
417        mEuiccCard.setDefaultSmdpAddress("smdp.gsma.com", resultCaptor, mHandler);
418        resultCaptor.await();
419
420        assertUnexpectedException(resultCaptor.exception);
421        verifyStoreData(channel, "BF3F0F800D736D64702E67736D612E636F6D");
422    }
423
424    @Test
425    public void testGetRulesAuthTable() {
426        int channel = mockLogicalChannelResponses("BF4347"
427                + "A021" // Rule #1
428                + "800206C0" // Policy rules: DO_NOT_DELETE | DO_NOT_DISABLE
429                + "A118" // Operator IDs
430                + "B70A800312F3458103010203" // ID #1: 213, 54, [1,2,3], null
431                + "B70A800312F3458203040506" // ID #2: 213, 54, null, [4,5,6]
432                + "820108" // Flag (no user consent)
433                + "A022" // Rule #2
434                + "80020780" // Policy rules: DO_NOT_DISABLE
435                + "A118" // Operator IDs
436                + "B70A800312E3458103010203" // ID #1: 213, 54E, [1,2,3], null
437                + "B70A8003EEEE458203040506" // ID #2: EEE, 54E, null, [4,5,6]
438                + "82020780" // Flag (user consent)
439                + "9000");
440
441        ResultCaptor<EuiccRulesAuthTable> resultCaptor = new ResultCaptor<>();
442        mEuiccCard.getRulesAuthTable(resultCaptor, mHandler);
443        resultCaptor.await();
444
445        EuiccRulesAuthTable rat = resultCaptor.result;
446        assertEquals(-1,
447                rat.findIndex(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE,
448                        new CarrierIdentifier(new byte[] {0x12, (byte) 0xF3, 0x45}, null, null)));
449        assertEquals(1,
450                rat.findIndex(EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE,
451                        new CarrierIdentifier(new byte[] {0x23, 0x67, 0x45}, null, "040506")));
452        assertFalse(rat.hasPolicyRuleFlag(0,
453                EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED));
454        assertTrue(rat.hasPolicyRuleFlag(1,
455                EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED));
456        verifyStoreData(channel, "BF4300");
457    }
458
459    @Test
460    public void testResetMemory() {
461        int channel = mockLogicalChannelResponses("BF34038001009000");
462
463        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
464        mEuiccCard.resetMemory(EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
465                resultCaptor, mHandler);
466        resultCaptor.await();
467
468        assertUnexpectedException(resultCaptor.exception);
469        verifyStoreData(channel, "BF340482020640");
470    }
471
472    @Test
473    public void testResetMemory_SimRefresh() {
474        int channel = mockLogicalChannelResponses("6106", "6f00");
475
476        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
477        mEuiccCard.resetMemory(EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
478                resultCaptor, mHandler);
479        resultCaptor.await();
480
481        assertUnexpectedException(resultCaptor.exception);
482        verifyStoreData(channel, "BF340482020640");
483    }
484
485    @Test
486    public void testGetEuiccChallenge() {
487        int channel = mockLogicalChannelResponses("BF2E0580030102039000");
488
489        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
490        mEuiccCard.getEuiccChallenge(resultCaptor, mHandler);
491        resultCaptor.await();
492
493        assertArrayEquals(new byte[] {1, 2, 3}, resultCaptor.result);
494        verifyStoreData(channel, "BF2E00");
495    }
496
497    @Test
498    public void testGetEuiccInfo1() {
499        int channel = mockLogicalChannelResponses("BF20030102039000");
500
501        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
502        mEuiccCard.getEuiccInfo1(resultCaptor, mHandler);
503        resultCaptor.await();
504
505        assertEquals("BF2003010203", IccUtils.bytesToHexString(resultCaptor.result));
506        verifyStoreData(channel, "BF2000");
507    }
508
509    @Test
510    public void testGetEuiccInfo2() {
511        int channel = mockLogicalChannelResponses("BF22030102039000");
512
513        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
514        mEuiccCard.getEuiccInfo2(resultCaptor, mHandler);
515        resultCaptor.await();
516
517        assertEquals("BF2203010203", IccUtils.bytesToHexString(resultCaptor.result));
518        verifyStoreData(channel, "BF2200");
519    }
520
521    @Test
522    public void testAuthenticateServer() {
523        int channel = mockLogicalChannelResponses("BF3802A0009000");
524
525        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
526        mEuiccCard.authenticateServer("A1B2C3-X4Y5Z6", // Matching id
527                Asn1Node.newBuilder(0xA0).build().toBytes(),
528                Asn1Node.newBuilder(0xA1).build().toBytes(),
529                Asn1Node.newBuilder(0xA2).build().toBytes(),
530                Asn1Node.newBuilder(0xA3).build().toBytes(), resultCaptor, mHandler);
531        resultCaptor.await();
532
533        assertUnexpectedException(resultCaptor.exception);
534        assertEquals("BF3802A000", IccUtils.bytesToHexString(resultCaptor.result));
535        verifyStoreData(channel,
536                "BF382D" + "A000" + "A100" + "A200" + "A300" + "A023"
537                        + "800D4131423243332D583459355A36" // Matching id
538                        + "A112800489674523" // TAC
539                        + "A100" // Device capabilities
540                        + "82088967452301214305"); // IMEI
541    }
542
543    @Test
544    public void testAuthenticateServer_Error() {
545        int channel = mockLogicalChannelResponses("BF38038101039000");
546
547        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
548        mEuiccCard.authenticateServer("A1B2C3-X4Y5Z6", // Matching id
549                Asn1Node.newBuilder(0xA0).build().toBytes(),
550                Asn1Node.newBuilder(0xA1).build().toBytes(),
551                Asn1Node.newBuilder(0xA2).build().toBytes(),
552                Asn1Node.newBuilder(0xA3).build().toBytes(), resultCaptor, mHandler);
553        resultCaptor.await();
554
555        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
556        verifyStoreData(channel,
557                "BF382D" + "A000" + "A100" + "A200" + "A300" + "A023"
558                        + "800D4131423243332D583459355A36" // Matching id
559                        + "A112800489674523" // TAC
560                        + "A100" // Device capabilities
561                        + "82088967452301214305"); // IMEI
562    }
563
564    @Test
565    public void testPrepareDownload() {
566        int channel = mockLogicalChannelResponses("BF2102A0009000");
567
568        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
569        mEuiccCard.prepareDownload(
570                IccUtils.hexStringToBytes("4131423243332D583459355A36"), // hashCc
571                Asn1Node.newBuilder(0xA0).build().toBytes(),
572                Asn1Node.newBuilder(0xA1).build().toBytes(),
573                Asn1Node.newBuilder(0xA2).build().toBytes(), resultCaptor, mHandler);
574        resultCaptor.await();
575
576        assertEquals("BF2102A000", IccUtils.bytesToHexString(resultCaptor.result));
577        verifyStoreData(channel,
578                "BF2115" + "A000" + "A100"
579                        + "040D4131423243332D583459355A36" // hashCc
580                        + "A200");
581    }
582
583    @Test
584    public void testPrepareDownload_Error() {
585        int channel = mockLogicalChannelResponses("BF2105A1030201039000");
586
587        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
588        mEuiccCard.prepareDownload(
589                IccUtils.hexStringToBytes("4131423243332D583459355A36"), // hashCc
590                Asn1Node.newBuilder(0xA0).build().toBytes(),
591                Asn1Node.newBuilder(0xA1).build().toBytes(),
592                Asn1Node.newBuilder(0xA2).build().toBytes(), resultCaptor, mHandler);
593        resultCaptor.await();
594
595        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
596        verifyStoreData(channel,
597                "BF2115" + "A000" + "A100"
598                        + "040D4131423243332D583459355A36" // hashCc
599                        + "A200");
600    }
601
602    @Test
603    public void testLoadBoundProfilePackage() {
604        int channel = mockLogicalChannelResponses(
605                // For boundProfilePackage head + initialiseSecureChannelRequest
606                // (ES8+.InitialiseSecureChannel)
607                "9000",
608                // For firstSequenceOf87 (ES8+.ConfigureISDP)
609                "9000",
610                // For head of sequenceOf88 (ES8+.StoreMetadata)
611                "9000",
612                // For body (element 1) of sequenceOf88 (ES8+.StoreMetadata)
613                "9000",
614                "9000",
615                // For head of sequenceOf86 (ES8+.LoadProfileElements)
616                "9000",
617                // For body (element 1) of sequenceOf86 (ES8+.LoadProfileElements)
618                "9000",
619                // Profile installation result (element 2 of sequenceOf86)
620                "BF37009000");
621
622        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
623        mEuiccCard.loadBoundProfilePackage(
624                Asn1Node.newBuilder(0xBF36)
625                        .addChild(Asn1Node.newBuilder(0xBF23))
626                        .addChild(Asn1Node.newBuilder(0xA0)
627                                .addChildAsBytes(0x87, new byte[] {1, 2, 3}))
628                        .addChild(Asn1Node.newBuilder(0xA1)
629                                .addChildAsBytes(0x88, new byte[] {4, 5, 6}))
630                        .addChild(Asn1Node.newBuilder(0xA2))
631                        .addChild(Asn1Node.newBuilder(0xA3)
632                                .addChildAsBytes(0x86, new byte[] {7, 8, 9})
633                                .addChildAsBytes(0x86, new byte[] {0xA, 0xB, 0xC}))
634                        .build().toBytes(),
635                resultCaptor, mHandler);
636        resultCaptor.await();
637
638        assertEquals("BF3700", IccUtils.bytesToHexString(resultCaptor.result));
639        verifyStoreData(channel, "BF361FBF2300"); // ES8+.InitialiseSecureChannel
640        verifyStoreData(channel, "A0058703010203"); // ES8+.ConfigureISDP
641        verifyStoreData(channel, "A105"); // ES8+.StoreMetadata
642        verifyStoreData(channel, "8803040506"); // ES8+.StoreMetadata
643        verifyStoreData(channel, "A200");
644        verifyStoreData(channel, "A30A"); // ES8+.LoadProfileElements
645        verifyStoreData(channel, "8603070809"); // ES8+.LoadProfileElements
646        verifyStoreData(channel, "86030A0B0C"); // ES8+.LoadProfileElements
647    }
648
649    @Test
650    public void testLoadBoundProfilePackage_Error() {
651        int channel = mockLogicalChannelResponses(
652                // For boundProfilePackage head + initialiseSecureChannelRequest
653                // (ES8+.InitialiseSecureChannel)
654                "9000",
655                // For firstSequenceOf87 (ES8+.ConfigureISDP)
656                "9000",
657                // For head of sequenceOf88 (ES8+.StoreMetadata)
658                "9000",
659                // For body (element 1) of sequenceOf88 (ES8+.StoreMetadata)
660                "9000",
661                "9000",
662                // For head of sequenceOf86 (ES8+.LoadProfileElements)
663                "9000",
664                // For body (element 1) of sequenceOf86 (ES8+.LoadProfileElements)
665                "9000",
666                // Profile installation result (element 2 of sequenceOf86)
667                "BF370ABF2707A205A1038101039000");
668
669        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
670        mEuiccCard.loadBoundProfilePackage(
671                Asn1Node.newBuilder(0xBF36)
672                        .addChild(Asn1Node.newBuilder(0xBF23))
673                        .addChild(Asn1Node.newBuilder(0xA0)
674                                .addChildAsBytes(0x87, new byte[] {1, 2, 3}))
675                        .addChild(Asn1Node.newBuilder(0xA1)
676                                .addChildAsBytes(0x88, new byte[] {4, 5, 6}))
677                        .addChild(Asn1Node.newBuilder(0xA2))
678                        .addChild(Asn1Node.newBuilder(0xA3)
679                                .addChildAsBytes(0x86, new byte[] {7, 8, 9})
680                                .addChildAsBytes(0x86, new byte[] {0xA, 0xB, 0xC}))
681                        .build().toBytes(),
682                resultCaptor, mHandler);
683        resultCaptor.await();
684
685        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
686        verifyStoreData(channel, "BF361FBF2300"); // ES8+.InitialiseSecureChannel
687        verifyStoreData(channel, "A0058703010203"); // ES8+.ConfigureISDP
688        verifyStoreData(channel, "A105"); // ES8+.StoreMetadata
689        verifyStoreData(channel, "8803040506"); // ES8+.StoreMetadata
690        verifyStoreData(channel, "A200");
691        verifyStoreData(channel, "A30A"); // ES8+.LoadProfileElements
692        verifyStoreData(channel, "8603070809"); // ES8+.LoadProfileElements
693        verifyStoreData(channel, "86030A0B0C"); // ES8+.LoadProfileElements
694    }
695
696    @Test
697    public void testCancelSession() {
698        int channel = mockLogicalChannelResponses("BF41009000");
699
700        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
701        mEuiccCard.cancelSession(IccUtils.hexStringToBytes("A1B2C3"),
702                EuiccCardManager.CANCEL_REASON_POSTPONED, resultCaptor, mHandler);
703        resultCaptor.await();
704
705        assertEquals("BF4100", IccUtils.bytesToHexString(resultCaptor.result));
706        verifyStoreData(channel, "BF41088003A1B2C3810101");
707    }
708
709    @Test
710    public void testCancelSession_Error() {
711        int channel = mockLogicalChannelResponses("BF41038101039000");
712
713        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
714        mEuiccCard.cancelSession(IccUtils.hexStringToBytes("A1B2C3"),
715                EuiccCardManager.CANCEL_REASON_POSTPONED, resultCaptor, mHandler);
716        resultCaptor.await();
717
718        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
719        verifyStoreData(channel, "BF41088003A1B2C3810101");
720    }
721
722    @Test
723    public void testListNotifications() {
724        int channel = mockLogicalChannelResponses("BF282BA029"
725                + "BF2F118001010C08736D64702E636F6D81020410" // Notification #1
726                + "BF2F128001020C09736D6470322E636F6D81020420" // Notification #2
727                + "9000");
728
729        ResultCaptor<EuiccNotification[]> resultCaptor = new ResultCaptor<>();
730        mEuiccCard.listNotifications(
731                EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE,
732                resultCaptor, mHandler);
733        resultCaptor.await();
734
735        assertArrayEquals(
736                new EuiccNotification[] {
737                        new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE, null),
738                        new EuiccNotification(2, "smdp2.com", EuiccNotification.EVENT_DISABLE, null)
739                },
740                resultCaptor.result);
741        verifyStoreData(channel, "BF280481020430");
742    }
743
744    @Test
745    public void testListNotifications_Error() {
746        int channel = mockLogicalChannelResponses("BF28038101039000");
747
748        ResultCaptor<EuiccNotification[]> resultCaptor = new ResultCaptor<>();
749        mEuiccCard.listNotifications(
750                EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE,
751                resultCaptor, mHandler);
752        resultCaptor.await();
753
754        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
755        verifyStoreData(channel, "BF280481020430");
756    }
757
758    @Test
759    public void testRetrieveNotificationList() {
760        int channel = mockLogicalChannelResponses("BF2B2FA02D"
761                // Notification #1
762                + "3014BF2F118001010C08736D64702E636F6D81020410"
763                // Notification #2
764                + "3015BF2F128001020C09736D6470322E636F6D81020420"
765                + "9000");
766
767        ResultCaptor<EuiccNotification[]> resultCaptor = new ResultCaptor<>();
768        mEuiccCard.retrieveNotificationList(
769                EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE,
770                resultCaptor, mHandler);
771        resultCaptor.await();
772
773        assertArrayEquals(
774                new EuiccNotification[] {
775                        new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE,
776                                IccUtils.hexStringToBytes(
777                                        "3014BF2F118001010C08736D64702E636F6D81020410")),
778                        new EuiccNotification(2, "smdp2.com", EuiccNotification.EVENT_DISABLE,
779                                IccUtils.hexStringToBytes(
780                                        "3015BF2F128001020C09736D6470322E636F6D81020420"))
781                },
782                resultCaptor.result);
783        verifyStoreData(channel, "BF2B06A00481020430");
784    }
785
786    @Test
787    public void testRetrieveNotificationList_Empty() {
788        int channel = mockLogicalChannelResponses("BF2B038101019000");
789
790        ResultCaptor<EuiccNotification[]> resultCaptor = new ResultCaptor<>();
791        mEuiccCard.retrieveNotificationList(
792                EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE,
793                resultCaptor, mHandler);
794        resultCaptor.await();
795
796        assertArrayEquals(new EuiccNotification[0], resultCaptor.result);
797        verifyStoreData(channel, "BF2B06A00481020430");
798    }
799
800    @Test
801    public void testRetrieveNotificationList_Error() {
802        int channel = mockLogicalChannelResponses("BF2B038101039000");
803
804        ResultCaptor<EuiccNotification[]> resultCaptor = new ResultCaptor<>();
805        mEuiccCard.retrieveNotificationList(
806                EuiccNotification.EVENT_DELETE | EuiccNotification.EVENT_DISABLE,
807                resultCaptor, mHandler);
808        resultCaptor.await();
809
810        assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
811        verifyStoreData(channel, "BF2B06A00481020430");
812    }
813
814    @Test
815    public void testRetrieveNotification() {
816        int channel = mockLogicalChannelResponses("BF2B18A016"
817                + "3014BF2F118001010C08736D64702E636F6D81020410" // Notification
818                + "9000");
819
820        ResultCaptor<EuiccNotification> resultCaptor = new ResultCaptor<>();
821        mEuiccCard.retrieveNotification(5, resultCaptor, mHandler);
822        resultCaptor.await();
823
824        assertEquals(
825                new EuiccNotification(1, "smdp.com", EuiccNotification.EVENT_DELETE,
826                        IccUtils.hexStringToBytes("3014BF2F118001010C08736D64702E636F6D81020410")),
827                resultCaptor.result);
828        verifyStoreData(channel, "BF2B05A003800105");
829    }
830
831    @Test
832    public void testRetrieveNotification_Error() {
833        int channel = mockLogicalChannelResponses("BF2B038101019000");
834
835        ResultCaptor<EuiccNotification> resultCaptor = new ResultCaptor<>();
836        mEuiccCard.retrieveNotification(5, resultCaptor, mHandler);
837        resultCaptor.await();
838
839        assertEquals(1, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode());
840        verifyStoreData(channel, "BF2B05A003800105");
841    }
842
843    @Test
844    public void testRemoveNotificationFromList() {
845        int channel = mockLogicalChannelResponses("BF30038001009000");
846
847        ResultCaptor<Void> resultCaptor = new ResultCaptor<>();
848        mEuiccCard.removeNotificationFromList(5, resultCaptor, mHandler);
849        resultCaptor.await();
850
851        assertUnexpectedException(resultCaptor.exception);
852        verifyStoreData(channel, "BF3003800105");
853    }
854
855    private void verifyStoreData(int channel, String command) {
856        verify(mMockCi, times(1))
857                .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91),
858                        eq(0), eq(command.length() / 2), eq(command), any());
859    }
860
861    private int mockLogicalChannelResponses(Object... responses) {
862        int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi,
863                "E00582030200009000");
864        LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, responses);
865        LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel);
866        return channel;
867    }
868}
869