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  */
16 
17 package android.carrierapi.cts;
18 
19 import static android.carrierapi.cts.FcpTemplate.FILE_IDENTIFIER;
20 import static android.carrierapi.cts.IccUtils.bytesToHexString;
21 import static android.carrierapi.cts.IccUtils.hexStringToBytes;
22 import static android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL;
23 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
24 
25 import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_2021;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 import static com.google.common.truth.Truth.assertWithMessage;
29 
30 import static org.junit.Assert.fail;
31 import static org.junit.Assume.assumeTrue;
32 
33 import android.content.BroadcastReceiver;
34 import android.content.ContentProviderClient;
35 import android.content.ContentValues;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.IntentFilter;
39 import android.database.Cursor;
40 import android.net.Uri;
41 import android.os.AsyncTask;
42 import android.os.Build;
43 import android.os.Handler;
44 import android.os.HandlerThread;
45 import android.os.ParcelUuid;
46 import android.os.PersistableBundle;
47 import android.platform.test.annotations.SystemUserOnly;
48 import android.provider.Telephony;
49 import android.provider.VoicemailContract;
50 import android.telephony.AccessNetworkConstants;
51 import android.telephony.AvailableNetworkInfo;
52 import android.telephony.CarrierConfigManager;
53 import android.telephony.IccOpenLogicalChannelResponse;
54 import android.telephony.PhoneStateListener;
55 import android.telephony.SignalStrengthUpdateRequest;
56 import android.telephony.SignalThresholdInfo;
57 import android.telephony.SubscriptionInfo;
58 import android.telephony.SubscriptionManager;
59 import android.telephony.TelephonyManager;
60 import android.util.Base64;
61 import android.util.Log;
62 
63 import androidx.test.runner.AndroidJUnit4;
64 
65 import com.android.compatibility.common.util.ShellIdentityUtils;
66 import com.android.compatibility.common.util.UiccUtil;
67 
68 import com.google.common.collect.Range;
69 
70 import org.junit.After;
71 import org.junit.Before;
72 import org.junit.Test;
73 import org.junit.runner.RunWith;
74 
75 import java.util.ArrayList;
76 import java.util.Arrays;
77 import java.util.Collections;
78 import java.util.HashSet;
79 import java.util.List;
80 import java.util.Set;
81 import java.util.concurrent.CountDownLatch;
82 import java.util.concurrent.TimeUnit;
83 import java.util.concurrent.atomic.AtomicReference;
84 import java.util.function.Consumer;
85 import java.util.stream.Collectors;
86 
87 import javax.annotation.Nonnull;
88 
89 /**
90  * Unit tests for various carrier-related APIs.
91  *
92  * <p>Test using `atest CtsCarrierApiTestCases:CarrierApiTest` or `make cts -j64 && cts-tradefed run
93  * cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.CarrierApiTest`
94  */
95 // TODO(b/130187425): Split CarrierApiTest apart to have separate test classes for functionality
96 @RunWith(AndroidJUnit4.class)
97 public class CarrierApiTest extends BaseCarrierApiTest {
98     private static final String TAG = "CarrierApiTest";
99 
100     private TelephonyManager mTelephonyManager;
101     private CarrierConfigManager mCarrierConfigManager;
102     private SubscriptionManager mSubscriptionManager;
103     private ContentProviderClient mVoicemailProvider;
104     private ContentProviderClient mStatusProvider;
105     private Uri mVoicemailContentUri;
106     private Uri mStatusContentUri;
107     private String selfPackageName;
108     private HandlerThread mListenerThread;
109 
110     // The minimum allocatable logical channel number, per TS 102 221 Section 11.1.17.1
111     private static final int MIN_LOGICAL_CHANNEL = 1;
112     // The maximum allocatable logical channel number in the standard range, per TS 102 221 Section
113     // 11.1.17.1
114     private static final int MAX_LOGICAL_CHANNEL = 3;
115     // Class bytes. The logical channel used should be included for bits b2b1. TS 102 221 Table 11.5
116     private static final int CLA_GET_RESPONSE = 0x00;
117     private static final int CLA_MANAGE_CHANNEL = 0x00;
118     private static final int CLA_READ_BINARY = 0x00;
119     private static final int CLA_SELECT = 0x00;
120     private static final int CLA_STATUS = 0x80;
121     private static final String CLA_STATUS_STRING = "80";
122     // APDU Instruction Bytes. TS 102 221 Section 10.1.2
123     private static final int COMMAND_GET_RESPONSE = 0xC0;
124     private static final int COMMAND_MANAGE_CHANNEL = 0x70;
125     private static final int COMMAND_READ_BINARY = 0xB0;
126     private static final int COMMAND_SELECT = 0xA4;
127     private static final int COMMAND_STATUS = 0xF2;
128     private static final String COMMAND_STATUS_STRING = "F2";
129     // Status words. TS 102 221 Section 10.2.1
130     private static final byte[] STATUS_NORMAL = {(byte) 0x90, (byte) 0x00};
131     private static final String STATUS_NORMAL_STRING = "9000";
132     private static final String STATUS_BYTES_REMAINING = "61";
133     private static final String STATUS_WARNING_A = "62";
134     private static final String STATUS_WARNING_B = "63";
135     private static final String STATUS_FILE_NOT_FOUND = "6a82";
136     private static final String STATUS_INCORRECT_PARAMETERS = "6a86";
137     private static final String STATUS_WRONG_PARAMETERS = "6b00";
138     private static final Set<String> INVALID_PARAMETERS_STATUSES =
139             new HashSet<>(Arrays.asList(STATUS_INCORRECT_PARAMETERS, STATUS_WRONG_PARAMETERS));
140     private static final String STATUS_WRONG_CLASS = "6e00";
141     // File ID for the EF ICCID. TS 102 221
142     private static final String ICCID_FILE_ID = "2FE2";
143     // File ID for the master file. TS 102 221
144     private static final String MF_FILE_ID = "3F00";
145     private static final int MF_FILE_ID_HEX = 0x3F00;
146     // File ID for the MF Access Rule Reference. TS 102 221
147     private static final String MF_ARR_FILE_ID = "2F06";
148     private static final String ALPHA_TAG_A = "tagA";
149     private static final String ALPHA_TAG_B = "tagB";
150     private static final String NUMBER_A = "1234567890";
151     private static final String NUMBER_B = "0987654321";
152     private static final String TESTING_PLMN = "12345";
153 
154     private static final String EAP_SIM_AKA_RAND = "11111111111111111111111111111111";
155 
156     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
157     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2
158     private static final String EAP_AKA_AUTN = "12351417161900001130131215141716";
159 
160     // EAP-AKA Response Format: [DB][Length][RES][Length][CK][Length][IK]
161     private static final int EAP_AKA_RESPONSE_LENGTH = 1 + 1 + 16 + 1 + 16 + 1 + 16;
162 
163     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
164     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
165     // Format: [DB][Length][RES][Length][CK][Length][IK]
166     private static final String EXPECTED_EAP_AKA_RESULT =
167             "DB10111013121514171619181B1A1D1C1F1E"
168                     + "101013121514171619181B1A1D1C1F1E11"
169                     + "1013121514171619181B1A1D1C1F1E1110";
170 
171     // Derived from TS 134 108#8.1.2 and TS 133 102#6.8.1.2. Based on EAP_SIM_AKA_RAND and assumed K
172     // value of 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
173     // Format: [Length][SRES][Length][Kc]
174     private static final String EXPECTED_EAP_SIM_RESULT = "0400000000080000000000000000";
175 
176     private static final int DSDS_PHONE_COUNT = 2;
177 
178     @Before
setUp()179     public void setUp() throws Exception {
180         Context context = getContext();
181         mTelephonyManager = context.getSystemService(TelephonyManager.class);
182         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
183         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
184         selfPackageName = context.getPackageName();
185         mVoicemailContentUri = VoicemailContract.Voicemails.buildSourceUri(selfPackageName);
186         mVoicemailProvider =
187                 context.getContentResolver().acquireContentProviderClient(mVoicemailContentUri);
188         mStatusContentUri = VoicemailContract.Status.buildSourceUri(selfPackageName);
189         mStatusProvider =
190                 context.getContentResolver().acquireContentProviderClient(mStatusContentUri);
191         mListenerThread = new HandlerThread("CarrierApiTest");
192         mListenerThread.start();
193     }
194 
195     @After
tearDown()196     public void tearDown() throws Exception {
197         if (!werePreconditionsSatisfied()) return;
198 
199         mListenerThread.quit();
200         try {
201             mStatusProvider.delete(mStatusContentUri, null, null);
202             mVoicemailProvider.delete(mVoicemailContentUri, null, null);
203         } catch (Exception e) {
204             Log.w(TAG, "Failed to clean up voicemail tables in tearDown", e);
205         }
206     }
207 
208     @Test
testSimCardPresent()209     public void testSimCardPresent() {
210         assertWithMessage("This test requires a SIM card")
211                 .that(mTelephonyManager.getSimState())
212                 .isNotEqualTo(TelephonyManager.SIM_STATE_ABSENT);
213     }
214 
215     @Test
testHasCarrierPrivileges()216     public void testHasCarrierPrivileges() {
217         assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
218                 .that(mTelephonyManager.hasCarrierPrivileges())
219                 .isTrue();
220     }
221 
assertUpdateAvailableNetworkSuccess(int value)222     private static void assertUpdateAvailableNetworkSuccess(int value) {
223         assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
224     }
225 
assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value)226     private static void assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value) {
227         assertThat(value)
228                 .isEqualTo(
229                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
230     }
231 
assertSetOpportunisticSubSuccess(int value)232     private static void assertSetOpportunisticSubSuccess(int value) {
233         assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
234     }
235 
getFirstActivateCarrierPrivilegedSubscriptionId()236     private int getFirstActivateCarrierPrivilegedSubscriptionId() {
237         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
238         List<SubscriptionInfo> subscriptionInfos =
239                 mSubscriptionManager.getActiveSubscriptionInfoList();
240         if (subscriptionInfos != null) {
241             for (SubscriptionInfo info : subscriptionInfos) {
242                 TelephonyManager telephonyManager =
243                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
244                 if (telephonyManager.hasCarrierPrivileges()) {
245                     subId = info.getSubscriptionId();
246                     return subId;
247                 }
248             }
249         }
250         return subId;
251     }
252 
253     @Test
testUpdateAvailableNetworksWithCarrierPrivilege()254     public void testUpdateAvailableNetworksWithCarrierPrivilege() {
255         int subIdWithCarrierPrivilege = getFirstActivateCarrierPrivilegedSubscriptionId();
256         int activeSubscriptionInfoCount =
257                 ShellIdentityUtils.invokeMethodWithShellPermissions(
258                         mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
259         if (mTelephonyManager.getPhoneCount() == 1) {
260             return;
261         }
262 
263         /* TODO: b/145993690 */
264         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
265             /* This test requires two SIM cards */
266             return;
267         }
268         if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
269             /* This test requires SIM with carrier privilege */
270             return;
271         }
272 
273         List<SubscriptionInfo> subscriptionInfoList =
274                 mSubscriptionManager.getOpportunisticSubscriptions();
275         List<String> mccMncs = new ArrayList<String>();
276         List<Integer> bands = new ArrayList<Integer>();
277         List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>();
278         Consumer<Integer> callbackSuccess = CarrierApiTest::assertUpdateAvailableNetworkSuccess;
279         Consumer<Integer> callbackNoOpportunisticSubAvailable =
280                 CarrierApiTest::assertUpdateAvailableNetworkNoOpportunisticSubAvailable;
281         Consumer<Integer> setOpCallbackSuccess = CarrierApiTest::assertSetOpportunisticSubSuccess;
282         if (subscriptionInfoList == null
283                 || subscriptionInfoList.size() == 0
284                 || !mSubscriptionManager.isActiveSubscriptionId(
285                         subscriptionInfoList.get(0).getSubscriptionId())) {
286             try {
287                 AvailableNetworkInfo availableNetworkInfo =
288                         new AvailableNetworkInfo(
289                                 subIdWithCarrierPrivilege,
290                                 AvailableNetworkInfo.PRIORITY_HIGH,
291                                 mccMncs,
292                                 bands);
293                 availableNetworkInfos.add(availableNetworkInfo);
294                 // Call updateAvailableNetworks without opportunistic subscription.
295                 // callbackNoOpportunisticSubAvailable is expected to be triggered
296                 // and the return value will be checked against
297                 // UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE
298                 mTelephonyManager.updateAvailableNetworks(
299                         availableNetworkInfos,
300                         AsyncTask.SERIAL_EXECUTOR,
301                         callbackNoOpportunisticSubAvailable);
302             } finally {
303                 // clear all the operations at the end of test.
304                 availableNetworkInfos.clear();
305                 mTelephonyManager.updateAvailableNetworks(
306                         availableNetworkInfos,
307                         AsyncTask.SERIAL_EXECUTOR,
308                         callbackNoOpportunisticSubAvailable);
309             }
310         } else {
311             // This is case of DSDS phone, one active opportunistic subscription and one
312             // active primary subscription.
313             int resultSubId;
314             try {
315                 AvailableNetworkInfo availableNetworkInfo =
316                         new AvailableNetworkInfo(
317                                 subscriptionInfoList.get(0).getSubscriptionId(),
318                                 AvailableNetworkInfo.PRIORITY_HIGH,
319                                 mccMncs,
320                                 bands);
321                 availableNetworkInfos.add(availableNetworkInfo);
322                 mTelephonyManager.updateAvailableNetworks(
323                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
324                 // wait for the data change to take effect
325                 waitForMs(500);
326                 // Call setPreferredData and reconfirm with getPreferred data
327                 // that the same is updated.
328                 int preferSubId = subscriptionInfoList.get(0).getSubscriptionId();
329                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
330                         preferSubId, false, AsyncTask.SERIAL_EXECUTOR, setOpCallbackSuccess);
331                 // wait for the data change to take effect
332                 waitForMs(500);
333                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
334                 assertThat(resultSubId).isEqualTo(preferSubId);
335             } finally {
336                 // clear all the operations at the end of test.
337                 availableNetworkInfos.clear();
338                 mTelephonyManager.updateAvailableNetworks(
339                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
340                 waitForMs(500);
341                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
342                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
343                         false,
344                         AsyncTask.SERIAL_EXECUTOR,
345                         callbackSuccess);
346                 waitForMs(500);
347                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
348                 assertThat(resultSubId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
349             }
350         }
351     }
352 
waitForMs(long ms)353     public static void waitForMs(long ms) {
354         try {
355             Thread.sleep(ms);
356         } catch (InterruptedException e) {
357             Log.d(TAG, "InterruptedException while waiting: " + e);
358         }
359     }
360 
361     @Test
testGetIccAuthentication()362     public void testGetIccAuthentication() {
363         // EAP-SIM rand is 16 bytes.
364         String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
365         String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
366 
367         try {
368             assertWithMessage("getIccAuthentication should return null for empty data.")
369                     .that(
370                             mTelephonyManager.getIccAuthentication(
371                                     TelephonyManager.APPTYPE_USIM,
372                                     TelephonyManager.AUTHTYPE_EAP_AKA,
373                                     ""))
374                     .isNull();
375             String response =
376                     mTelephonyManager.getIccAuthentication(
377                             TelephonyManager.APPTYPE_USIM,
378                             TelephonyManager.AUTHTYPE_EAP_SIM,
379                             base64Challenge);
380             assertWithMessage("Response to EAP-SIM Challenge must not be Null.")
381                     .that(response)
382                     .isNotNull();
383             // response is base64 encoded. After decoding, the value should be:
384             // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
385             byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
386             assertThat(result).hasLength(14);
387             String response2 =
388                     mTelephonyManager.getIccAuthentication(
389                             TelephonyManager.APPTYPE_USIM,
390                             TelephonyManager.AUTHTYPE_EAP_SIM,
391                             base64Challenge2);
392             assertWithMessage("Two responses must be different")
393                     .that(response)
394                     .isNotEqualTo(response2);
395         } catch (SecurityException e) {
396             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
397         }
398     }
399 
400     @Test
401     @SystemUserOnly(reason = "b/177921545, broadcast sent only to primary user")
testSendDialerSpecialCode()402     public void testSendDialerSpecialCode() {
403         IntentReceiver intentReceiver = new IntentReceiver();
404         final IntentFilter intentFilter = new IntentFilter();
405         intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION);
406         intentFilter.addDataScheme("android_secret_code");
407 
408         Context context = getContext();
409         context.registerReceiver(intentReceiver, intentFilter);
410         try {
411             mTelephonyManager.sendDialerSpecialCode("4636");
412             assertWithMessage(
413                             "Did not receive expected Intent: "
414                                     + Telephony.Sms.Intents.SECRET_CODE_ACTION)
415                     .that(intentReceiver.waitForReceive())
416                     .isTrue();
417         } catch (SecurityException e) {
418             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
419         } catch (InterruptedException e) {
420             Log.d(TAG, "Broadcast receiver wait was interrupted.");
421         } finally {
422             context.unregisterReceiver(intentReceiver);
423         }
424     }
425 
426     @Test
testSubscriptionInfoListing()427     public void testSubscriptionInfoListing() {
428         try {
429             assertThat(mSubscriptionManager.getActiveSubscriptionInfoCount()).isGreaterThan(0);
430             List<SubscriptionInfo> subInfoList =
431                     mSubscriptionManager.getActiveSubscriptionInfoList();
432             assertWithMessage("getActiveSubscriptionInfoList() returned null")
433                     .that(subInfoList)
434                     .isNotNull();
435             assertWithMessage("getActiveSubscriptionInfoList() returned an empty list")
436                     .that(subInfoList)
437                     .isNotEmpty();
438             for (SubscriptionInfo info : subInfoList) {
439                 TelephonyManager tm =
440                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
441                 assertWithMessage(
442                                 "getActiveSubscriptionInfoList() returned an inaccessible"
443                                         + " subscription")
444                         .that(tm.hasCarrierPrivileges())
445                         .isTrue();
446 
447                 // Check other APIs to make sure they are accessible and return consistent info.
448                 SubscriptionInfo infoForSlot =
449                         mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
450                                 info.getSimSlotIndex());
451                 assertWithMessage("getActiveSubscriptionInfoForSimSlotIndex() returned null")
452                         .that(infoForSlot)
453                         .isNotNull();
454                 assertWithMessage(
455                                 "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent"
456                                         + " info")
457                         .that(infoForSlot.getSubscriptionId())
458                         .isEqualTo(info.getSubscriptionId());
459 
460                 SubscriptionInfo infoForSubId =
461                         mSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId());
462                 assertWithMessage("getActiveSubscriptionInfo() returned null")
463                         .that(infoForSubId)
464                         .isNotNull();
465                 assertWithMessage("getActiveSubscriptionInfo() returned inconsistent info")
466                         .that(infoForSubId.getSubscriptionId())
467                         .isEqualTo(info.getSubscriptionId());
468             }
469         } catch (SecurityException e) {
470             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
471         }
472     }
473 
474     @Test
testCarrierConfigIsAccessible()475     public void testCarrierConfigIsAccessible() {
476         try {
477             PersistableBundle bundle = mCarrierConfigManager.getConfig();
478             assertWithMessage("CarrierConfigManager#getConfig() returned null")
479                     .that(bundle)
480                     .isNotNull();
481             assertWithMessage("CarrierConfigManager#getConfig() returned empty bundle")
482                     .that(bundle.isEmpty())
483                     .isFalse();
484 
485             int subId = SubscriptionManager.getDefaultSubscriptionId();
486             bundle = mCarrierConfigManager.getConfigForSubId(subId);
487             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned null")
488                     .that(bundle)
489                     .isNotNull();
490             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned empty bundle")
491                     .that(bundle.isEmpty())
492                     .isFalse();
493         } catch (SecurityException e) {
494             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
495         }
496     }
497 
498     @Test
testTelephonyApisAreAccessible()499     public void testTelephonyApisAreAccessible() {
500         // The following methods may return any value depending on the state of the device. Simply
501         // call them to make sure they do not throw any exceptions. Methods that return a device
502         // identifier will be accessible to apps with carrier privileges in Q, but this may change
503         // in a future release.
504         try {
505             mTelephonyManager.getDeviceId();
506             mTelephonyManager.getImei();
507             mTelephonyManager.getMeid();
508             mTelephonyManager.getDeviceSoftwareVersion();
509             mTelephonyManager.getNai();
510             mTelephonyManager.getDataNetworkType();
511             mTelephonyManager.getVoiceNetworkType();
512             mTelephonyManager.getSimSerialNumber();
513             mTelephonyManager.getSubscriberId();
514             mTelephonyManager.getGroupIdLevel1();
515             mTelephonyManager.getLine1Number();
516             mTelephonyManager.getVoiceMailNumber();
517             mTelephonyManager.getVisualVoicemailPackageName();
518             mTelephonyManager.getVoiceMailAlphaTag();
519             mTelephonyManager.getForbiddenPlmns();
520             mTelephonyManager.getServiceState();
521             mTelephonyManager.getManualNetworkSelectionPlmn();
522             mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
523         } catch (SecurityException e) {
524             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
525         }
526     }
527 
528     @Test
testVoicemailTableIsAccessible()529     public void testVoicemailTableIsAccessible() throws Exception {
530         ContentValues value = new ContentValues();
531         value.put(VoicemailContract.Voicemails.NUMBER, "0123456789");
532         value.put(VoicemailContract.Voicemails.SOURCE_PACKAGE, selfPackageName);
533         try {
534             Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value);
535             assertThat(uri).isNotNull();
536             Cursor cursor =
537                     mVoicemailProvider.query(
538                             uri,
539                             new String[] {
540                                 VoicemailContract.Voicemails.NUMBER,
541                                 VoicemailContract.Voicemails.SOURCE_PACKAGE
542                             },
543                             null,
544                             null,
545                             null);
546             assertThat(cursor).isNotNull();
547             assertThat(cursor.moveToFirst()).isTrue();
548             assertThat(cursor.getString(0)).isEqualTo("0123456789");
549             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
550             assertThat(cursor.moveToNext()).isFalse();
551         } catch (SecurityException e) {
552             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
553         }
554     }
555 
556     @Test
testVoicemailStatusTableIsAccessible()557     public void testVoicemailStatusTableIsAccessible() throws Exception {
558         ContentValues value = new ContentValues();
559         value.put(
560                 VoicemailContract.Status.CONFIGURATION_STATE,
561                 VoicemailContract.Status.CONFIGURATION_STATE_OK);
562         value.put(VoicemailContract.Status.SOURCE_PACKAGE, selfPackageName);
563         try {
564             Uri uri = mStatusProvider.insert(mStatusContentUri, value);
565             assertThat(uri).isNotNull();
566             Cursor cursor =
567                     mVoicemailProvider.query(
568                             uri,
569                             new String[] {
570                                 VoicemailContract.Status.CONFIGURATION_STATE,
571                                 VoicemailContract.Status.SOURCE_PACKAGE
572                             },
573                             null,
574                             null,
575                             null);
576             assertThat(cursor).isNotNull();
577             assertThat(cursor.moveToFirst()).isTrue();
578             assertThat(cursor.getInt(0)).isEqualTo(VoicemailContract.Status.CONFIGURATION_STATE_OK);
579             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
580             assertThat(cursor.moveToNext()).isFalse();
581         } catch (SecurityException e) {
582             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
583         }
584     }
585 
586     static final int READ_PHONE_STATE_LISTENERS =
587             PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
588                     | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
589                     | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
590 
591     static final int READ_PRECISE_PHONE_STATE_LISTENERS =
592             PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
593                     | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
594                     | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
595                     | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
596                     | PhoneStateListener.LISTEN_BARRING_INFO;
597 
598     static final int CARRIER_PRIVILEGE_LISTENERS =
599             READ_PHONE_STATE_LISTENERS | READ_PRECISE_PHONE_STATE_LISTENERS;
600 
601     @Test
testGetManualNetworkSelectionPlmnPersisted()602     public void testGetManualNetworkSelectionPlmnPersisted() throws Exception {
603         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
604 
605         try {
606             mTelephonyManager.setNetworkSelectionModeManual(
607                     TESTING_PLMN /* operatorNumeric */, true /* persistSelection */);
608             String plmn = mTelephonyManager.getManualNetworkSelectionPlmn();
609             assertThat(plmn).isEqualTo(TESTING_PLMN);
610         } finally {
611             mTelephonyManager.setNetworkSelectionModeAutomatic();
612         }
613     }
614 
615     @Test
testPhoneStateListener()616     public void testPhoneStateListener() throws Exception {
617         PhoneStateListener psl = new PhoneStateListener((Runnable r) -> {});
618         try {
619             mTelephonyManager.listen(psl, CARRIER_PRIVILEGE_LISTENERS);
620         } finally {
621             mTelephonyManager.listen(psl, PhoneStateListener.LISTEN_NONE);
622         }
623     }
624 
625     @Test
testIsManualNetworkSelectionAllowed()626     public void testIsManualNetworkSelectionAllowed() throws Exception {
627         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
628 
629         try {
630             assertThat(mTelephonyManager.isManualNetworkSelectionAllowed()).isTrue();
631         } catch (SecurityException e) {
632             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
633         }
634     }
635 
636     @Test
testGetNetworkSelectionMode()637     public void testGetNetworkSelectionMode() throws Exception {
638         try {
639             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
640                     mTelephonyManager, (tm) -> tm.setNetworkSelectionModeAutomatic());
641             int networkMode = mTelephonyManager.getNetworkSelectionMode();
642             assertThat(networkMode).isEqualTo(TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
643         } catch (SecurityException e) {
644             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
645         }
646     }
647 
648     @Test
testSubscriptionInfoChangeListener()649     public void testSubscriptionInfoChangeListener() throws Exception {
650         final AtomicReference<SecurityException> error = new AtomicReference<>();
651         final CountDownLatch latch = new CountDownLatch(1);
652         new Handler(mListenerThread.getLooper())
653                 .post(
654                         () -> {
655                             SubscriptionManager.OnSubscriptionsChangedListener listener =
656                                     new SubscriptionManager.OnSubscriptionsChangedListener();
657                             try {
658                                 mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
659                             } catch (SecurityException e) {
660                                 error.set(e);
661                             } finally {
662                                 mSubscriptionManager.removeOnSubscriptionsChangedListener(listener);
663                                 latch.countDown();
664                             }
665                         });
666         assertWithMessage("Test timed out").that(latch.await(30L, TimeUnit.SECONDS)).isTrue();
667         if (error.get() != null) {
668             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
669         }
670     }
671 
672     /**
673      * Test that it's possible to open logical channels to the ICC. This mirrors the Manage Channel
674      * command described in TS 102 221 Section 11.1.17.
675      */
676     @Test
testIccOpenLogicalChannel()677     public void testIccOpenLogicalChannel() {
678         // The AID here doesn't matter - we just need to open a valid connection. In this case, the
679         // specified AID ("") opens a channel and selects the MF.
680         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
681         final int logicalChannel = response.getChannel();
682         try {
683             verifyValidIccOpenLogicalChannelResponse(response);
684         } finally {
685             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
686         }
687     }
688 
689     @Test
testIccOpenLogicalChannelWithValidP2()690     public void testIccOpenLogicalChannelWithValidP2() {
691         // {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU
692         // followed by a Select APDU with the given AID and p2 values. See Open Mobile API
693         // Specification v3.2 Section 6.2.7.h and TS 102 221 for details.
694         int p2 = 0x0C; // '0C' for no data returned (TS 102 221 Section 11.1.1.2)
695         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("", p2);
696         final int logicalChannel = response.getChannel();
697         try {
698             verifyValidIccOpenLogicalChannelResponse(response);
699         } finally {
700             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
701         }
702     }
703 
704     @Test
testIccOpenLogicalChannelWithInvalidP2()705     public void testIccOpenLogicalChannelWithInvalidP2() {
706         // Valid p2 values are defined in TS 102 221 Table 11.2. Per Table 11.2, 0xF0 should be
707         // invalid. Any p2 values that produce non '9000'/'62xx'/'63xx' status words are treated as
708         // an error and the channel is not opened. Due to compatibility issues with older devices,
709         // this check is only enabled for new devices launching on Q+.
710         if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) {
711             int p2 = 0xF0;
712             IccOpenLogicalChannelResponse response =
713                     mTelephonyManager.iccOpenLogicalChannel("", p2);
714             final int logicalChannel = response.getChannel();
715             assertThat(logicalChannel).isEqualTo(INVALID_CHANNEL);
716             assertThat(response.getStatus()).isNotEqualTo(STATUS_NO_ERROR);
717         }
718     }
719 
720     /**
721      * Test that it's possible to close logical channels to the ICC. This follows the Manage Channel
722      * command described in TS 102 221 Section 11.1.17.
723      */
724     @Test
testIccCloseLogicalChannel()725     public void testIccCloseLogicalChannel() {
726         // The directory here doesn't matter - we just need to open a valid connection that can
727         // later be closed. In this case, the specified AID ("") opens a channel and selects the MF.
728         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
729 
730         // Check that the select command succeeded. This ensures that the logical channel is indeed
731         // open.
732         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
733         assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isTrue();
734 
735         // Close opened channel twice.
736         assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isFalse();
737 
738         // Channel 0 is guaranteed to be always available and cannot be closed, per TS 102 221
739         // Section 11.1.17
740         assertThat(mTelephonyManager.iccCloseLogicalChannel(0)).isFalse();
741     }
742 
743     /**
744      * This test ensures that valid APDU instructions can be sent and processed by the ICC. To do
745      * so, APDUs are sent to: - get the status of the MF - select the Access Rule Reference (ARR)
746      * for the MF - get the FCP template response for the select
747      */
748     @Test
testIccTransmitApduLogicalChannel()749     public void testIccTransmitApduLogicalChannel() {
750         // An open LC is required for transmitting APDU commands. This opens an LC to the MF.
751         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
752                 mTelephonyManager.iccOpenLogicalChannel("");
753 
754         // Get the status of the current directory. This should match the MF. TS 102 221 Section
755         // 11.1.2
756         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
757 
758         try {
759             int cla = CLA_STATUS;
760             int p1 = 0; // no indication of application status
761             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
762             // above
763             int p3 = 0; // length of 'data' payload
764             String data = "";
765             String response =
766                     mTelephonyManager.iccTransmitApduLogicalChannel(
767                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
768             FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
769             // Check that the FCP Template's file ID matches the MF
770             assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
771             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
772 
773             // Select the Access Rule Reference for the MF. Similar to the MF, this will exist
774             // across all SIM cards. TS 102 221 Section 11.1.1
775             cla = CLA_SELECT;
776             p1 = 0; // select EF by FID
777             p2 = 0x04; // requesting FCP template
778             p3 = 2; // data (FID to be selected) is 2 bytes
779             data = MF_ARR_FILE_ID;
780             response =
781                     mTelephonyManager.iccTransmitApduLogicalChannel(
782                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
783 
784             // Devices launching with Q or later must immediately return the FCP template from the
785             // previous SELECT command. Some devices that launched before Q return TPDUs (instead of
786             // APDUs) - these devices must issue a subsequent GET RESPONSE command to get the FCP
787             // template.
788             if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) {
789                 // Conditionally need to send GET RESPONSE apdu based on response from
790                 // TelephonyManager
791                 if (response.startsWith(STATUS_BYTES_REMAINING)) {
792                     // Read the FCP template from the ICC. TS 102 221 Section 12.1.1
793                     cla = CLA_GET_RESPONSE;
794                     p1 = 0;
795                     p2 = 0;
796                     p3 = 0;
797                     data = "";
798                     response =
799                             mTelephonyManager.iccTransmitApduLogicalChannel(
800                                     logicalChannel, cla, COMMAND_GET_RESPONSE, p1, p2, p3, data);
801                 }
802             }
803 
804             fcpTemplate = FcpTemplate.parseFcpTemplate(response);
805             // Check that the FCP Template's file ID matches the selected ARR
806             assertThat(containsFileId(fcpTemplate, MF_ARR_FILE_ID)).isTrue();
807             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
808         } finally {
809             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
810         }
811     }
812 
813     /**
814      * Tests several invalid APDU instructions over a logical channel and makes sure appropriate
815      * errors are returned from the UICC.
816      */
817     @Test
testIccTransmitApduLogicalChannelWithInvalidInputs()818     public void testIccTransmitApduLogicalChannelWithInvalidInputs() {
819         // An open LC is required for transmitting apdu commands. This opens an LC to the MF.
820         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
821                 mTelephonyManager.iccOpenLogicalChannel("");
822         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
823 
824         try {
825             // Make some invalid APDU commands and make sure they fail as expected.
826             // Use an invalid p1 value for Status apdu
827             int cla = CLA_STATUS | logicalChannel;
828             int p1 = 0xFF; // only '00', '01', and '02' are allowed
829             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
830             // above
831             int p3 = 0; // length of 'data' payload
832             String data = "";
833             String response =
834                     mTelephonyManager.iccTransmitApduLogicalChannel(
835                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
836             assertThat(INVALID_PARAMETERS_STATUSES.contains(response)).isTrue();
837 
838             // Select a file that doesn't exist
839             cla = CLA_SELECT;
840             p1 = 0x00; // select by file ID
841             p2 = 0x0C; // no data returned
842             p3 = 0x02; // length of 'data' payload
843             data = "FFFF"; // invalid file ID
844             response =
845                     mTelephonyManager.iccTransmitApduLogicalChannel(
846                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
847             assertThat(response).isEqualTo(STATUS_FILE_NOT_FOUND);
848 
849             // Manage channel with incorrect p1 parameter
850             cla = CLA_MANAGE_CHANNEL | logicalChannel;
851             p1 = 0x83; // Only '80' or '00' allowed for Manage Channel p1
852             p2 = logicalChannel; // channel to be closed
853             p3 = 0; // length of 'data' payload
854             data = "";
855             response =
856                     mTelephonyManager.iccTransmitApduLogicalChannel(
857                             logicalChannel, cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
858             assertThat(isErrorResponse(response)).isTrue();
859 
860             // Use an incorrect class byte for Status apdu
861             cla = 0xFF;
862             p1 = 0; // no indication of application status
863             p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
864             p3 = 0; // length of 'data' payload
865             data = "";
866             response =
867                     mTelephonyManager.iccTransmitApduLogicalChannel(
868                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
869             assertThat(response).isEqualTo(STATUS_WRONG_CLASS);
870 
871             // Provide a data field that is longer than described for Select apdu
872             cla = CLA_SELECT | logicalChannel;
873             p1 = 0; // select by file ID
874             p2 = 0x0C; // no data returned
875             p3 = 0x04; // data passed is actually 2 bytes long
876             data = "3F00"; // valid ID
877             response =
878                     mTelephonyManager.iccTransmitApduLogicalChannel(
879                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
880             assertThat(isErrorResponse(response)).isTrue();
881 
882             // Use an invalid instruction
883             cla = 0;
884             p1 = 0;
885             p2 = 0;
886             p3 = 0;
887             data = "";
888             int invalidInstruction = 0xFF; // see TS 102 221 Table 10.5 for valid instructions
889             response =
890                     mTelephonyManager.iccTransmitApduLogicalChannel(
891                             logicalChannel, cla, invalidInstruction, p1, p2, p3, data);
892             assertThat(isErrorResponse(response)).isTrue();
893         } finally {
894             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
895         }
896     }
897 
898     /**
899      * This test ensures that files can be read off the UICC. This helps to test the SIM booting
900      * process, as it process involves several file-reads. The ICCID is one of the first files read.
901      */
902     @Test
testApduFileRead()903     public void testApduFileRead() {
904         // Open a logical channel and select the MF.
905         IccOpenLogicalChannelResponse iccOpenLogicalChannel =
906                 mTelephonyManager.iccOpenLogicalChannel("");
907         final int logicalChannel = iccOpenLogicalChannel.getChannel();
908 
909         try {
910             // Select the ICCID. TS 102 221 Section 13.2
911             int p1 = 0; // select by file ID
912             int p2 = 0x0C; // no data returned
913             int p3 = 2; // length of 'data' payload
914             String response =
915                     mTelephonyManager.iccTransmitApduLogicalChannel(
916                             logicalChannel, CLA_SELECT, COMMAND_SELECT, p1, p2, p3, ICCID_FILE_ID);
917             assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
918 
919             // Read the contents of the ICCID.
920             p1 = 0; // 0-byte offset
921             p2 = 0; // 0-byte offset
922             p3 = 0; // length of 'data' payload
923             response =
924                     mTelephonyManager.iccTransmitApduLogicalChannel(
925                             logicalChannel, CLA_READ_BINARY, COMMAND_READ_BINARY, p1, p2, p3, "");
926             assertThat(response).endsWith(STATUS_NORMAL_STRING);
927         } finally {
928             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
929         }
930     }
931 
932     /** This test sends several valid APDU commands over the basic channel (channel 0). */
933     @Test
testIccTransmitApduBasicChannel()934     public void testIccTransmitApduBasicChannel() {
935         // select the MF
936         int cla = CLA_SELECT;
937         int p1 = 0; // select EF by FID
938         int p2 = 0x0C; // requesting FCP template
939         int p3 = 2; // length of 'data' payload
940         String data = MF_FILE_ID;
941         String response =
942                 mTelephonyManager.iccTransmitApduBasicChannel(
943                         cla, COMMAND_SELECT, p1, p2, p3, data);
944         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
945 
946         // get the Status of the current file/directory
947         cla = CLA_STATUS;
948         p1 = 0; // no indication of application status
949         p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
950         p3 = 0; // length of 'data' payload
951         data = "";
952         response =
953                 mTelephonyManager.iccTransmitApduBasicChannel(
954                         cla, COMMAND_STATUS, p1, p2, p3, data);
955         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
956         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
957 
958         // Manually open a logical channel
959         cla = CLA_MANAGE_CHANNEL;
960         p1 = 0; // open a logical channel
961         p2 = 0; // '00' for open command
962         p3 = 0; // length of data payload
963         data = "";
964         response =
965                 mTelephonyManager.iccTransmitApduBasicChannel(
966                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
967         // response is in the format | 1 byte: channel number | 2 bytes: status word |
968         String responseStatus = response.substring(2);
969         assertThat(responseStatus).isEqualTo(STATUS_NORMAL_STRING);
970 
971         // Close the open channel
972         byte[] responseBytes = hexStringToBytes(response);
973         int channel = responseBytes[0];
974         cla = CLA_MANAGE_CHANNEL;
975         p1 = 0x80; // close a logical channel
976         p2 = channel; // the channel to be closed
977         p3 = 0; // length of data payload
978         data = "";
979         response =
980                 mTelephonyManager.iccTransmitApduBasicChannel(
981                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
982         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
983     }
984 
985     /**
986      * This test verifies that {@link TelephonyManager#setLine1NumberForDisplay(String, String)}
987      * correctly sets the Line 1 alpha tag and number when called.
988      */
989     @Test
testLine1NumberForDisplay()990     public void testLine1NumberForDisplay() {
991         // Cache original alpha tag and number values.
992         String originalAlphaTag = mTelephonyManager.getLine1AlphaTag();
993         String originalNumber = mTelephonyManager.getLine1Number();
994 
995         try {
996             // clear any potentially overridden values and cache defaults
997             mTelephonyManager.setLine1NumberForDisplay(null, null);
998             String defaultAlphaTag = mTelephonyManager.getLine1AlphaTag();
999             String defaultNumber = mTelephonyManager.getLine1Number();
1000 
1001             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A)).isTrue();
1002             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_A);
1003             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_A);
1004 
1005             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B)).isTrue();
1006             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_B);
1007             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_B);
1008 
1009             // null is used to clear the Line 1 alpha tag and number values.
1010             assertThat(mTelephonyManager.setLine1NumberForDisplay(null, null)).isTrue();
1011             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(defaultAlphaTag);
1012             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(defaultNumber);
1013         } finally {
1014             // Reset original alpha tag and number values.
1015             mTelephonyManager.setLine1NumberForDisplay(originalAlphaTag, originalNumber);
1016         }
1017     }
1018 
1019     /**
1020      * This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly
1021      * sets the VoiceMail alpha tag and number when called.
1022      */
1023     @Test
testVoiceMailNumber()1024     public void testVoiceMailNumber() {
1025         // Cache original alpha tag and number values.
1026         String originalAlphaTag = mTelephonyManager.getVoiceMailAlphaTag();
1027         String originalNumber = mTelephonyManager.getVoiceMailNumber();
1028 
1029         try {
1030             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A)).isTrue();
1031             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_A);
1032             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_A);
1033 
1034             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B)).isTrue();
1035             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_B);
1036             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_B);
1037         } finally {
1038             // Reset original alpha tag and number values.
1039             mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber);
1040         }
1041     }
1042 
1043     /**
1044      * This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly
1045      * create a group with the given subscription id.
1046      *
1047      * <p>This also verifies that {@link SubscriptionManager#removeSubscriptionsFromGroup(List,
1048      * ParcelUuid)} correctly remove the given subscription group.
1049      */
1050     @Test
testCreateAndRemoveSubscriptionGroup()1051     public void testCreateAndRemoveSubscriptionGroup() {
1052         // Set subscription group with current sub Id.
1053         int subId = SubscriptionManager.getDefaultSubscriptionId();
1054         List<Integer> subGroup = Arrays.asList(subId);
1055         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(subGroup);
1056 
1057         // Getting subscriptions in group.
1058         List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1059 
1060         try {
1061             assertThat(infoList).hasSize(1);
1062             assertThat(infoList.get(0).getGroupUuid()).isEqualTo(uuid);
1063             assertThat(infoList.get(0).getSubscriptionId()).isEqualTo(subId);
1064         } finally {
1065             // Verify that the given subGroup has been removed.
1066             mSubscriptionManager.removeSubscriptionsFromGroup(subGroup, uuid);
1067             infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1068             assertThat(infoList).isEmpty();
1069         }
1070     }
1071 
1072     @Test
testAddSubscriptionToExistingGroupForMultipleSims()1073     public void testAddSubscriptionToExistingGroupForMultipleSims() {
1074         if (mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT
1075                 || mSubscriptionManager.getActiveSubscriptionInfoList().size() < DSDS_PHONE_COUNT) {
1076             // This test requires at least two active subscriptions.
1077             return;
1078         }
1079 
1080         // Set subscription group with current sub Id.
1081         int subId = SubscriptionManager.getDefaultDataSubscriptionId();
1082         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1083         ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
1084                 (sm) -> sm.createSubscriptionGroup(Arrays.asList(subId)));
1085 
1086         try {
1087             // Get all active subscriptions.
1088             List<SubscriptionInfo> activeSubInfos =
1089                     mSubscriptionManager.getActiveSubscriptionInfoList();
1090 
1091             List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
1092             activeSubGroup.removeIf(id -> id == subId);
1093 
1094             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1095                     (sm) -> sm.addSubscriptionsIntoGroup(activeSubGroup, uuid));
1096 
1097             List<Integer> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1098                     mSubscriptionManager,
1099                     (sm) -> getSubscriptionIdList(sm.getSubscriptionsInGroup(uuid)));
1100 
1101             activeSubGroup.add(subId);
1102             assertThat(infoList).hasSize(activeSubGroup.size());
1103             assertThat(infoList).containsExactly(activeSubGroup);
1104         } finally {
1105             removeSubscriptionsFromGroup(uuid);
1106         }
1107     }
1108 
1109     /**
1110      * This test verifies that {@link SubscriptionManager#addSubscriptionsIntoGroup(List,
1111      * ParcelUuid)}} correctly add some additional subscriptions to the existing group.
1112      *
1113      * <p>This test required the device has more than one subscription.
1114      */
1115     @Test
testAddSubscriptionToExistingGroupForEsim()1116     public void testAddSubscriptionToExistingGroupForEsim() {
1117         // Set subscription group with current sub Id.
1118         int subId = SubscriptionManager.getDefaultDataSubscriptionId();
1119         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1120         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(Arrays.asList(subId));
1121 
1122         try {
1123             // Get all accessible eSim subscription.
1124             List<SubscriptionInfo> accessibleSubInfos =
1125                     mSubscriptionManager.getAccessibleSubscriptionInfoList();
1126             if (accessibleSubInfos != null && accessibleSubInfos.size() > 1) {
1127                 List<Integer> accessibleSubGroup = getSubscriptionIdList(accessibleSubInfos);
1128                 accessibleSubGroup.removeIf(id -> id == subId);
1129 
1130                 mSubscriptionManager.addSubscriptionsIntoGroup(accessibleSubGroup, uuid);
1131 
1132                 List<Integer> infoList =
1133                         getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid));
1134                 accessibleSubGroup.add(subId);
1135                 assertThat(infoList).hasSize(accessibleSubGroup.size());
1136                 assertThat(infoList).containsExactly(accessibleSubGroup);
1137             }
1138         } finally {
1139             removeSubscriptionsFromGroup(uuid);
1140         }
1141     }
1142 
1143     /**
1144      * This test verifies that {@link SubscriptionManager#setOpportunistic(boolean, int)} correctly
1145      * set the opportunistic property of the given subscription.
1146      */
1147     @Test
testOpportunistic()1148     public void testOpportunistic() {
1149         int subId = SubscriptionManager.getDefaultDataSubscriptionId();
1150         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1151         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1152         boolean oldOpportunistic = info.isOpportunistic();
1153         boolean newOpportunistic = !oldOpportunistic;
1154 
1155         try {
1156             // Mark the given subscription as opportunistic subscription.
1157             assertThat(mSubscriptionManager.setOpportunistic(newOpportunistic, subId)).isTrue();
1158 
1159             // Verify that the given subscription is opportunistic subscription.
1160             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1161             assertThat(info.isOpportunistic()).isEqualTo(newOpportunistic);
1162         } finally {
1163             // Set back to original opportunistic property.
1164             mSubscriptionManager.setOpportunistic(oldOpportunistic, subId);
1165             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1166             assertThat(info.isOpportunistic()).isEqualTo(oldOpportunistic);
1167         }
1168     }
1169 
1170     /**
1171      * This test verifies that {@link TelephonyManager#iccExchangeSimIO(int, int, int, int, int,
1172      * String)} correctly transmits iccIO commands to the UICC card. First, the MF is selected via a
1173      * SELECT apdu via the basic channel, then a STATUS AT-command is sent.
1174      */
1175     @Test
testIccExchangeSimIO()1176     public void testIccExchangeSimIO() {
1177         // select the MF first. This makes sure the next STATUS AT-command returns a FCP template
1178         // for the right file.
1179         int cla = CLA_SELECT;
1180         int p1 = 0; // select EF by FID
1181         int p2 = 0x0C; // requesting FCP template
1182         int p3 = 2; // length of 'data' payload
1183         String data = MF_FILE_ID;
1184         String response =
1185                 mTelephonyManager.iccTransmitApduBasicChannel(
1186                         cla, COMMAND_SELECT, p1, p2, p3, data);
1187         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1188 
1189         // The iccExchangeSimIO command implements the +CRSM command defined in TS 27.007 section
1190         // 8.18. A STATUS command is sent and the returned value will be an FCP template.
1191         byte[] result =
1192                 mTelephonyManager.iccExchangeSimIO(
1193                         0, // fileId: not required for STATUS
1194                         COMMAND_STATUS, // command: STATUS
1195                         0, // p1: not required for STATUS
1196                         0, // p2: not required for STATUS
1197                         0, // p3: not required for STATUS
1198                         ""); // filePath: not required for STATUS
1199         String resultString = bytesToHexString(result);
1200         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
1201         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
1202         assertWithMessage("iccExchangeSimIO returned non-normal Status byte: %s", resultString)
1203                 .that(fcpTemplate.getStatus())
1204                 .isEqualTo(STATUS_NORMAL_STRING);
1205     }
1206 
1207     /**
1208      * This test checks that a STATUS apdu can be sent as an encapsulated envelope to the UICC via
1209      * {@link TelephonyManager#sendEnvelopeWithStatus(String)}.
1210      */
1211     @Test
testSendEnvelopeWithStatus()1212     public void testSendEnvelopeWithStatus() {
1213         // STATUS apdu as hex String
1214         String envelope =
1215                 CLA_STATUS_STRING
1216                         + COMMAND_STATUS_STRING
1217                         + "00" // p1: no indication of application status
1218                         + "00"; // p2: identical parameters to
1219         String response = mTelephonyManager.sendEnvelopeWithStatus(envelope);
1220 
1221         // TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope
1222         assertWithMessage("sendEnvelopeWithStatus is null for envelope=%s", envelope)
1223                 .that(response)
1224                 .isNotNull();
1225     }
1226 
1227     /**
1228      * This test checks that applications with carrier privilege can set/clear signal strength
1229      * update request via {@link
1230      * TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and {@link
1231      * TelephonyManager#clearSignalStrengthUpdateRequest} without {@link
1232      * android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
1233      */
1234     @Test
testSetClearSignalStrengthUpdateRequest()1235     public void testSetClearSignalStrengthUpdateRequest() {
1236         final SignalStrengthUpdateRequest request =
1237                 new SignalStrengthUpdateRequest.Builder()
1238                         .setSignalThresholdInfos(
1239                                 List.of(
1240                                         new SignalThresholdInfo.Builder()
1241                                                 .setRadioAccessNetworkType(
1242                                                         AccessNetworkConstants.AccessNetworkType
1243                                                                 .GERAN)
1244                                                 .setSignalMeasurementType(
1245                                                         SignalThresholdInfo
1246                                                                 .SIGNAL_MEASUREMENT_TYPE_RSSI)
1247                                                 .setThresholds(new int[] {-113, -103, -97, -51})
1248                                                 .build()))
1249                         .setReportingRequestedWhileIdle(true)
1250                         .build();
1251         try {
1252             mTelephonyManager.setSignalStrengthUpdateRequest(request);
1253         } finally {
1254             mTelephonyManager.clearSignalStrengthUpdateRequest(request);
1255         }
1256     }
1257 
verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response)1258     private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
1259         // The assigned channel should be between the min and max allowed channel numbers
1260         int channel = response.getChannel();
1261         assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, MAX_LOGICAL_CHANNEL));
1262         assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
1263         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
1264     }
1265 
removeSubscriptionsFromGroup(ParcelUuid uuid)1266     private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
1267         List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1268         if (!infoList.isEmpty()) {
1269             List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
1270             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1271                     (sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
1272         }
1273         infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1274         assertThat(infoList).isEmpty();
1275     }
1276 
getSubscriptionIdList(List<SubscriptionInfo> subInfoList)1277     private List<Integer> getSubscriptionIdList(List<SubscriptionInfo> subInfoList) {
1278         if (subInfoList == null || subInfoList.isEmpty()) return Collections.EMPTY_LIST;
1279         return subInfoList.stream()
1280                 .map(info -> info.getSubscriptionId())
1281                 .collect(Collectors.toList());
1282     }
1283 
1284     /**
1285      * Checks whether the a {@code fcpTemplate} contains the given {@code fileId}.
1286      *
1287      * @param fcpTemplate The FCP Template to be checked.
1288      * @param fileId The file ID that is being searched for
1289      * @return true iff fcpTemplate contains fileId.
1290      */
containsFileId(FcpTemplate fcpTemplate, String fileId)1291     private boolean containsFileId(FcpTemplate fcpTemplate, String fileId) {
1292         return fcpTemplate.getTlvs().stream()
1293                 .anyMatch(tlv -> tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId));
1294     }
1295 
1296     /**
1297      * Returns true iff {@code response} indicates an error with the previous APDU.
1298      *
1299      * @param response The APDU response to be checked.
1300      * @return true iff the given response indicates an error occurred
1301      */
isErrorResponse(@onnull String response)1302     private boolean isErrorResponse(@Nonnull String response) {
1303         return !(STATUS_NORMAL_STRING.equals(response)
1304                 || response.startsWith(STATUS_WARNING_A)
1305                 || response.startsWith(STATUS_WARNING_B)
1306                 || response.startsWith(STATUS_BYTES_REMAINING));
1307     }
1308 
1309     private static class IntentReceiver extends BroadcastReceiver {
1310         private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
1311 
1312         @Override
onReceive(Context context, Intent intent)1313         public void onReceive(Context context, Intent intent) {
1314             mReceiveLatch.countDown();
1315         }
1316 
waitForReceive()1317         public boolean waitForReceive() throws InterruptedException {
1318             return mReceiveLatch.await(30, TimeUnit.SECONDS);
1319         }
1320     }
1321 
1322     @Test
testEapSimAuthentication()1323     public void testEapSimAuthentication() {
1324         assumeTrue(
1325                 "testEapSimAuthentication requires a 2021 CTS UICC or newer",
1326                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1327         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1328         // n: 128 (Bits to use for RES value)
1329         // Format: [Length][RAND]
1330         String challenge = "10" + EAP_SIM_AKA_RAND;
1331         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1332         String base64Response =
1333                 mTelephonyManager.getIccAuthentication(
1334                         TelephonyManager.APPTYPE_USIM,
1335                         TelephonyManager.AUTHTYPE_EAP_SIM,
1336                         base64Challenge);
1337         byte[] response = Base64.decode(base64Response, Base64.DEFAULT);
1338         assertWithMessage("Results for AUTHTYPE_EAP_SIM failed")
1339                 .that(response)
1340                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_SIM_RESULT));
1341     }
1342 
1343     @Test
testEapAkaAuthentication()1344     public void testEapAkaAuthentication() {
1345         assumeTrue(
1346                 "testEapAkaAuthentication requires a 2021 CTS UICC or newer",
1347                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1348         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1349         // n: 128 (Bits to use for RES value)
1350         // Format: [Length][Rand][Length][Autn]
1351         String challenge = "10" + EAP_SIM_AKA_RAND + "10" + EAP_AKA_AUTN;
1352         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1353         String base64Response =
1354                 mTelephonyManager.getIccAuthentication(
1355                         TelephonyManager.APPTYPE_USIM,
1356                         TelephonyManager.AUTHTYPE_EAP_AKA,
1357                         base64Challenge);
1358 
1359         assertWithMessage("UICC returned null for EAP-AKA auth").that(base64Response).isNotNull();
1360         byte[] response = Base64.decode(base64Response, Base64.NO_WRAP);
1361 
1362         // response may be formatted as: [DB][Length][RES][Length][CK][Length][IK][Length][Kc]
1363         byte[] akaResponse = Arrays.copyOfRange(response, 0, EAP_AKA_RESPONSE_LENGTH);
1364         assertWithMessage("Results for AUTHTYPE_EAP_AKA failed")
1365                 .that(akaResponse)
1366                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_AKA_RESULT));
1367     }
1368 }
1369