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.app.AppOpsManager;
19import android.content.ContentValues;
20import android.content.Intent;
21import android.database.Cursor;
22import android.database.MatrixCursor;
23import android.net.Uri;
24import android.os.Bundle;
25import android.os.UserHandle;
26import android.provider.Settings;
27import android.test.mock.MockContentProvider;
28import android.test.mock.MockContentResolver;
29import android.test.suitebuilder.annotation.SmallTest;
30import static org.junit.Assert.*;
31import static org.mockito.Mockito.*;
32import org.junit.After;
33import org.junit.Before;
34import org.junit.Test;
35import org.mockito.ArgumentCaptor;
36import org.mockito.Mock;
37
38import android.telephony.SubscriptionInfo;
39import android.telephony.SubscriptionManager;
40import android.util.Log;
41
42import java.util.ArrayList;
43import java.util.List;
44
45public class SubscriptionControllerTest extends TelephonyTest {
46
47    private static final int SINGLE_SIM = 1;
48    private String mCallingPackage;
49    private SubscriptionController mSubscriptionControllerUT;
50    private MockContentResolver mMockContentResolver;
51
52    @Mock private List<SubscriptionInfo> mSubList;
53    @Mock private AppOpsManager mAppOps;
54
55    public class FakeSubscriptionContentProvider extends MockContentProvider {
56
57        private ArrayList<ContentValues> mSubscriptionArray =
58                new ArrayList<ContentValues>();
59
60        private String[] mKeyMappingSet = new String[]{
61                SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
62                SubscriptionManager.ICC_ID, SubscriptionManager.SIM_SLOT_INDEX,
63                SubscriptionManager.DISPLAY_NAME, SubscriptionManager.CARRIER_NAME,
64                SubscriptionManager.NAME_SOURCE, SubscriptionManager.COLOR,
65                SubscriptionManager.NUMBER, SubscriptionManager.DISPLAY_NUMBER_FORMAT,
66                SubscriptionManager.DATA_ROAMING, SubscriptionManager.MCC,
67                SubscriptionManager.MNC, SubscriptionManager.CB_EXTREME_THREAT_ALERT,
68                SubscriptionManager.CB_SEVERE_THREAT_ALERT, SubscriptionManager.CB_AMBER_ALERT,
69                SubscriptionManager.CB_ALERT_SOUND_DURATION,
70                SubscriptionManager.CB_ALERT_REMINDER_INTERVAL,
71                SubscriptionManager.CB_ALERT_VIBRATE, SubscriptionManager.CB_ALERT_SPEECH,
72                SubscriptionManager.CB_ETWS_TEST_ALERT, SubscriptionManager.CB_CHANNEL_50_ALERT,
73                SubscriptionManager.CB_CMAS_TEST_ALERT, SubscriptionManager.CB_OPT_OUT_DIALOG,
74                SubscriptionManager.SIM_PROVISIONING_STATUS};
75
76        /* internal util function */
77        private MatrixCursor convertFromContentToCursor(ContentValues initialValues) {
78            MatrixCursor cursor = null;
79            ArrayList<Object> values = new ArrayList<Object>();
80
81            if (initialValues != null && mKeyMappingSet.length != 0) {
82                cursor = new MatrixCursor(mKeyMappingSet);
83                /* push value from contentValues to matrixCursors */
84                for (String key : mKeyMappingSet) {
85                    if (initialValues.containsKey(key)) {
86                        values.add(initialValues.get(key));
87                    } else {
88                        values.add(null);
89                    }
90                }
91                cursor.addRow(values.toArray());
92            }
93            return cursor;
94        }
95
96        @Override
97        public int delete(Uri uri, String selection, String[] selectionArgs) {
98            if (mSubscriptionArray.size() > 0) {
99                mSubscriptionArray.remove(0);
100                return 1;
101            }
102            return -1;
103        }
104
105        @Override
106        public Uri insert(Uri uri, ContentValues values) {
107            values.put(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID, 0);
108            mSubscriptionArray.add(values);
109            return uri;
110        }
111
112        @Override
113        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
114                            String sortOrder) {
115            if (mSubscriptionArray.size() > 0) {
116                return convertFromContentToCursor(mSubscriptionArray.get(0));
117            }
118            return null;
119        }
120
121        @Override
122        public Bundle call(String method, String request, Bundle args) {
123            return null;
124        }
125
126        @Override
127        public int update(android.net.Uri uri, android.content.ContentValues values,
128                          java.lang.String selection, java.lang.String[] selectionArgs) {
129            if (mSubscriptionArray.size() > 0) {
130                ContentValues val = mSubscriptionArray.get(0);
131                for (String key : values.keySet()) {
132                    val.put(key, values.getAsString(key));
133                    Log.d(TAG, "update the values..." + key + "..." + values.getAsString(key));
134                }
135                mSubscriptionArray.set(0, val);
136                return 1;
137            }
138            return -1;
139        }
140    }
141
142    @Before
143    public void setUp() throws Exception {
144        super.setUp("SubscriptionControllerTest");
145
146        doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount();
147        doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount();
148
149        replaceInstance(SubscriptionController.class, "sInstance", null, null);
150
151        SubscriptionController.init(mContext, null);
152        mSubscriptionControllerUT = SubscriptionController.getInstance();
153        mCallingPackage = mContext.getOpPackageName();
154
155        doReturn(1).when(mProxyController).getMaxRafSupported();
156        mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[]{5});
157
158        mSubscriptionControllerUT.getInstance().updatePhonesAvailability(new Phone[]{mPhone});
159        mMockContentResolver = (MockContentResolver) mContext.getContentResolver();
160        mMockContentResolver.addProvider(SubscriptionManager.CONTENT_URI.getAuthority(),
161                new FakeSubscriptionContentProvider());
162    }
163
164    @After
165    public void tearDown() throws Exception {
166        /* should clear fake content provider and resolver here */
167        mContext.getContentResolver().delete(SubscriptionManager.CONTENT_URI, null, null);
168
169        /* clear settings for default voice/data/sms sub ID */
170        Settings.Global.putInt(mContext.getContentResolver(),
171                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
172                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
173        Settings.Global.putInt(mContext.getContentResolver(),
174                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
175                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
176        Settings.Global.putInt(mContext.getContentResolver(),
177                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
178                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
179
180        mSubscriptionControllerUT = null;
181        super.tearDown();
182    }
183
184    @Test @SmallTest
185    public void testInsertSim() {
186        int slotID = mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage);
187
188        //verify there is no sim inserted in the SubscriptionManager
189        assertEquals(0, slotID);
190
191        //insert one Subscription Info
192        mSubscriptionControllerUT.addSubInfoRecord("test", slotID);
193
194        //verify there is one sim
195        assertEquals(1, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
196
197        //sanity for slot id and sub id
198        List<SubscriptionInfo> mSubList = mSubscriptionControllerUT
199                .getActiveSubscriptionInfoList(mCallingPackage);
200        assertTrue(mSubList != null && mSubList.size() > 0);
201        for (int i = 0; i < mSubList.size(); i++) {
202            assertTrue(SubscriptionManager.isValidSubscriptionId(
203                    mSubList.get(i).getSubscriptionId()));
204            assertTrue(SubscriptionManager.isValidSlotIndex(mSubList.get(i).getSimSlotIndex()));
205        }
206    }
207
208    @Test @SmallTest
209    public void testChangeSIMProperty() {
210        int dataRoaming = 1;
211        int iconTint = 1;
212        String disName = "TESTING";
213        String disNum = "12345";
214
215        testInsertSim();
216        /* Get SUB ID */
217        int[] subIds = mSubscriptionControllerUT.getActiveSubIdList();
218        assertTrue(subIds != null && subIds.length != 0);
219        int subID = subIds[0];
220
221        /* Setting */
222        mSubscriptionControllerUT.setDisplayName(disName, subID);
223        mSubscriptionControllerUT.setDataRoaming(dataRoaming, subID);
224        mSubscriptionControllerUT.setDisplayNumber(disNum, subID);
225        mSubscriptionControllerUT.setIconTint(iconTint, subID);
226
227        /* Getting, there is no direct getter function for each fields of property */
228        SubscriptionInfo subInfo = mSubscriptionControllerUT
229                .getActiveSubscriptionInfo(subID, mCallingPackage);
230        assertNotNull(subInfo);
231        assertEquals(dataRoaming, subInfo.getDataRoaming());
232        assertEquals(disName, subInfo.getDisplayName());
233        assertEquals(iconTint, subInfo.getIconTint());
234        assertEquals(disNum, subInfo.getNumber());
235
236        /* verify broadcast intent */
237        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
238        verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture());
239        assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED,
240                captorIntent.getValue().getAction());
241    }
242
243    @Test @SmallTest
244    public void testCleanUpSIM() {
245        testInsertSim();
246        assertFalse(mSubscriptionControllerUT.isActiveSubId(1));
247        mSubscriptionControllerUT.clearSubInfo();
248        assertFalse(mSubscriptionControllerUT.isActiveSubId(0));
249        assertEquals(SubscriptionManager.SIM_NOT_INSERTED,
250                mSubscriptionControllerUT.getSlotIndex(0));
251    }
252
253    @Test @SmallTest
254    public void testDefaultSubID() {
255        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
256                mSubscriptionControllerUT.getDefaultDataSubId());
257        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
258                mSubscriptionControllerUT.getDefaultSmsSubId());
259        assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
260                mSubscriptionControllerUT.getDefaultSmsSubId());
261        /* insert one sim */
262        testInsertSim();
263        // if support single sim, sms/data/voice default sub should be the same
264        assertNotSame(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
265                mSubscriptionControllerUT.getDefaultSubId());
266        assertEquals(mSubscriptionControllerUT.getDefaultDataSubId(),
267                mSubscriptionControllerUT.getDefaultSmsSubId());
268        assertEquals(mSubscriptionControllerUT.getDefaultDataSubId(),
269                mSubscriptionControllerUT.getDefaultVoiceSubId());
270    }
271
272    @Test @SmallTest
273    public void testSetGetMCCMNC() {
274        testInsertSim();
275        String mCcMncVERIZON = "310004";
276        mSubscriptionControllerUT.setMccMnc(mCcMncVERIZON, 0);
277
278        SubscriptionInfo subInfo = mSubscriptionControllerUT
279                .getActiveSubscriptionInfo(0, mCallingPackage);
280        assertNotNull(subInfo);
281        assertEquals(Integer.parseInt(mCcMncVERIZON.substring(0, 3)), subInfo.getMcc());
282        assertEquals(Integer.parseInt(mCcMncVERIZON.substring(3)), subInfo.getMnc());
283
284         /* verify broadcast intent */
285        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
286        verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture());
287        assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED,
288                captorIntent.getValue().getAction());
289    }
290
291    @Test
292    @SmallTest
293    public void testSetDefaultDataSubId() throws Exception {
294        doReturn(1).when(mPhone).getSubId();
295
296        mSubscriptionControllerUT.setDefaultDataSubId(1);
297
298        verify(mPhone, times(1)).updateDataConnectionTracker();
299        ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class);
300        verify(mContext, times(1)).sendStickyBroadcastAsUser(
301                captorIntent.capture(), eq(UserHandle.ALL));
302
303        Intent intent = captorIntent.getValue();
304        assertEquals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED, intent.getAction());
305
306        Bundle b = intent.getExtras();
307
308        assertTrue(b.containsKey(PhoneConstants.SUBSCRIPTION_KEY));
309        assertEquals(1, b.getInt(PhoneConstants.SUBSCRIPTION_KEY));
310    }
311}
312