Home | History | Annotate | Download | only in cts
      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
    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
    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      */
    195     private boolean hasCellular() {
    196         return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) &&
    197                 mTelephonyManager.getPhoneCount() > 0;
    198     }
    199 
    200     private boolean isSimCardPresent() {
    201         return mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE &&
    202                 mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
    203     }
    204 
    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 
    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 
    229     public void testSimCardPresent() {
    230         if (!hasCellular) return;
    231         assertTrue("This test requires SIM card.", isSimCardPresent());
    232     }
    233 
    234     public void testHasCarrierPrivileges() {
    235         if (!hasCellular) return;
    236         if (!mTelephonyManager.hasCarrierPrivileges()) {
    237             failMessage();
    238         }
    239     }
    240 
    241     private static void assertUpdateAvailableNetworkSuccess(int value) {
    242         assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS, value);
    243     }
    244 
    245     private static void assertUpdateAvailableNetworkInvalidArguments(int value) {
    246         assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS, value);
    247     }
    248 
    249     private static void assertSetOpportunisticSubSuccess(int value) {
    250         assertEquals(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS, value);
    251     }
    252 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
   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      */
   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      */
   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 
   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 
   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 
   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      */
   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      */
   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
   1167         public void onReceive(Context context, Intent intent) {
   1168             mReceiveLatch.countDown();
   1169         }
   1170 
   1171         public boolean waitForReceive() throws InterruptedException {
   1172             return mReceiveLatch.await(30, TimeUnit.SECONDS);
   1173         }
   1174     }
   1175 }
   1176