1/*
2 * Copyright (C) 2016 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 */
16package com.android.internal.telephony.uicc;
17
18import android.os.Handler;
19import android.os.HandlerThread;
20import android.os.Message;
21import android.test.suitebuilder.annotation.SmallTest;
22
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Test;
26
27import com.android.internal.telephony.TelephonyTest;
28import com.android.internal.telephony.cat.CatService;
29import org.mockito.ArgumentCaptor;
30import org.mockito.Mock;
31import static org.mockito.Mockito.*;
32
33import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertFalse;
35import static org.junit.Assert.assertNull;
36import static org.junit.Assert.assertTrue;
37import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
38
39public class UiccCardTest extends TelephonyTest {
40    private UiccCard mUicccard;
41
42    public UiccCardTest() {
43        super();
44    }
45
46    private IccIoResult mIccIoResult;
47
48    private UiccCardHandlerThread mTestHandlerThread;
49    private Handler mHandler;
50    private static final int UICCCARD_UPDATE_CARD_STATE_EVENT = 1;
51    private static final int UICCCARD_UPDATE_CARD_APPLICATION_EVENT = 2;
52    private static final int UICCCARD_CARRIER_PRIVILEDGE_LOADED_EVENT = 3;
53    private static final int UICCCARD_ABSENT = 4;
54
55    @Mock
56    private CatService mCAT;
57    @Mock
58    private IccCardStatus mIccCardStatus;
59    @Mock
60    private Handler mMockedHandler;
61
62
63    private class UiccCardHandlerThread extends HandlerThread {
64
65        private UiccCardHandlerThread(String name) {
66            super(name);
67        }
68
69        @Override
70        public void onLooperPrepared() {
71            mUicccard = new UiccCard(mContextFixture.getTestDouble(),
72                                     mSimulatedCommands, mIccCardStatus);
73            /* create a custom handler for the Handler Thread */
74            mHandler = new Handler(mTestHandlerThread.getLooper()) {
75                @Override
76                public void handleMessage(Message msg) {
77                    switch (msg.what) {
78                        case UICCCARD_UPDATE_CARD_STATE_EVENT:
79                            /* Upon handling this event, new CarrierPrivilegeRule
80                            will be created with the looper of HandlerThread */
81                            logd("Update UICC Card State");
82                            mUicccard.update(mContextFixture.getTestDouble(),
83                                    mSimulatedCommands, mIccCardStatus);
84                            setReady(true);
85                            break;
86                        case UICCCARD_UPDATE_CARD_APPLICATION_EVENT:
87                            logd("Update UICC Card Applications");
88                            mUicccard.update(mContextFixture.getTestDouble(),
89                                    mSimulatedCommands, mIccCardStatus);
90                            setReady(true);
91                            break;
92                        default:
93                            logd("Unknown Event " + msg.what);
94                    }
95                }
96            };
97
98            setReady(true);
99            logd("create UiccCard");
100        }
101    }
102
103    private IccCardApplicationStatus composeUiccApplicationStatus(
104            IccCardApplicationStatus.AppType appType,
105            IccCardApplicationStatus.AppState appState, String aid) {
106        IccCardApplicationStatus mIccCardAppStatus = new IccCardApplicationStatus();
107        mIccCardAppStatus.aid = aid;
108        mIccCardAppStatus.app_type = appType;
109        mIccCardAppStatus.app_state = appState;
110        mIccCardAppStatus.pin1 = mIccCardAppStatus.pin2 =
111                IccCardStatus.PinState.PINSTATE_ENABLED_VERIFIED;
112        return mIccCardAppStatus;
113    }
114
115    @Before
116    public void setUp() throws Exception {
117
118        super.setUp(getClass().getSimpleName());
119        /* initially there are no application available */
120        mIccCardStatus.mApplications = new IccCardApplicationStatus[]{};
121        mIccCardStatus.mCdmaSubscriptionAppIndex =
122                mIccCardStatus.mImsSubscriptionAppIndex =
123                        mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1;
124
125        mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40"));
126        mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult);
127        /* starting the Handler Thread */
128        mTestHandlerThread = new UiccCardHandlerThread(TAG);
129        mTestHandlerThread.start();
130
131        waitUntilReady();
132        replaceInstance(UiccCard.class, "mCatService", mUicccard, mCAT);
133    }
134
135    @After
136    public void tearDown() throws Exception {
137        mTestHandlerThread.quit();
138        super.tearDown();
139    }
140
141    @Test
142    @SmallTest
143    public void tesUiccCartdInfoSanity() {
144        /* before update sanity test */
145        assertEquals(0, mUicccard.getNumApplications());
146        assertNull(mUicccard.getCardState());
147        assertNull(mUicccard.getUniversalPinState());
148        assertNull(mUicccard.getOperatorBrandOverride());
149        /* CarrierPrivilegeRule equals null, return true */
150        assertTrue(mUicccard.areCarrierPriviligeRulesLoaded());
151        for (IccCardApplicationStatus.AppType mAppType :
152                IccCardApplicationStatus.AppType.values()) {
153            assertFalse(mUicccard.isApplicationOnIcc(mAppType));
154        }
155    }
156
157    @Test @SmallTest
158    public void testUpdateUiccCardApplication() {
159        /* update app status and index */
160        IccCardApplicationStatus cdmaApp = composeUiccApplicationStatus(
161                IccCardApplicationStatus.AppType.APPTYPE_CSIM,
162                IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN, "0xA0");
163        IccCardApplicationStatus imsApp = composeUiccApplicationStatus(
164                IccCardApplicationStatus.AppType.APPTYPE_ISIM,
165                IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN, "0xA1");
166        IccCardApplicationStatus umtsApp = composeUiccApplicationStatus(
167                IccCardApplicationStatus.AppType.APPTYPE_USIM,
168                IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN, "0xA2");
169        mIccCardStatus.mApplications = new IccCardApplicationStatus[]{cdmaApp, imsApp, umtsApp};
170        mIccCardStatus.mCdmaSubscriptionAppIndex = 0;
171        mIccCardStatus.mImsSubscriptionAppIndex = 1;
172        mIccCardStatus.mGsmUmtsSubscriptionAppIndex = 2;
173        Message mCardUpdate = mHandler.obtainMessage(UICCCARD_UPDATE_CARD_APPLICATION_EVENT);
174        setReady(false);
175        mCardUpdate.sendToTarget();
176
177        waitUntilReady();
178
179        assertEquals(3, mUicccard.getNumApplications());
180        assertTrue(mUicccard.isApplicationOnIcc(IccCardApplicationStatus.AppType.APPTYPE_CSIM));
181        assertTrue(mUicccard.isApplicationOnIcc(IccCardApplicationStatus.AppType.APPTYPE_ISIM));
182        assertTrue(mUicccard.isApplicationOnIcc(IccCardApplicationStatus.AppType.APPTYPE_USIM));
183    }
184
185    @Test @SmallTest
186    public void testUpdateUiccCardState() {
187        int mChannelId = 1;
188        /* set card as present */
189        mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
190        /* Mock open Channel ID 1 */
191        mSimulatedCommands.setOpenChannelId(mChannelId);
192        Message mCardUpdate = mHandler.obtainMessage(UICCCARD_UPDATE_CARD_STATE_EVENT);
193        setReady(false);
194        mCardUpdate.sendToTarget();
195        /* try to create a new CarrierPrivilege, loading state -> loaded state */
196        /* wait till the async result and message delay */
197        waitUntilReady();
198
199        assertEquals(IccCardStatus.CardState.CARDSTATE_PRESENT, mUicccard.getCardState());
200
201        waitForMs(50);
202
203        assertTrue(mUicccard.areCarrierPriviligeRulesLoaded());
204        verify(mSimulatedCommandsVerifier, times(1)).iccOpenLogicalChannel(isA(String.class),
205                anyInt(), isA(Message.class));
206        verify(mSimulatedCommandsVerifier, times(1)).iccTransmitApduLogicalChannel(
207                eq(mChannelId), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString(),
208                isA(Message.class)
209        );
210    }
211
212    @Test @SmallTest
213    public void testUpdateUiccCardPinState() {
214        mIccCardStatus.mUniversalPinState = IccCardStatus.PinState.PINSTATE_ENABLED_VERIFIED;
215        mUicccard.update(mContextFixture.getTestDouble(), mSimulatedCommands, mIccCardStatus);
216        assertEquals(IccCardStatus.PinState.PINSTATE_ENABLED_VERIFIED,
217                mUicccard.getUniversalPinState());
218    }
219
220    @Test @SmallTest
221    public void testCarrierPriviledgeLoadedListener() {
222        mUicccard.registerForCarrierPrivilegeRulesLoaded(mMockedHandler,
223                UICCCARD_CARRIER_PRIVILEDGE_LOADED_EVENT, null);
224        ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
225        ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
226        testUpdateUiccCardState();
227        verify(mMockedHandler, atLeast(1)).sendMessageDelayed(mCaptorMessage.capture(),
228                mCaptorLong.capture());
229        assertEquals(UICCCARD_CARRIER_PRIVILEDGE_LOADED_EVENT, mCaptorMessage.getValue().what);
230    }
231
232    @Test @SmallTest
233    public void testCardAbsentListener() {
234        mUicccard.registerForAbsent(mMockedHandler, UICCCARD_ABSENT, null);
235        /* assume hotswap capable, avoid bootup on card removal */
236        mContextFixture.putBooleanResource(com.android.internal.R.bool.config_hotswapCapable, true);
237        mSimulatedCommands.setRadioPower(true, null);
238
239        /* Mock Card State transition from card_present to card_absent */
240        logd("UICC Card Present update");
241        mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
242        Message mCardUpdate = mHandler.obtainMessage(UICCCARD_UPDATE_CARD_STATE_EVENT);
243        mCardUpdate.sendToTarget();
244        waitForMs(50);
245
246        logd("UICC Card absent update");
247        mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT;
248        mUicccard.update(mContextFixture.getTestDouble(), mSimulatedCommands, mIccCardStatus);
249        waitForMs(50);
250
251        ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
252        ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
253        verify(mMockedHandler, atLeast(1)).sendMessageDelayed(mCaptorMessage.capture(),
254                                                             mCaptorLong.capture());
255        assertEquals(UICCCARD_ABSENT, mCaptorMessage.getValue().what);
256    }
257}
258