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