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;
17
18import android.Manifest;
19import android.content.ContentProvider;
20import android.content.ContentValues;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.UserInfo;
24import android.net.Uri;
25import android.os.AsyncResult;
26import android.os.HandlerThread;
27import android.os.Message;
28import android.provider.Telephony;
29import android.telephony.CarrierConfigManager;
30import android.telephony.SubscriptionInfo;
31import android.telephony.SubscriptionManager;
32import android.test.mock.MockContentProvider;
33import android.test.mock.MockContentResolver;
34import android.test.suitebuilder.annotation.SmallTest;
35
36import com.android.internal.telephony.uicc.IccCardProxy;
37import com.android.internal.telephony.uicc.IccFileHandler;
38import com.android.internal.telephony.uicc.IccRecords;
39import com.android.internal.telephony.uicc.IccUtils;
40
41import org.junit.After;
42import org.junit.Assert;
43import org.junit.Before;
44import org.junit.Test;
45import org.mockito.ArgumentCaptor;
46import org.mockito.Mock;
47import org.mockito.invocation.InvocationOnMock;
48import org.mockito.stubbing.Answer;
49
50import java.util.Arrays;
51import java.util.HashMap;
52
53import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
54import static org.junit.Assert.assertEquals;
55import static org.mockito.Mockito.any;
56import static org.mockito.Mockito.anyBoolean;
57import static org.mockito.Mockito.anyInt;
58import static org.mockito.Mockito.anyString;
59import static org.mockito.Mockito.doAnswer;
60import static org.mockito.Mockito.doReturn;
61import static org.mockito.Mockito.eq;
62import static org.mockito.Mockito.times;
63import static org.mockito.Mockito.verify;
64
65public class SubscriptionInfoUpdaterTest extends TelephonyTest {
66
67    private static final int FAKE_SUB_ID = 1;
68    private static final String FAKE_PLMN = "123456";
69
70    private SubscriptionInfoUpdaterHandlerThread mSubscriptionInfoUpdaterHandlerThread;
71    private IccRecords mIccRecord;
72    @Mock
73    private UserInfo mUserInfo;
74    @Mock
75    private SubscriptionInfo mSubInfo;
76    @Mock
77    private ContentProvider mContentProvider;
78    @Mock
79    private HashMap<String, Object> mSubscriptionContent;
80    @Mock
81    private IccFileHandler mIccFileHandler;
82
83    /*Custom ContentProvider */
84    private class FakeSubscriptionContentProvider extends MockContentProvider {
85        @Override
86        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
87            for (String key : values.keySet()) {
88                mSubscriptionContent.put(key, values.get(key));
89            }
90            return 1;
91        }
92    }
93
94    private class SubscriptionInfoUpdaterHandlerThread extends HandlerThread {
95
96        private SubscriptionInfoUpdaterHandlerThread(String name) {
97            super(name);
98        }
99
100        @Override
101        public void onLooperPrepared() {
102            new SubscriptionInfoUpdater(mContext, new Phone[]{mPhone},
103                    new CommandsInterface[]{mSimulatedCommands});
104            setReady(true);
105        }
106    }
107
108    @Before
109    public void setUp() throws Exception {
110        super.setUp(this.getClass().getSimpleName());
111
112        replaceInstance(SubscriptionInfoUpdater.class, "mIccId", null,
113                new String[SubscriptionInfoUpdater.STATUS_SIM1_INSERTED]);
114        replaceInstance(SubscriptionInfoUpdater.class, "mInsertSimState", null,
115                new int[SubscriptionInfoUpdater.STATUS_SIM1_INSERTED]);
116        replaceInstance(SubscriptionInfoUpdater.class, "mContext", null, null);
117        replaceInstance(SubscriptionInfoUpdater.class, "PROJECT_SIM_NUM", null,
118                SubscriptionInfoUpdater.STATUS_SIM1_INSERTED);
119
120        doReturn(SubscriptionInfoUpdater.STATUS_SIM1_INSERTED)
121                .when(mTelephonyManager).getSimCount();
122        doReturn(SubscriptionInfoUpdater.STATUS_SIM1_INSERTED)
123                .when(mTelephonyManager).getPhoneCount();
124
125        doReturn(mUserInfo).when(mIActivityManager).getCurrentUser();
126        doReturn(new int[]{FAKE_SUB_ID}).when(mSubscriptionController).getSubId(0);
127        mContentProvider = new FakeSubscriptionContentProvider();
128        ((MockContentResolver) mContext.getContentResolver()).addProvider(
129                SubscriptionManager.CONTENT_URI.getAuthority(),
130                mContentProvider);
131        mIccRecord = mIccCardProxy.getIccRecords();
132
133        mSubscriptionInfoUpdaterHandlerThread = new SubscriptionInfoUpdaterHandlerThread(TAG);
134        mSubscriptionInfoUpdaterHandlerThread.start();
135        waitUntilReady();
136    }
137
138    @After
139    public void tearDown() throws Exception {
140        mSubscriptionInfoUpdaterHandlerThread.quitSafely();
141        super.tearDown();
142    }
143
144    @Test
145    @SmallTest
146    public void testSimAbsent() {
147        doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController)
148                .getSubInfoUsingSlotIdWithCheck(eq(0), anyBoolean(), anyString());
149        Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
150        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
151                IccCardConstants.INTENT_VALUE_ICC_ABSENT);
152        mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
153
154        mContext.sendBroadcast(mIntent);
155
156        waitForMs(100);
157        verify(mSubscriptionContent).put(eq(SubscriptionManager.SIM_SLOT_INDEX),
158                eq(SubscriptionManager.INVALID_SIM_SLOT_INDEX));
159
160        CarrierConfigManager mConfigManager = (CarrierConfigManager)
161                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
162        verify(mConfigManager).updateConfigForPhoneId(eq(0),
163                eq(IccCardConstants.INTENT_VALUE_ICC_ABSENT));
164        verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
165    }
166
167    @Test
168    @SmallTest
169    public void testSimUnknown() {
170        Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
171        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
172                IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
173        mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID);
174
175        mContext.sendBroadcast(mIntent);
176
177        waitForMs(100);
178        verify(mSubscriptionContent, times(0)).put(anyString(), any());
179        CarrierConfigManager mConfigManager = (CarrierConfigManager)
180                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
181        verify(mConfigManager).updateConfigForPhoneId(eq(1),
182                eq(IccCardConstants.INTENT_VALUE_ICC_UNKNOWN));
183        verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
184    }
185
186    @Test
187    @SmallTest
188    public void testSimError() {
189        Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
190        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
191                IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
192        mIntent.putExtra(PhoneConstants.PHONE_KEY, 2);
193
194        mContext.sendBroadcast(mIntent);
195        waitForMs(100);
196        verify(mSubscriptionContent, times(0)).put(anyString(), any());
197        CarrierConfigManager mConfigManager = (CarrierConfigManager)
198                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
199        verify(mConfigManager).updateConfigForPhoneId(eq(2),
200                eq(IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR));
201        verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
202    }
203
204    @Test
205    @SmallTest
206    public void testWrongSimState() {
207        Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
208        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
209                IccCardConstants.INTENT_VALUE_ICC_IMSI);
210        mIntent.putExtra(PhoneConstants.PHONE_KEY, 2);
211
212        mContext.sendBroadcast(mIntent);
213        waitForMs(100);
214        verify(mSubscriptionContent, times(0)).put(anyString(), any());
215        CarrierConfigManager mConfigManager = (CarrierConfigManager)
216                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
217        verify(mConfigManager, times(0)).updateConfigForPhoneId(eq(2),
218                eq(IccCardConstants.INTENT_VALUE_ICC_IMSI));
219        verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
220    }
221
222    @Test
223    @SmallTest
224    public void testSimLoaded() {
225        /* mock new sim got loaded and there is no sim loaded before */
226        doReturn(null).when(mSubscriptionController)
227                .getSubInfoUsingSlotIdWithCheck(eq(0), anyBoolean(), anyString());
228        doReturn("89012604200000000000").when(mIccRecord).getIccId();
229        doReturn(FAKE_PLMN).when(mTelephonyManager).getSimOperatorNumericForPhone(0);
230        Intent intentInternalSimStateChanged =
231                new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
232        intentInternalSimStateChanged.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
233                IccCardConstants.INTENT_VALUE_ICC_LOADED);
234        intentInternalSimStateChanged.putExtra(PhoneConstants.PHONE_KEY, 0);
235
236        mContext.sendBroadcast(intentInternalSimStateChanged);
237        waitForMs(100);
238
239        // verify SIM_STATE_CHANGED broadcast. It should be broadcast twice, once for
240        // READ_PHONE_STATE and once for READ_PRIVILEGED_PHONE_STATE
241        /* todo: cannot verify as intent is sent using ActivityManagerNative.broadcastStickyIntent()
242         * uncomment code below when that is fixed
243         */
244        /* ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
245        ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
246        verify(mContext, times(2)).sendBroadcast(intentArgumentCaptor.capture(),
247                stringArgumentCaptor.capture());
248        assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED,
249                intentArgumentCaptor.getAllValues().get(0).getAction());
250        assertEquals(Manifest.permission.READ_PHONE_STATE,
251                stringArgumentCaptor.getAllValues().get(0));
252        assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED,
253                intentArgumentCaptor.getAllValues().get(1).getAction());
254        assertEquals(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
255                stringArgumentCaptor.getAllValues().get(1)); */
256
257        SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
258        verify(mTelephonyManager).getSimOperatorNumericForPhone(0);
259        verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
260                eq("89012604200000000000"), eq(0));
261        verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
262        verify(mSubscriptionController, times(1)).setMccMnc(FAKE_PLMN, FAKE_SUB_ID);
263        CarrierConfigManager mConfigManager = (CarrierConfigManager)
264                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
265        verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
266                eq(IccCardConstants.INTENT_VALUE_ICC_LOADED));
267
268        // ACTION_USER_UNLOCKED should trigger another SIM_STATE_CHANGED
269        Intent intentSimStateChanged = new Intent(Intent.ACTION_USER_UNLOCKED);
270        mContext.sendBroadcast(intentSimStateChanged);
271        waitForMs(100);
272
273        // verify SIM_STATE_CHANGED broadcast
274        /* todo: cannot verify as intent is sent using ActivityManagerNative.broadcastStickyIntent()
275         * uncomment code below when that is fixed
276         */
277        /* verify(mContext, times(4)).sendBroadcast(intentArgumentCaptor.capture(),
278                stringArgumentCaptor.capture());
279        assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED,
280                intentArgumentCaptor.getAllValues().get(2).getAction());
281        assertEquals(Manifest.permission.READ_PHONE_STATE,
282                stringArgumentCaptor.getAllValues().get(2));
283        assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED,
284                intentArgumentCaptor.getAllValues().get(3).getAction());
285        assertEquals(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
286                stringArgumentCaptor.getAllValues().get(3)); */
287    }
288
289    @Test
290    @SmallTest
291    public void testSimLoadedEmptyOperatorNumeric() {
292        /* mock new sim got loaded and there is no sim loaded before */
293        doReturn(null).when(mSubscriptionController)
294                .getSubInfoUsingSlotIdWithCheck(eq(0), anyBoolean(), anyString());
295        doReturn("89012604200000000000").when(mIccRecord).getIccId();
296        // operator numeric is empty
297        doReturn("").when(mTelephonyManager).getSimOperatorNumericForPhone(0);
298        Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
299        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
300                IccCardConstants.INTENT_VALUE_ICC_LOADED);
301        mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
302
303        mContext.sendBroadcast(mIntent);
304        waitForMs(100);
305        SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
306        verify(mTelephonyManager).getSimOperatorNumericForPhone(0);
307        verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
308                eq("89012604200000000000"), eq(0));
309        verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
310        verify(mSubscriptionController, times(0)).setMccMnc(anyString(), anyInt());
311        CarrierConfigManager mConfigManager = (CarrierConfigManager)
312                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
313        verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
314                eq(IccCardConstants.INTENT_VALUE_ICC_LOADED));
315    }
316
317    @Test
318    @SmallTest
319    public void testSimLockedWithOutIccId() {
320        /* mock no IccId Info present and try to query IccId
321         after IccId query, update subscriptionDB */
322        doReturn(mIccFileHandler).when(mIccCardProxy).getIccFileHandler();
323        doAnswer(new Answer<Void>() {
324            @Override
325            public Void answer(InvocationOnMock invocation) throws Throwable {
326                Message msg = (Message) invocation.getArguments()[1];
327                AsyncResult.forMessage(msg).result = IccUtils
328                        .hexStringToBytes("89012604200000000000");
329                msg.sendToTarget();
330                return null;
331            }
332        }).when(mIccFileHandler).loadEFTransparent(anyInt(), any(Message.class));
333
334        doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController)
335                .getSubInfoUsingSlotIdWithCheck(eq(0), anyBoolean(), anyString());
336
337        Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
338        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
339                IccCardConstants.INTENT_VALUE_ICC_LOCKED);
340        mIntent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, "TESTING");
341        mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
342
343        mContext.sendBroadcast(mIntent);
344        waitForMs(100);
345
346        /* old IccId != new queried IccId */
347        verify(mSubscriptionContent).put(eq(SubscriptionManager.SIM_SLOT_INDEX),
348                eq(SubscriptionManager.INVALID_SIM_SLOT_INDEX));
349        SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
350        verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
351                eq("98106240020000000000"), eq(0));
352
353        verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
354        CarrierConfigManager mConfigManager = (CarrierConfigManager)
355                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
356        verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
357                eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED));
358    }
359
360    @Test
361    @SmallTest
362    public void testSimLockWIthIccId() {
363        /* no need for IccId query */
364        try {
365            replaceInstance(SubscriptionInfoUpdater.class, "mIccId", null,
366                    new String[]{"89012604200000000000"});
367        } catch (Exception ex) {
368            Assert.fail("unexpected exception thrown" + ex.getMessage());
369        }
370        doReturn(mIccFileHandler).when(mIccCardProxy).getIccFileHandler();
371
372        Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
373        mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
374                IccCardConstants.INTENT_VALUE_ICC_LOCKED);
375        mIntent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, "TESTING");
376        mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
377
378        mContext.sendBroadcast(mIntent);
379        waitForMs(100);
380
381        verify(mIccFileHandler, times(0)).loadEFTransparent(anyInt(), any(Message.class));
382        SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
383        verify(mSubscriptionManager, times(0)).addSubscriptionInfoRecord(
384                anyString(), eq(0));
385        verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
386        CarrierConfigManager mConfigManager = (CarrierConfigManager)
387                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
388        /* broadcast is done */
389        verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
390                eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED));
391    }
392
393}