• 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.carrierapi.cts.IccUtils.isSeriouslyLetterOrDigit;
23 import static android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL;
24 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_MISSING_RESOURCE;
25 import static android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
26 import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER;
27 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_THERMAL;
28 import static android.telephony.TelephonyManager.DATA_ENABLED_REASON_USER;
29 
30 import static com.android.compatibility.common.util.UiccUtil.UiccCertificate.CTS_UICC_2021;
31 
32 import static com.google.common.truth.Truth.assertThat;
33 import static com.google.common.truth.Truth.assertWithMessage;
34 
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertNotNull;
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assert.fail;
39 import static org.junit.Assume.assumeFalse;
40 import static org.junit.Assume.assumeNoException;
41 import static org.junit.Assume.assumeTrue;
42 
43 import android.content.BroadcastReceiver;
44 import android.content.ContentProviderClient;
45 import android.content.ContentValues;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.IntentFilter;
49 import android.content.pm.PackageManager;
50 import android.database.Cursor;
51 import android.net.Uri;
52 import android.os.AsyncTask;
53 import android.os.Build;
54 import android.os.Handler;
55 import android.os.HandlerThread;
56 import android.os.ParcelUuid;
57 import android.os.PersistableBundle;
58 import android.platform.test.annotations.SystemUserOnly;
59 import android.platform.test.flag.junit.CheckFlagsRule;
60 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
61 import android.provider.Telephony;
62 import android.provider.VoicemailContract;
63 import android.telephony.AccessNetworkConstants;
64 import android.telephony.AvailableNetworkInfo;
65 import android.telephony.CarrierConfigManager;
66 import android.telephony.IccOpenLogicalChannelResponse;
67 import android.telephony.PhoneStateListener;
68 import android.telephony.SignalStrengthUpdateRequest;
69 import android.telephony.SignalThresholdInfo;
70 import android.telephony.SubscriptionInfo;
71 import android.telephony.SubscriptionManager;
72 import android.telephony.SubscriptionPlan;
73 import android.telephony.TelephonyManager;
74 import android.telephony.data.NetworkSlicingConfig;
75 import android.telephony.ims.ImsException;
76 import android.telephony.ims.ImsManager;
77 import android.telephony.ims.ImsMmTelManager;
78 import android.telephony.ims.ImsStateCallback;
79 import android.telephony.ims.RegistrationManager;
80 import android.util.Base64;
81 import android.util.Log;
82 
83 import androidx.test.runner.AndroidJUnit4;
84 
85 import com.android.compatibility.common.util.MediaUtils;
86 import com.android.compatibility.common.util.PollingCheck;
87 import com.android.compatibility.common.util.ShellIdentityUtils;
88 import com.android.compatibility.common.util.UiccUtil;
89 import com.android.internal.telephony.flags.Flags;
90 
91 import com.google.common.collect.Range;
92 
93 import org.junit.After;
94 import org.junit.Before;
95 import org.junit.Rule;
96 import org.junit.Test;
97 import org.junit.runner.RunWith;
98 
99 import java.io.IOException;
100 import java.time.ZonedDateTime;
101 import java.util.ArrayList;
102 import java.util.Arrays;
103 import java.util.Collections;
104 import java.util.HashSet;
105 import java.util.List;
106 import java.util.Set;
107 import java.util.concurrent.CompletableFuture;
108 import java.util.concurrent.CountDownLatch;
109 import java.util.concurrent.TimeUnit;
110 import java.util.concurrent.atomic.AtomicReference;
111 import java.util.function.Consumer;
112 import java.util.stream.Collectors;
113 
114 import javax.annotation.Nonnull;
115 
116 /**
117  * Unit tests for various carrier-related APIs.
118  *
119  * <p>Test using `atest CtsCarrierApiTestCases:CarrierApiTest` or `make cts -j64 && cts-tradefed run
120  * cts -m CtsCarrierApiTestCases --test android.carrierapi.cts.CarrierApiTest`
121  */
122 // TODO(b/130187425): Split CarrierApiTest apart to have separate test classes for functionality
123 @RunWith(AndroidJUnit4.class)
124 public class CarrierApiTest extends BaseCarrierApiTest {
125     @Rule
126     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
127 
128     private static final String TAG = "CarrierApiTest";
129 
130     private TelephonyManager mTelephonyManager;
131     private CarrierConfigManager mCarrierConfigManager;
132     private SubscriptionManager mSubscriptionManager;
133     private ContentProviderClient mVoicemailProvider;
134     private ContentProviderClient mStatusProvider;
135     private PackageManager mPackageManager;
136     private Uri mVoicemailContentUri;
137     private Uri mStatusContentUri;
138     private String selfPackageName;
139     private HandlerThread mListenerThread;
140     private ImsManager mImsManager;
141     private ImsMmTelManager mMmTelManager;
142 
143     private static final int MAX_RETRIES = 10;
144     // The minimum allocatable logical channel number, per TS 102 221 Section 11.1.17.1
145     private static final int MIN_LOGICAL_CHANNEL = 1;
146     // The maximum allocatable logical channel number in the standard range, per TS 102 221 Section
147     // 11.1.17.1
148     private static final int MAX_LOGICAL_CHANNEL = 3;
149     private static final int MAX_LOGICAL_CHANNEL_EXTENDED = 19;
150     // Class bytes. The logical channel used should be included for bits b2b1. TS 102 221 Table 11.5
151     private static final int CLA_GET_RESPONSE = 0x00;
152     private static final int CLA_MANAGE_CHANNEL = 0x00;
153     private static final int CLA_READ_BINARY = 0x00;
154     private static final int CLA_SELECT = 0x00;
155     private static final int CLA_STATUS = 0x80;
156     private static final String CLA_STATUS_STRING = "80";
157     // APDU Instruction Bytes. TS 102 221 Section 10.1.2
158     private static final int COMMAND_GET_RESPONSE = 0xC0;
159     private static final int COMMAND_MANAGE_CHANNEL = 0x70;
160     private static final int COMMAND_READ_BINARY = 0xB0;
161     private static final int COMMAND_SELECT = 0xA4;
162     private static final int COMMAND_STATUS = 0xF2;
163     private static final String COMMAND_STATUS_STRING = "F2";
164     // Status words. TS 102 221 Section 10.2.1
165     private static final byte[] STATUS_NORMAL = {(byte) 0x90, (byte) 0x00};
166     private static final String STATUS_NORMAL_STRING = "9000";
167     private static final String STATUS_BYTES_REMAINING = "61";
168     private static final String STATUS_WARNING_A = "62";
169     private static final String STATUS_WARNING_B = "63";
170     private static final String STATUS_CHANNEL_NOT_SUPPORTED = "6881";
171     private static final String STATUS_FILE_NOT_FOUND = "6a82";
172     private static final String STATUS_INCORRECT_PARAMETERS = "6a86";
173     private static final String STATUS_WRONG_PARAMETERS = "6b00";
174     private static final Set<String> INVALID_PARAMETERS_STATUSES =
175             new HashSet<>(Arrays.asList(STATUS_INCORRECT_PARAMETERS, STATUS_WRONG_PARAMETERS));
176     private static final String STATUS_WRONG_CLASS = "6e00";
177     private static final String STATUS_TECHNICAL_PROBLEM = "6f00";
178     // File ID for the EF ICCID. TS 102 221
179     private static final String ICCID_FILE_ID = "2FE2";
180     // File ID for the EF_PL. TS 131 102 Annex A
181     private static final String PL_FILE_ID = "2F05";
182     // File ID for the master file. TS 102 221
183     private static final String MF_FILE_ID = "3F00";
184     private static final int MF_FILE_ID_HEX = 0x3F00;
185     // File ID for the MF Access Rule Reference. TS 102 221
186     private static final String MF_ARR_FILE_ID = "2F06";
187     private static final String ALPHA_TAG_A = "tagA";
188     private static final String ALPHA_TAG_B = "tagB";
189     private static final String NUMBER_A = "1234567890";
190     private static final String NUMBER_B = "0987654321";
191     private static final String TESTING_PLMN = "12345";
192     private static final int PL_ENTRY_LENGTH = 2;
193     private static final int HEX_BYTES_PER_CHAR = 2;
194 
195     private static final String EAP_SIM_AKA_RAND = "11111111111111111111111111111111";
196 
197     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
198     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2
199     private static final String EAP_AKA_AUTN = "12351417161900001130131215141716";
200 
201     // EAP-AKA Response Format: [DB][Length][RES][Length][CK][Length][IK]
202     private static final int EAP_AKA_RESPONSE_LENGTH = 1 + 1 + 16 + 1 + 16 + 1 + 16;
203 
204     // Derived from TS 134 108#8.1.2. Based on EAP_SIM_AKA_RAND and assumed K value of
205     // 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
206     // Format: [DB][Length][RES][Length][CK][Length][IK]
207     private static final String EXPECTED_EAP_AKA_RESULT =
208             "DB10111013121514171619181B1A1D1C1F1E"
209                     + "101013121514171619181B1A1D1C1F1E11"
210                     + "1013121514171619181B1A1D1C1F1E1110";
211 
212     // Derived from TS 134 108#8.1.2 and TS 133 102#6.8.1.2. Based on EAP_SIM_AKA_RAND and assumed K
213     // value of 000102030405060708090A0B0C0D0E0F, per TS 134 108#8.2.
214     // Format: [Length][SRES][Length][Kc]
215     private static final String EXPECTED_EAP_SIM_RESULT = "0400000000080000000000000000";
216 
217     private static final int DSDS_PHONE_COUNT = 2;
218     private static final String PLMN_A = "123456";
219     private static final String PLMN_B = "78901";
220     private static final List<String> FPLMN_TEST = Arrays.asList(PLMN_A, PLMN_B);
221     private static final int MAX_FPLMN_NUM = 1000;
222     private static final int MIN_FPLMN_NUM = 3;
223 
224     private static final ZonedDateTime SUB_PLAN_START =
225             ZonedDateTime.parse("2024-01-01T00:00:00.000Z");
226     private static final ZonedDateTime SUB_PLAN_END =
227             ZonedDateTime.parse("2029-12-31T00:00:00.000Z");
228     private static final CharSequence SUB_PLAN_TITLE = "CTS test subscription plan";
229     private static final CharSequence SUB_PLAN_SUMMARY = "CTS test subscription plan summary";
230     private static final long SUB_PLAN_EXPIRATION_DURATION = 36000L;
231     private static final long SUB_PLAN_DATA_LIMIT_BYTES = 1200000L;
232 
233     @Before
setUp()234     public void setUp() throws Exception {
235         Context context = getContext();
236         mTelephonyManager = context.getSystemService(TelephonyManager.class);
237         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
238         mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
239         selfPackageName = context.getPackageName();
240         mVoicemailContentUri = VoicemailContract.Voicemails.buildSourceUri(selfPackageName);
241         mVoicemailProvider =
242                 context.getContentResolver().acquireContentProviderClient(mVoicemailContentUri);
243         mStatusContentUri = VoicemailContract.Status.buildSourceUri(selfPackageName);
244         mStatusProvider =
245                 context.getContentResolver().acquireContentProviderClient(mStatusContentUri);
246         mPackageManager = context.getPackageManager();
247         mImsManager = context.getSystemService(ImsManager.class);
248         if (mImsManager != null) {
249             final int subId = SubscriptionManager.getDefaultSubscriptionId();
250             mMmTelManager = mImsManager.getImsMmTelManager(subId);
251         }
252         mListenerThread = new HandlerThread("CarrierApiTest");
253         mListenerThread.start();
254     }
255 
256     @After
tearDown()257     public void tearDown() throws Exception {
258         if (!werePreconditionsSatisfied()) return;
259 
260         if (mListenerThread != null) {
261             mListenerThread.quit();
262         }
263         try {
264             mStatusProvider.delete(mStatusContentUri, null, null);
265             mVoicemailProvider.delete(mVoicemailContentUri, null, null);
266         } catch (Exception e) {
267             Log.w(TAG, "Failed to clean up voicemail tables in tearDown", e);
268         }
269     }
270 
271     @Test
testSimCardPresent()272     public void testSimCardPresent() {
273         assertWithMessage("This test requires a SIM card")
274                 .that(mTelephonyManager.getSimState())
275                 .isNotEqualTo(TelephonyManager.SIM_STATE_ABSENT);
276     }
277 
278     @Test
testHasCarrierPrivileges()279     public void testHasCarrierPrivileges() {
280         assertWithMessage(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE)
281                 .that(mTelephonyManager.hasCarrierPrivileges())
282                 .isTrue();
283     }
284 
assertUpdateAvailableNetworkSuccess(int value)285     private static void assertUpdateAvailableNetworkSuccess(int value) {
286         assertThat(value).isEqualTo(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS);
287     }
288 
assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value)289     private static void assertUpdateAvailableNetworkNoOpportunisticSubAvailable(int value) {
290         assertThat(value)
291                 .isEqualTo(
292                         TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE);
293     }
294 
assertSetOpportunisticSubSuccess(int value)295     private static void assertSetOpportunisticSubSuccess(int value) {
296         assertThat(value).isEqualTo(TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS);
297     }
298 
getFirstActivateCarrierPrivilegedSubscriptionId()299     private int getFirstActivateCarrierPrivilegedSubscriptionId() {
300         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
301         List<SubscriptionInfo> subscriptionInfos =
302                 mSubscriptionManager.getActiveSubscriptionInfoList();
303         if (subscriptionInfos != null) {
304             for (SubscriptionInfo info : subscriptionInfos) {
305                 TelephonyManager telephonyManager =
306                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
307                 if (telephonyManager.hasCarrierPrivileges()) {
308                     subId = info.getSubscriptionId();
309                     return subId;
310                 }
311             }
312         }
313         return subId;
314     }
315 
316     @Test
testUpdateAvailableNetworksWithCarrierPrivilege()317     public void testUpdateAvailableNetworksWithCarrierPrivilege() {
318         int subIdWithCarrierPrivilege = getFirstActivateCarrierPrivilegedSubscriptionId();
319         int activeSubscriptionInfoCount =
320                 ShellIdentityUtils.invokeMethodWithShellPermissions(
321                         mSubscriptionManager, (tm) -> tm.getActiveSubscriptionInfoCount());
322         if (mTelephonyManager.getPhoneCount() == 1) {
323             return;
324         }
325 
326         /* TODO: b/145993690 */
327         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
328             /* This test requires two SIM cards */
329             return;
330         }
331         if (subIdWithCarrierPrivilege == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
332             /* This test requires SIM with carrier privilege */
333             return;
334         }
335 
336         List<SubscriptionInfo> subscriptionInfoList =
337                 mSubscriptionManager.getOpportunisticSubscriptions();
338         List<String> mccMncs = new ArrayList<String>();
339         List<Integer> bands = new ArrayList<Integer>();
340         List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>();
341         Consumer<Integer> callbackSuccess = CarrierApiTest::assertUpdateAvailableNetworkSuccess;
342         Consumer<Integer> callbackNoOpportunisticSubAvailable =
343                 CarrierApiTest::assertUpdateAvailableNetworkNoOpportunisticSubAvailable;
344         Consumer<Integer> setOpCallbackSuccess = CarrierApiTest::assertSetOpportunisticSubSuccess;
345         if (subscriptionInfoList == null
346                 || subscriptionInfoList.size() == 0
347                 || !mSubscriptionManager.isActiveSubscriptionId(
348                         subscriptionInfoList.get(0).getSubscriptionId())) {
349             try {
350                 AvailableNetworkInfo availableNetworkInfo =
351                         new AvailableNetworkInfo(
352                                 subIdWithCarrierPrivilege,
353                                 AvailableNetworkInfo.PRIORITY_HIGH,
354                                 mccMncs,
355                                 bands);
356                 availableNetworkInfos.add(availableNetworkInfo);
357                 // Call updateAvailableNetworks without opportunistic subscription.
358                 // callbackNoOpportunisticSubAvailable is expected to be triggered
359                 // and the return value will be checked against
360                 // UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE
361                 mTelephonyManager.updateAvailableNetworks(
362                         availableNetworkInfos,
363                         AsyncTask.SERIAL_EXECUTOR,
364                         callbackNoOpportunisticSubAvailable);
365             } finally {
366                 // clear all the operations at the end of test.
367                 availableNetworkInfos.clear();
368                 mTelephonyManager.updateAvailableNetworks(
369                         availableNetworkInfos,
370                         AsyncTask.SERIAL_EXECUTOR,
371                         callbackNoOpportunisticSubAvailable);
372             }
373         } else {
374             // This is case of DSDS phone, one active opportunistic subscription and one
375             // active primary subscription.
376             int resultSubId;
377             try {
378                 AvailableNetworkInfo availableNetworkInfo =
379                         new AvailableNetworkInfo(
380                                 subscriptionInfoList.get(0).getSubscriptionId(),
381                                 AvailableNetworkInfo.PRIORITY_HIGH,
382                                 mccMncs,
383                                 bands);
384                 availableNetworkInfos.add(availableNetworkInfo);
385                 mTelephonyManager.updateAvailableNetworks(
386                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
387                 // wait for the data change to take effect
388                 waitForMs(500);
389                 // Call setPreferredData and reconfirm with getPreferred data
390                 // that the same is updated.
391                 int preferSubId = subscriptionInfoList.get(0).getSubscriptionId();
392                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
393                         preferSubId, false, AsyncTask.SERIAL_EXECUTOR, setOpCallbackSuccess);
394                 // wait for the data change to take effect
395                 waitForMs(500);
396                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
397                 assertThat(resultSubId).isEqualTo(preferSubId);
398             } finally {
399                 // clear all the operations at the end of test.
400                 availableNetworkInfos.clear();
401                 mTelephonyManager.updateAvailableNetworks(
402                         availableNetworkInfos, AsyncTask.SERIAL_EXECUTOR, callbackSuccess);
403                 waitForMs(500);
404                 mTelephonyManager.setPreferredOpportunisticDataSubscription(
405                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
406                         false,
407                         AsyncTask.SERIAL_EXECUTOR,
408                         callbackSuccess);
409                 waitForMs(500);
410                 resultSubId = mTelephonyManager.getPreferredOpportunisticDataSubscription();
411                 assertThat(resultSubId).isEqualTo(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
412             }
413         }
414     }
415 
waitForMs(long ms)416     public static void waitForMs(long ms) {
417         try {
418             Thread.sleep(ms);
419         } catch (InterruptedException e) {
420             Log.d(TAG, "InterruptedException while waiting: " + e);
421         }
422     }
423 
424     @Test
testGetIccAuthentication()425     public void testGetIccAuthentication() {
426         // EAP-SIM rand is 16 bytes.
427         String base64Challenge = "ECcTqwuo6OfY8ddFRboD9WM=";
428         String base64Challenge2 = "EMNxjsFrPCpm+KcgCmQGnwQ=";
429 
430         try {
431             assertWithMessage("getIccAuthentication should return null for empty data.")
432                     .that(
433                             mTelephonyManager.getIccAuthentication(
434                                     TelephonyManager.APPTYPE_USIM,
435                                     TelephonyManager.AUTHTYPE_EAP_AKA,
436                                     ""))
437                     .isNull();
438             String response =
439                     mTelephonyManager.getIccAuthentication(
440                             TelephonyManager.APPTYPE_USIM,
441                             TelephonyManager.AUTHTYPE_EAP_SIM,
442                             base64Challenge);
443             assertWithMessage("UICC returned null for EAP-SIM auth").that(response).isNotNull();
444             // response is base64 encoded. After decoding, the value should be:
445             // 1 length byte + SRES(4 bytes) + 1 length byte + Kc(8 bytes)
446             byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT);
447             assertThat(result).hasLength(14);
448             String response2 =
449                     mTelephonyManager.getIccAuthentication(
450                             TelephonyManager.APPTYPE_USIM,
451                             TelephonyManager.AUTHTYPE_EAP_SIM,
452                             base64Challenge2);
453             assertWithMessage("Two responses must be different")
454                     .that(response)
455                     .isNotEqualTo(response2);
456         } catch (UnsupportedOperationException e) {
457             assumeNoException("EAP-SIM/AKA not supported", e);
458         } catch (SecurityException e) {
459             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
460         }
461     }
462 
463     @Test
464     @SystemUserOnly(reason = "b/177921545, broadcast sent only to primary user")
testSendDialerSpecialCode()465     public void testSendDialerSpecialCode() {
466         assumeTrue(hasTelephonyCalling());
467 
468         IntentReceiver intentReceiver = new IntentReceiver();
469         final IntentFilter intentFilter = new IntentFilter();
470         intentFilter.addAction(Telephony.Sms.Intents.SECRET_CODE_ACTION);
471         intentFilter.addDataScheme("android_secret_code");
472 
473         Context context = getContext();
474         context.registerReceiver(intentReceiver, intentFilter);
475         try {
476             mTelephonyManager.sendDialerSpecialCode("4636");
477             assertWithMessage(
478                             "Did not receive expected Intent: "
479                                     + Telephony.Sms.Intents.SECRET_CODE_ACTION)
480                     .that(intentReceiver.waitForReceive())
481                     .isTrue();
482         } catch (SecurityException e) {
483             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
484         } catch (InterruptedException e) {
485             Log.d(TAG, "Broadcast receiver wait was interrupted.");
486         } finally {
487             context.unregisterReceiver(intentReceiver);
488         }
489     }
490 
491     @Test
testSubscriptionInfoListing()492     public void testSubscriptionInfoListing() {
493         try {
494             assertThat(mSubscriptionManager.getActiveSubscriptionInfoCount()).isGreaterThan(0);
495             List<SubscriptionInfo> subInfoList =
496                     mSubscriptionManager.getActiveSubscriptionInfoList();
497             assertWithMessage("getActiveSubscriptionInfoList() returned null")
498                     .that(subInfoList)
499                     .isNotNull();
500             assertWithMessage("getActiveSubscriptionInfoList() returned an empty list")
501                     .that(subInfoList)
502                     .isNotEmpty();
503             for (SubscriptionInfo info : subInfoList) {
504                 TelephonyManager tm =
505                         mTelephonyManager.createForSubscriptionId(info.getSubscriptionId());
506                 assertWithMessage(
507                                 "getActiveSubscriptionInfoList() returned an inaccessible"
508                                         + " subscription")
509                         .that(tm.hasCarrierPrivileges())
510                         .isTrue();
511 
512                 // Check other APIs to make sure they are accessible and return consistent info.
513                 SubscriptionInfo infoForSlot =
514                         mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
515                                 info.getSimSlotIndex());
516                 assertWithMessage("getActiveSubscriptionInfoForSimSlotIndex() returned null")
517                         .that(infoForSlot)
518                         .isNotNull();
519                 assertWithMessage(
520                                 "getActiveSubscriptionInfoForSimSlotIndex() returned inconsistent"
521                                         + " info")
522                         .that(infoForSlot.getSubscriptionId())
523                         .isEqualTo(info.getSubscriptionId());
524 
525                 SubscriptionInfo infoForSubId =
526                         mSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId());
527                 assertWithMessage("getActiveSubscriptionInfo() returned null")
528                         .that(infoForSubId)
529                         .isNotNull();
530                 assertWithMessage("getActiveSubscriptionInfo() returned inconsistent info")
531                         .that(infoForSubId.getSubscriptionId())
532                         .isEqualTo(info.getSubscriptionId());
533             }
534         } catch (SecurityException e) {
535             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
536         }
537     }
538 
539     @Test
testCarrierConfigIsAccessible()540     public void testCarrierConfigIsAccessible() {
541         try {
542             PersistableBundle bundle = mCarrierConfigManager.getConfig();
543             assertWithMessage("CarrierConfigManager#getConfig() returned null")
544                     .that(bundle)
545                     .isNotNull();
546             assertWithMessage("CarrierConfigManager#getConfig() returned empty bundle")
547                     .that(bundle.isEmpty())
548                     .isFalse();
549 
550             int subId = SubscriptionManager.getDefaultSubscriptionId();
551             bundle = mCarrierConfigManager.getConfigForSubId(subId);
552             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned null")
553                     .that(bundle)
554                     .isNotNull();
555             assertWithMessage("CarrierConfigManager#getConfigForSubId() returned empty bundle")
556                     .that(bundle.isEmpty())
557                     .isFalse();
558         } catch (SecurityException e) {
559             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
560         }
561     }
562 
563     @Test
testTelephonyApisAreAccessibleWithFeatureMapping()564     public void testTelephonyApisAreAccessibleWithFeatureMapping() {
565         // The following methods may return any value depending on the state of the device. Simply
566         // call them to make sure they do not throw any exceptions. Methods that return a device
567         // identifier will be accessible to apps with carrier privileges in Q, but this may change
568         // in a future release.
569         try {
570             mTelephonyManager.getDeviceId();
571             mTelephonyManager.getDeviceSoftwareVersion();
572             mTelephonyManager.getImei();
573 
574             if (hasFeature(PackageManager.FEATURE_TELEPHONY_CDMA)) {
575                 mTelephonyManager.getMeid();
576             }
577             if (hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
578                 mTelephonyManager.getNai();
579                 mTelephonyManager.getSimSerialNumber();
580                 mTelephonyManager.getSubscriberId();
581                 mTelephonyManager.getGroupIdLevel1();
582                 mTelephonyManager.getLine1Number();
583                 mTelephonyManager.getForbiddenPlmns();
584                 mTelephonyManager.setForbiddenPlmns(new ArrayList<String>());
585                 // TODO(b/235490259): test all slots once TM#isModemEnabledForSlot allows
586                 mTelephonyManager.isModemEnabledForSlot(
587                         SubscriptionManager.getSlotIndex(mTelephonyManager.getSubscriptionId()));
588             }
589             if (hasFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) {
590                 mTelephonyManager.getDataNetworkType();
591                 mTelephonyManager.getServiceState();
592                 mTelephonyManager.getManualNetworkSelectionPlmn();
593             }
594             if (hasFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) {
595                 mTelephonyManager.getVoiceNetworkType();
596                 mTelephonyManager.getVoiceMailNumber();
597                 mTelephonyManager.getVisualVoicemailPackageName();
598                 mTelephonyManager.getVoiceMailAlphaTag();
599             }
600         } catch (SecurityException e) {
601             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
602         }
603     }
604 
605     @Test
testImsApisAreAccessibleWithFeatureMapping()606     public void testImsApisAreAccessibleWithFeatureMapping() {
607         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_IMS));
608         final int subId = mTelephonyManager.getSubscriptionId();
609         try {
610             mMmTelManager.createForSubscriptionId(subId);
611 
612             RegistrationManager.RegistrationCallback rc =
613                     new RegistrationManager.RegistrationCallback() {};
614             try {
615                 mMmTelManager.registerImsRegistrationCallback(r -> r.run(), rc);
616             } catch (ImsException ignored) {
617             } finally {
618                 mMmTelManager.unregisterImsRegistrationCallback(rc);
619             }
620             if (Flags.emergencyRegistrationState()) {
621                 try {
622                     mMmTelManager.registerImsEmergencyRegistrationCallback(r -> r.run(), rc);
623                 } catch (ImsException ignored) {
624                 } finally {
625                     mMmTelManager.unregisterImsEmergencyRegistrationCallback(rc);
626                 }
627             }
628 
629             mMmTelManager.getRegistrationTransportType(r -> r.run(), (i) -> {});
630 
631             ImsMmTelManager.CapabilityCallback cc =
632                     new ImsMmTelManager.CapabilityCallback() {};
633             try {
634                 mMmTelManager.registerMmTelCapabilityCallback(r -> r.run(), cc);
635             } catch (ImsException ignored) {
636             } finally {
637                 mMmTelManager.unregisterMmTelCapabilityCallback(cc);
638             }
639 
640             mMmTelManager.isAdvancedCallingSettingEnabled();
641             mMmTelManager.isVtSettingEnabled();
642             mMmTelManager.setVoWiFiSettingEnabled(mMmTelManager.isVoWiFiSettingEnabled());
643 
644             try {
645                 mMmTelManager.setCrossSimCallingEnabled(
646                         mMmTelManager.isCrossSimCallingEnabled());
647             } catch (ImsException ignored) {
648             }
649 
650             mMmTelManager.setVoWiFiRoamingSettingEnabled(
651                     mMmTelManager.isVoWiFiRoamingSettingEnabled());
652             mMmTelManager.setVoWiFiModeSetting(mMmTelManager.getVoWiFiModeSetting());
653             mMmTelManager.isTtyOverVolteEnabled();
654 
655             ImsStateCallback ic = new ImsStateCallback() {
656                 @Override
657                 public void onUnavailable(int reason) {
658                 }
659                 @Override
660                 public void onAvailable() {
661                 }
662                 @Override
663                 public void onError() {
664                 }
665             };
666             try {
667                 mMmTelManager.registerImsStateCallback(r -> r.run(), ic);
668             } catch (ImsException ignored) {
669             } finally {
670                 mMmTelManager.unregisterImsStateCallback(ic);
671             }
672         } catch (SecurityException e) {
673             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
674         }
675     }
676 
677     @Test
testVoicemailTableIsAccessible()678     public void testVoicemailTableIsAccessible() throws Exception {
679         ContentValues value = new ContentValues();
680         value.put(VoicemailContract.Voicemails.NUMBER, "0123456789");
681         value.put(VoicemailContract.Voicemails.SOURCE_PACKAGE, selfPackageName);
682         try {
683             Uri uri = mVoicemailProvider.insert(mVoicemailContentUri, value);
684             assertThat(uri).isNotNull();
685             Cursor cursor =
686                     mVoicemailProvider.query(
687                             uri,
688                             new String[] {
689                                 VoicemailContract.Voicemails.NUMBER,
690                                 VoicemailContract.Voicemails.SOURCE_PACKAGE
691                             },
692                             null,
693                             null,
694                             null);
695             assertThat(cursor).isNotNull();
696             assertThat(cursor.moveToFirst()).isTrue();
697             assertThat(cursor.getString(0)).isEqualTo("0123456789");
698             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
699             assertThat(cursor.moveToNext()).isFalse();
700         } catch (SecurityException e) {
701             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
702         }
703     }
704 
705     @Test
testVoicemailStatusTableIsAccessible()706     public void testVoicemailStatusTableIsAccessible() throws Exception {
707         ContentValues value = new ContentValues();
708         value.put(
709                 VoicemailContract.Status.CONFIGURATION_STATE,
710                 VoicemailContract.Status.CONFIGURATION_STATE_OK);
711         value.put(VoicemailContract.Status.SOURCE_PACKAGE, selfPackageName);
712         try {
713             Uri uri = mStatusProvider.insert(mStatusContentUri, value);
714             assertThat(uri).isNotNull();
715             Cursor cursor =
716                     mVoicemailProvider.query(
717                             uri,
718                             new String[] {
719                                 VoicemailContract.Status.CONFIGURATION_STATE,
720                                 VoicemailContract.Status.SOURCE_PACKAGE
721                             },
722                             null,
723                             null,
724                             null);
725             assertThat(cursor).isNotNull();
726             assertThat(cursor.moveToFirst()).isTrue();
727             assertThat(cursor.getInt(0)).isEqualTo(VoicemailContract.Status.CONFIGURATION_STATE_OK);
728             assertThat(cursor.getString(1)).isEqualTo(selfPackageName);
729             assertThat(cursor.moveToNext()).isFalse();
730         } catch (SecurityException e) {
731             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
732         }
733     }
734 
735     static final int READ_PHONE_STATE_LISTENERS =
736             PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
737                     | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
738                     | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
739 
740     static final int READ_PRECISE_PHONE_STATE_LISTENERS =
741             PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
742                     | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
743                     | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
744                     | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
745                     | PhoneStateListener.LISTEN_BARRING_INFO;
746 
747     static final int CARRIER_PRIVILEGE_LISTENERS =
748             READ_PHONE_STATE_LISTENERS | READ_PRECISE_PHONE_STATE_LISTENERS;
749 
750     @Test
testGetManualNetworkSelectionPlmnPersisted()751     public void testGetManualNetworkSelectionPlmnPersisted() throws Exception {
752         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
753 
754         try {
755             mTelephonyManager.setNetworkSelectionModeManual(
756                     TESTING_PLMN /* operatorNumeric */, true /* persistSelection */);
757             String plmn = mTelephonyManager.getManualNetworkSelectionPlmn();
758             assertThat(plmn).isEqualTo(TESTING_PLMN);
759         } finally {
760             mTelephonyManager.setNetworkSelectionModeAutomatic();
761         }
762     }
763 
764     @Test
testPhoneStateListener()765     public void testPhoneStateListener() throws Exception {
766         PhoneStateListener psl = new PhoneStateListener((Runnable r) -> {});
767         try {
768             mTelephonyManager.listen(psl, CARRIER_PRIVILEGE_LISTENERS);
769         } finally {
770             mTelephonyManager.listen(psl, PhoneStateListener.LISTEN_NONE);
771         }
772     }
773 
774     @Test
testIsManualNetworkSelectionAllowed()775     public void testIsManualNetworkSelectionAllowed() throws Exception {
776         if (mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_GSM) return;
777 
778         try {
779             assertThat(mTelephonyManager.isManualNetworkSelectionAllowed()).isTrue();
780         } catch (SecurityException e) {
781             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
782         }
783     }
784 
785     @Test
testGetNetworkSelectionMode()786     public void testGetNetworkSelectionMode() throws Exception {
787         try {
788             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
789                     mTelephonyManager, (tm) -> tm.setNetworkSelectionModeAutomatic());
790             int networkMode = mTelephonyManager.getNetworkSelectionMode();
791             assertThat(networkMode).isEqualTo(TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
792         } catch (SecurityException e) {
793             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
794         }
795     }
796 
797     @Test
testSubscriptionInfoChangeListener()798     public void testSubscriptionInfoChangeListener() throws Exception {
799         final AtomicReference<SecurityException> error = new AtomicReference<>();
800         final CountDownLatch latch = new CountDownLatch(1);
801         new Handler(mListenerThread.getLooper())
802                 .post(
803                         () -> {
804                             SubscriptionManager.OnSubscriptionsChangedListener listener =
805                                     new SubscriptionManager.OnSubscriptionsChangedListener();
806                             try {
807                                 mSubscriptionManager.addOnSubscriptionsChangedListener(listener);
808                             } catch (SecurityException e) {
809                                 error.set(e);
810                             } finally {
811                                 mSubscriptionManager.removeOnSubscriptionsChangedListener(listener);
812                                 latch.countDown();
813                             }
814                         });
815         assertWithMessage("Test timed out").that(latch.await(30L, TimeUnit.SECONDS)).isTrue();
816         if (error.get() != null) {
817             fail(NO_CARRIER_PRIVILEGES_FAILURE_MESSAGE);
818         }
819     }
820 
821     /**
822      * Test that it's possible to open logical channels to the ICC. This mirrors the Manage Channel
823      * command described in TS 102 221 Section 11.1.17.
824      */
825     @Test
testIccOpenLogicalChannel()826     public void testIccOpenLogicalChannel() {
827         // The AID here doesn't matter - we just need to open a valid connection. In this case, the
828         // specified AID ("") opens a channel and selects the MF.
829         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
830         assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
831         final int logicalChannel = response.getChannel();
832         try {
833             verifyValidIccOpenLogicalChannelResponse(response);
834         } finally {
835             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
836         }
837     }
838 
839     @Test
testIccOpenLogicalChannelWithValidP2()840     public void testIccOpenLogicalChannelWithValidP2() {
841         // {@link TelephonyManager#iccOpenLogicalChannel} sends a Manage Channel (open) APDU
842         // followed by a Select APDU with the given AID and p2 values. See Open Mobile API
843         // Specification v3.2 Section 6.2.7.h and TS 102 221 for details.
844         int p2 = 0x0C; // '0C' for no data returned (TS 102 221 Section 11.1.1.2)
845         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("", p2);
846         assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
847         final int logicalChannel = response.getChannel();
848         try {
849             verifyValidIccOpenLogicalChannelResponse(response);
850         } finally {
851             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
852         }
853     }
854 
855     @Test
testIccOpenLogicalChannelWithInvalidP2()856     public void testIccOpenLogicalChannelWithInvalidP2() {
857         // Valid p2 values are defined in TS 102 221 Table 11.2. Per Table 11.2, 0xF0 should be
858         // invalid. Any p2 values that produce non '9000'/'62xx'/'63xx' status words are treated as
859         // an error and the channel is not opened. Due to compatibility issues with older devices,
860         // this check is only enabled for new devices launching on Q+.
861         if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) {
862             int p2 = 0xF0;
863             IccOpenLogicalChannelResponse response =
864                     mTelephonyManager.iccOpenLogicalChannel("", p2);
865             final int logicalChannel = response.getChannel();
866             assertThat(logicalChannel).isEqualTo(INVALID_CHANNEL);
867             assertThat(response.getStatus()).isNotEqualTo(STATUS_NO_ERROR);
868         }
869     }
870 
871     @Test
testIccOpenTooManyLogicalChannels()872     public void testIccOpenTooManyLogicalChannels() throws IOException {
873         Set<Integer> channels = new HashSet<Integer>();
874         boolean failedOnce = false;
875         try {
876             for (int i = MIN_LOGICAL_CHANNEL; i <= MAX_LOGICAL_CHANNEL_EXTENDED + 1; i++) {
877                 IccOpenLogicalChannelResponse response =
878                         mTelephonyManager.iccOpenLogicalChannel("");
879                 int channel = response.getChannel();
880                 if (channel > 0) {
881                     // TODO(b/375102360): CF should implement handling more than one logical channel
882                     assumeFalse(channels.contains(channel) && MediaUtils.onCuttlefish());
883                     assertWithMessage("Logical channel " + channel + " was returned twice")
884                             .that(channels.add(channel)).isTrue();
885                 }
886                 if (response.getStatus() == STATUS_MISSING_RESOURCE) {
887                     assertThat(response.getSelectResponse()).isNull();
888                     assertThat(channel).isEqualTo(INVALID_CHANNEL);
889                     failedOnce = true;
890                     break;
891                 }
892                 assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
893                 assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
894                 assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL,
895                         MAX_LOGICAL_CHANNEL_EXTENDED));
896             }
897         } finally {
898             for (Integer channel : channels) {
899                 mTelephonyManager.iccCloseLogicalChannel(channel);
900             }
901         }
902         assertTrue(failedOnce);
903 
904         // Make sure you can open logical channel after closing old ones.
905         testIccOpenLogicalChannel();
906     }
907 
908     /**
909      * Test that it's possible to close logical channels to the ICC. This follows the Manage Channel
910      * command described in TS 102 221 Section 11.1.17.
911      */
912     @Test
testIccCloseLogicalChannel()913     public void testIccCloseLogicalChannel() {
914         // The directory here doesn't matter - we just need to open a valid connection that can
915         // later be closed. In this case, the specified AID ("") opens a channel and selects the MF.
916         IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel("");
917 
918         // Check that the select command succeeded. This ensures that the logical channel is indeed
919         // open.
920         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
921         assertThat(mTelephonyManager.iccCloseLogicalChannel(response.getChannel())).isTrue();
922 
923         // Close opened channel twice.
924         try {
925             boolean result = mTelephonyManager.iccCloseLogicalChannel(response.getChannel());
926             assertThat(result).isFalse();
927         } catch (IllegalArgumentException ex) {
928             //IllegalArgumentException is expected sometimes because of different behaviour of modem
929         }
930 
931         // Channel 0 is guaranteed to be always available and cannot be closed, per TS 102 221
932         // Section 11.1.17
933         try {
934             mTelephonyManager.iccCloseLogicalChannel(0);
935             fail("Expected IllegalArgumentException");
936         } catch (IllegalArgumentException ex) {
937             // IllegalArgumentException is expected
938         }
939     }
940 
941     /**
942      * This test ensures that valid APDU instructions can be sent and processed by the ICC. To do
943      * so, APDUs are sent to: - get the status of the MF - select the Access Rule Reference (ARR)
944      * for the MF - get the FCP template response for the select
945      */
946     @Test
testIccTransmitApduLogicalChannel()947     public void testIccTransmitApduLogicalChannel() {
948         // An open LC is required for transmitting APDU commands. This opens an LC to the MF.
949         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
950                 mTelephonyManager.iccOpenLogicalChannel("");
951         assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR);
952 
953         // Get the status of the current directory. This should match the MF. TS 102 221 Section
954         // 11.1.2
955         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
956 
957         try {
958             int cla = CLA_STATUS;
959             int p1 = 0; // no indication of application status
960             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
961             // above
962             int p3 = 0; // length of 'data' payload
963             String data = "";
964             String response =
965                     mTelephonyManager.iccTransmitApduLogicalChannel(
966                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
967             FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
968             // Check that the FCP Template's file ID matches the MF
969             assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
970             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
971 
972             // Select the Access Rule Reference for the MF. Similar to the MF, this will exist
973             // across all SIM cards. TS 102 221 Section 11.1.1
974             cla = CLA_SELECT;
975             p1 = 0; // select EF by FID
976             p2 = 0x04; // requesting FCP template
977             p3 = 2; // data (FID to be selected) is 2 bytes
978             data = MF_ARR_FILE_ID;
979             response =
980                     mTelephonyManager.iccTransmitApduLogicalChannel(
981                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
982 
983             // Devices launching with Q or later must immediately return the FCP template from the
984             // previous SELECT command. Some devices that launched before Q return TPDUs (instead of
985             // APDUs) - these devices must issue a subsequent GET RESPONSE command to get the FCP
986             // template.
987             if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) {
988                 // Conditionally need to send GET RESPONSE apdu based on response from
989                 // TelephonyManager
990                 if (response.startsWith(STATUS_BYTES_REMAINING)) {
991                     // Read the FCP template from the ICC. TS 102 221 Section 12.1.1
992                     cla = CLA_GET_RESPONSE;
993                     p1 = 0;
994                     p2 = 0;
995                     p3 = 0;
996                     data = "";
997                     response =
998                             mTelephonyManager.iccTransmitApduLogicalChannel(
999                                     logicalChannel, cla, COMMAND_GET_RESPONSE, p1, p2, p3, data);
1000                 }
1001             }
1002 
1003             fcpTemplate = FcpTemplate.parseFcpTemplate(response);
1004             // Check that the FCP Template's file ID matches the selected ARR
1005             assertThat(containsFileId(fcpTemplate, MF_ARR_FILE_ID)).isTrue();
1006             assertThat(fcpTemplate.getStatus()).isEqualTo(STATUS_NORMAL_STRING);
1007         } finally {
1008             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
1009         }
1010     }
1011 
1012     /**
1013      * Tests several invalid APDU instructions over a logical channel and makes sure appropriate
1014      * errors are returned from the UICC.
1015      */
1016     @Test
testIccTransmitApduLogicalChannelWithInvalidInputs()1017     public void testIccTransmitApduLogicalChannelWithInvalidInputs() {
1018         // An open LC is required for transmitting apdu commands. This opens an LC to the MF.
1019         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
1020                 mTelephonyManager.iccOpenLogicalChannel("");
1021         assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR);
1022         final int logicalChannel = iccOpenLogicalChannelResponse.getChannel();
1023 
1024         try {
1025             // Make some invalid APDU commands and make sure they fail as expected.
1026             // Use an invalid p1 value for Status apdu
1027             int cla = CLA_STATUS | logicalChannel;
1028             int p1 = 0xFF; // only '00', '01', and '02' are allowed
1029             int p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel()
1030             // above
1031             int p3 = 0; // length of 'data' payload
1032             String data = "";
1033             String response =
1034                     mTelephonyManager.iccTransmitApduLogicalChannel(
1035                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
1036             assertThat(INVALID_PARAMETERS_STATUSES.contains(response)).isTrue();
1037 
1038             // Select a file that doesn't exist
1039             cla = CLA_SELECT;
1040             p1 = 0x00; // select by file ID
1041             p2 = 0x0C; // no data returned
1042             p3 = 0x02; // length of 'data' payload
1043             data = "FFFF"; // invalid file ID
1044             response =
1045                     mTelephonyManager.iccTransmitApduLogicalChannel(
1046                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
1047             assertThat(response).isEqualTo(STATUS_FILE_NOT_FOUND);
1048 
1049             // Manage channel with incorrect p1 parameter
1050             cla = CLA_MANAGE_CHANNEL | logicalChannel;
1051             p1 = 0x83; // Only '80' or '00' allowed for Manage Channel p1
1052             p2 = logicalChannel; // channel to be closed
1053             p3 = 0; // length of 'data' payload
1054             data = "";
1055             response =
1056                     mTelephonyManager.iccTransmitApduLogicalChannel(
1057                             logicalChannel, cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
1058             assertThat(isErrorResponse(response)).isTrue();
1059 
1060             // Use an incorrect class byte for Status apdu
1061             cla = 0xFF;
1062             p1 = 0; // no indication of application status
1063             p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
1064             p3 = 0; // length of 'data' payload
1065             data = "";
1066             response =
1067                     mTelephonyManager.iccTransmitApduLogicalChannel(
1068                             logicalChannel, cla, COMMAND_STATUS, p1, p2, p3, data);
1069             assertThat(response).isEqualTo(STATUS_WRONG_CLASS);
1070 
1071             // Provide a data field that is longer than described for Select apdu
1072             cla = CLA_SELECT | logicalChannel;
1073             p1 = 0; // select by file ID
1074             p2 = 0x0C; // no data returned
1075             p3 = 0x04; // data passed is actually 2 bytes long
1076             data = "3F00"; // valid ID
1077             response =
1078                     mTelephonyManager.iccTransmitApduLogicalChannel(
1079                             logicalChannel, cla, COMMAND_SELECT, p1, p2, p3, data);
1080             assertThat(isErrorResponse(response)).isTrue();
1081 
1082             // Use an invalid instruction
1083             cla = 0;
1084             p1 = 0;
1085             p2 = 0;
1086             p3 = 0;
1087             data = "";
1088             int invalidInstruction = 0xFF; // see TS 102 221 Table 10.5 for valid instructions
1089             response =
1090                     mTelephonyManager.iccTransmitApduLogicalChannel(
1091                             logicalChannel, cla, invalidInstruction, p1, p2, p3, data);
1092             assertThat(isErrorResponse(response)).isTrue();
1093         } finally {
1094             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
1095         }
1096     }
1097 
1098     @Test
testIccTransmitApduLogicalChannelWithInvalidChannel()1099     public void testIccTransmitApduLogicalChannelWithInvalidChannel() throws IOException {
1100         IccOpenLogicalChannelResponse iccOpenLogicalChannelResponse =
1101                 mTelephonyManager.iccOpenLogicalChannel("");
1102         assertThat(iccOpenLogicalChannelResponse.getStatus()).isEqualTo(STATUS_NO_ERROR);
1103         final int closedCh = iccOpenLogicalChannelResponse.getChannel();
1104         mTelephonyManager.iccCloseLogicalChannel(closedCh);
1105 
1106         int[] badChannels = {
1107             // use after close
1108             closedCh,
1109 
1110             // common wrong values
1111             -2,
1112             -1,
1113             50,
1114             100,
1115 
1116             // int8_t max and max + 1
1117             127,
1118             128,
1119 
1120             // uint8_t max - 1 to + 2,
1121             254,
1122             255,
1123             256,
1124             257,
1125 
1126             // int16_t max and max + 1,
1127             32767,
1128             32768,
1129 
1130             // uint16_t max + 1,
1131             65536,
1132 
1133             // int32_t max
1134             2147483647,
1135         };
1136 
1137         for (int channel : badChannels) {
1138             String response = mTelephonyManager.iccTransmitApduLogicalChannel(
1139                     channel, CLA_STATUS, COMMAND_STATUS, 0, 0, 0, "");
1140             assertWithMessage("Unexpected response when transmitting on invalid channel " + channel)
1141                     .that(response)
1142                     .isAnyOf(STATUS_CHANNEL_NOT_SUPPORTED, STATUS_TECHNICAL_PROBLEM);
1143         }
1144     }
1145 
1146     /**
1147      * This test ensures that files can be read off the UICC. This helps to test the SIM booting
1148      * process, as it process involves several file-reads. The ICCID is one of the first files read.
1149      */
1150     @Test
testApduFileRead()1151     public void testApduFileRead() {
1152         // Open a logical channel and select the MF.
1153         IccOpenLogicalChannelResponse iccOpenLogicalChannel =
1154                 mTelephonyManager.iccOpenLogicalChannel("");
1155         assertThat(iccOpenLogicalChannel.getStatus()).isEqualTo(STATUS_NO_ERROR);
1156         final int logicalChannel = iccOpenLogicalChannel.getChannel();
1157 
1158         try {
1159             // Select the ICCID. TS 102 221 Section 13.2
1160             int p1 = 0; // select by file ID
1161             int p2 = 0x0C; // no data returned
1162             int p3 = 2; // length of 'data' payload
1163             String response =
1164                     mTelephonyManager.iccTransmitApduLogicalChannel(
1165                             logicalChannel, CLA_SELECT, COMMAND_SELECT, p1, p2, p3, ICCID_FILE_ID);
1166             assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1167 
1168             // Read the contents of the ICCID.
1169             p1 = 0; // 0-byte offset
1170             p2 = 0; // 0-byte offset
1171             p3 = 0; // length of 'data' payload
1172             response =
1173                     mTelephonyManager.iccTransmitApduLogicalChannel(
1174                             logicalChannel, CLA_READ_BINARY, COMMAND_READ_BINARY, p1, p2, p3, "");
1175             assertThat(response).endsWith(STATUS_NORMAL_STRING);
1176         } finally {
1177             mTelephonyManager.iccCloseLogicalChannel(logicalChannel);
1178         }
1179     }
1180 
1181     // ETSI TS 102 221 13.2
verifyValidIccId(String iccid)1182     private void verifyValidIccId(String iccid) {
1183         assertThat(iccid).hasLength(20);
1184     }
1185 
1186     // ETSI TS 102 221 13.3
verifyValidPl(String pl)1187     private void verifyValidPl(String pl) {
1188         final int hexEntryLength = PL_ENTRY_LENGTH * HEX_BYTES_PER_CHAR;
1189         assertThat(pl.length() % hexEntryLength).isEqualTo(0);
1190         assertThat(pl.length()).isAtLeast(hexEntryLength);
1191         for (int i = 0; i < pl.length(); i += hexEntryLength) {
1192             String langHex = pl.substring(i, i + hexEntryLength);
1193             assertThat(langHex).hasLength(hexEntryLength);
1194 
1195             byte[] lang = hexStringToBytes(langHex);
1196             assertThat(lang).hasLength(PL_ENTRY_LENGTH);
1197             int ch1 = Byte.toUnsignedInt(lang[0]);
1198             int ch2 = Byte.toUnsignedInt(lang[1]);
1199             if (ch1 == 0xFF && ch2 == 0xFF) continue;
1200 
1201             assertTrue("Language code is not alphanumeric: " + langHex,
1202                     isSeriouslyLetterOrDigit(ch1) && isSeriouslyLetterOrDigit(ch2));
1203         }
1204     }
1205 
openLogicalChannelWithRetries(String aid)1206     private IccOpenLogicalChannelResponse openLogicalChannelWithRetries(String aid) {
1207         for (int retries = 0; retries < MAX_RETRIES; retries++) {
1208             IccOpenLogicalChannelResponse response = mTelephonyManager.iccOpenLogicalChannel(aid);
1209             if (response.getStatus() != STATUS_MISSING_RESOURCE) return response;
1210             assertThat(response.getChannel()).isEqualTo(INVALID_CHANNEL);
1211             try {
1212                 // Let's give other processes time to finish and release occupied channels.
1213                 Thread.sleep(100);
1214             } catch (InterruptedException ex) {
1215                 break;
1216             }
1217         }
1218         fail("Couldn't open logical channel: no resources");
1219         return null;
1220     }
1221 
1222     /**
1223      * This test verifies if two files can be read off the UICC at the same time through two
1224      * different channels.
1225      */
1226     @Test
testApduFileReadTwoChannels()1227     public void testApduFileReadTwoChannels() throws IOException {
1228         int channel1 = INVALID_CHANNEL;
1229         int channel2 = INVALID_CHANNEL;
1230         try {
1231             IccOpenLogicalChannelResponse channel1rsp = openLogicalChannelWithRetries("");
1232             verifyValidIccOpenLogicalChannelResponse(channel1rsp);
1233             channel1 = channel1rsp.getChannel();
1234 
1235             IccOpenLogicalChannelResponse channel2rsp = openLogicalChannelWithRetries("");
1236             verifyValidIccOpenLogicalChannelResponse(channel2rsp);
1237             channel2 = channel2rsp.getChannel();
1238 
1239             // TODO(b/375102360): CF should implement handling more than one logical channel
1240             assumeFalse(channel1 == channel2 && MediaUtils.onCuttlefish());
1241             assertWithMessage("Two concurrently opened channels should be different")
1242                     .that(channel2).isNotEqualTo(channel1);
1243 
1244             // p1, p2, p3 - see testApduFileRead
1245             String selResponse = mTelephonyManager.iccTransmitApduLogicalChannel(
1246                     channel1, CLA_SELECT, COMMAND_SELECT, 0, 0x0C, 2, PL_FILE_ID);
1247             assertThat(selResponse).isEqualTo(STATUS_NORMAL_STRING);
1248 
1249             selResponse = mTelephonyManager.iccTransmitApduLogicalChannel(
1250                     channel2, CLA_SELECT, COMMAND_SELECT, 0, 0x0C, 2, ICCID_FILE_ID);
1251             assertThat(selResponse).isEqualTo(STATUS_NORMAL_STRING);
1252 
1253             // Read from two channels out of order -- SELECT command shouldn't affect other channels
1254             String contents2 = mTelephonyManager.iccTransmitApduLogicalChannel(
1255                     channel2, CLA_READ_BINARY, COMMAND_READ_BINARY, 0, 0, 0, "");
1256             assertThat(contents2).endsWith(STATUS_NORMAL_STRING);
1257 
1258             String contents1 = mTelephonyManager.iccTransmitApduLogicalChannel(
1259                     channel1, CLA_READ_BINARY, COMMAND_READ_BINARY, 0, 0, 0, "");
1260             assertThat(contents1).endsWith(STATUS_NORMAL_STRING);
1261 
1262             assertWithMessage("Contents of EF_PL and EF_ICCID shouldn't be the same")
1263                     .that(contents1).isNotEqualTo(contents2);
1264             verifyValidPl(contents1.substring(0, contents1.length() - 4));
1265             verifyValidIccId(contents2.substring(0, contents2.length() - 4));
1266         } finally {
1267             if (channel1 != INVALID_CHANNEL) {
1268                 mTelephonyManager.iccCloseLogicalChannel(channel1);
1269             }
1270             if (channel2 != INVALID_CHANNEL && channel1 != channel2) {
1271                 mTelephonyManager.iccCloseLogicalChannel(channel2);
1272             }
1273         }
1274     }
1275 
1276     /** This test sends several valid APDU commands over the basic channel (channel 0). */
1277     @Test
testIccTransmitApduBasicChannel()1278     public void testIccTransmitApduBasicChannel() {
1279         // select the MF
1280         int cla = CLA_SELECT;
1281         int p1 = 0; // select EF by FID
1282         int p2 = 0x0C; // requesting FCP template
1283         int p3 = 2; // length of 'data' payload
1284         String data = MF_FILE_ID;
1285         String response =
1286                 mTelephonyManager.iccTransmitApduBasicChannel(
1287                         cla, COMMAND_SELECT, p1, p2, p3, data);
1288         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1289 
1290         // get the Status of the current file/directory
1291         cla = CLA_STATUS;
1292         p1 = 0; // no indication of application status
1293         p2 = 0; // same response parameters as the SELECT in the iccOpenLogicalChannel() above
1294         p3 = 0; // length of 'data' payload
1295         data = "";
1296         response =
1297                 mTelephonyManager.iccTransmitApduBasicChannel(
1298                         cla, COMMAND_STATUS, p1, p2, p3, data);
1299         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(response);
1300         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
1301 
1302         // Manually open a logical channel
1303         cla = CLA_MANAGE_CHANNEL;
1304         p1 = 0; // open a logical channel
1305         p2 = 0; // '00' for open command
1306         p3 = 0; // length of data payload
1307         data = "";
1308         response =
1309                 mTelephonyManager.iccTransmitApduBasicChannel(
1310                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
1311         // response is in the format | 1 byte: channel number | 2 bytes: status word |
1312         String responseStatus = response.substring(response.length() - 4);
1313         assertThat(responseStatus).isEqualTo(STATUS_NORMAL_STRING);
1314 
1315         // Close the open channel
1316         byte[] responseBytes = hexStringToBytes(response);
1317         int channel = responseBytes[0];
1318         cla = CLA_MANAGE_CHANNEL;
1319         p1 = 0x80; // close a logical channel
1320         p2 = channel; // the channel to be closed
1321         p3 = 0; // length of data payload
1322         data = "";
1323         response =
1324                 mTelephonyManager.iccTransmitApduBasicChannel(
1325                         cla, COMMAND_MANAGE_CHANNEL, p1, p2, p3, data);
1326         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1327     }
1328 
1329     /**
1330      * This test verifies that {@link TelephonyManager#setLine1NumberForDisplay(String, String)}
1331      * correctly sets the Line 1 alpha tag and number when called, and the phone number
1332      * of {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}.
1333      */
1334     @Test
testLine1NumberForDisplay()1335     public void testLine1NumberForDisplay() {
1336         int subId = SubscriptionManager.getDefaultSubscriptionId();
1337         // Cache original alpha tag and number values.
1338         String originalAlphaTag = mTelephonyManager.getLine1AlphaTag();
1339         String originalNumber = mTelephonyManager.getLine1Number();
1340 
1341         try {
1342             // clear any potentially overridden values and cache defaults
1343             mTelephonyManager.setLine1NumberForDisplay(null, null);
1344             String defaultAlphaTag = mTelephonyManager.getLine1AlphaTag();
1345             String defaultNumber = mTelephonyManager.getLine1Number();
1346 
1347             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_A, NUMBER_A)).isTrue();
1348             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_A);
1349             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_A);
1350             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1351                     .isEqualTo(NUMBER_A);
1352 
1353             assertThat(mTelephonyManager.setLine1NumberForDisplay(ALPHA_TAG_B, NUMBER_B)).isTrue();
1354             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(ALPHA_TAG_B);
1355             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(NUMBER_B);
1356             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1357                     .isEqualTo(NUMBER_B);
1358 
1359             // null is used to clear the Line 1 alpha tag and number values.
1360             assertThat(mTelephonyManager.setLine1NumberForDisplay(null, null)).isTrue();
1361             assertThat(mTelephonyManager.getLine1AlphaTag()).isEqualTo(defaultAlphaTag);
1362             assertThat(mTelephonyManager.getLine1Number()).isEqualTo(defaultNumber);
1363             assertThat(mSubscriptionManager.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER))
1364                     .isEqualTo("");
1365         } finally {
1366             // Reset original alpha tag and number values.
1367             mTelephonyManager.setLine1NumberForDisplay(originalAlphaTag, originalNumber);
1368         }
1369     }
1370 
1371     /**
1372      * This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly
1373      * sets the VoiceMail alpha tag and number when called.
1374      */
1375     @Test
testVoiceMailNumber()1376     public void testVoiceMailNumber() {
1377         assumeTrue(hasTelephonyCalling());
1378 
1379         // Cache original alpha tag and number values.
1380         String originalAlphaTag = mTelephonyManager.getVoiceMailAlphaTag();
1381         String originalNumber = mTelephonyManager.getVoiceMailNumber();
1382 
1383         try {
1384             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_A, NUMBER_A)).isTrue();
1385             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_A);
1386             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_A);
1387 
1388             assertThat(mTelephonyManager.setVoiceMailNumber(ALPHA_TAG_B, NUMBER_B)).isTrue();
1389             assertThat(mTelephonyManager.getVoiceMailAlphaTag()).isEqualTo(ALPHA_TAG_B);
1390             assertThat(mTelephonyManager.getVoiceMailNumber()).isEqualTo(NUMBER_B);
1391         } finally {
1392             // Reset original alpha tag and number values.
1393             mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber);
1394         }
1395     }
1396 
1397     /**
1398      * This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly
1399      * create a group with the given subscription id.
1400      *
1401      * <p>This also verifies that {@link SubscriptionManager#removeSubscriptionsFromGroup(List,
1402      * ParcelUuid)} correctly remove the given subscription group.
1403      */
1404     @Test
testCreateAndRemoveSubscriptionGroup()1405     public void testCreateAndRemoveSubscriptionGroup() {
1406         // Set subscription group with current sub Id.
1407         int subId = SubscriptionManager.getDefaultSubscriptionId();
1408         List<Integer> subGroup = Arrays.asList(subId);
1409         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(subGroup);
1410 
1411         // Getting subscriptions in group.
1412         List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1413 
1414         try {
1415             assertThat(infoList).hasSize(1);
1416             assertThat(infoList.get(0).getGroupUuid()).isEqualTo(uuid);
1417             assertThat(infoList.get(0).getSubscriptionId()).isEqualTo(subId);
1418         } finally {
1419             // Verify that the given subGroup has been removed.
1420             mSubscriptionManager.removeSubscriptionsFromGroup(subGroup, uuid);
1421             infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
1422             assertThat(infoList).isEmpty();
1423         }
1424     }
1425 
1426     @Test
testAddSubscriptionToExistingGroupForMultipleSims()1427     public void testAddSubscriptionToExistingGroupForMultipleSims() {
1428         if (mTelephonyManager.getPhoneCount() < DSDS_PHONE_COUNT
1429                 || mSubscriptionManager.getActiveSubscriptionInfoList().size() < DSDS_PHONE_COUNT) {
1430             // This test requires at least two active subscriptions.
1431             return;
1432         }
1433 
1434         // Set subscription group with current sub Id.
1435         int subId = SubscriptionManager.getDefaultSubscriptionId();
1436         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1437         ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
1438                 (sm) -> sm.createSubscriptionGroup(Arrays.asList(subId)));
1439 
1440         try {
1441             // Get all active subscriptions.
1442             List<SubscriptionInfo> activeSubInfos =
1443                     ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
1444                     (sm) -> sm.getActiveSubscriptionInfoList());
1445 
1446             List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
1447             activeSubGroup.removeIf(id -> id == subId);
1448 
1449             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1450                     (sm) -> sm.addSubscriptionsIntoGroup(activeSubGroup, uuid));
1451 
1452             List<Integer> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1453                     mSubscriptionManager,
1454                     (sm) -> getSubscriptionIdList(sm.getSubscriptionsInGroup(uuid)));
1455 
1456             activeSubGroup.add(subId);
1457             assertThat(infoList).containsExactlyElementsIn(activeSubGroup);
1458         } finally {
1459             removeSubscriptionsFromGroup(uuid);
1460         }
1461     }
1462 
1463     /**
1464      * This test verifies that {@link SubscriptionManager#addSubscriptionsIntoGroup(List,
1465      * ParcelUuid)}} correctly add some additional subscriptions to the existing group.
1466      *
1467      * <p>This test required the device has more than one subscription.
1468      */
1469     @Test
testAddSubscriptionToExistingGroupForEsim()1470     public void testAddSubscriptionToExistingGroupForEsim() {
1471         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION));
1472         assumeTrue(hasFeature(PackageManager.FEATURE_TELEPHONY_EUICC));
1473         // Set subscription group with current sub Id.
1474         int subId = SubscriptionManager.getDefaultSubscriptionId();
1475         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1476         ParcelUuid uuid = mSubscriptionManager.createSubscriptionGroup(Arrays.asList(subId));
1477 
1478         try {
1479             // Get all accessible eSim subscription.
1480             List<SubscriptionInfo> accessibleSubInfos =
1481                     mSubscriptionManager.getAccessibleSubscriptionInfoList();
1482             if (accessibleSubInfos != null && accessibleSubInfos.size() > 1) {
1483                 List<Integer> accessibleSubGroup = getSubscriptionIdList(accessibleSubInfos);
1484                 accessibleSubGroup.removeIf(id -> id == subId);
1485 
1486                 mSubscriptionManager.addSubscriptionsIntoGroup(accessibleSubGroup, uuid);
1487 
1488                 List<Integer> infoList =
1489                         getSubscriptionIdList(mSubscriptionManager.getSubscriptionsInGroup(uuid));
1490                 accessibleSubGroup.add(subId);
1491                 assertThat(infoList).containsExactlyElementsIn(accessibleSubGroup);
1492             }
1493         } finally {
1494             removeSubscriptionsFromGroup(uuid);
1495         }
1496     }
1497 
1498     /**
1499      * This test verifies that {@link SubscriptionManager#setOpportunistic(boolean, int)} correctly
1500      * set the opportunistic property of the given subscription.
1501      */
1502     @Test
testOpportunistic()1503     public void testOpportunistic() {
1504         int subId = SubscriptionManager.getDefaultSubscriptionId();
1505         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) return;
1506         SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1507         boolean oldOpportunistic = info.isOpportunistic();
1508         boolean newOpportunistic = !oldOpportunistic;
1509 
1510         try {
1511             // Mark the given subscription as opportunistic subscription.
1512             assertThat(mSubscriptionManager.setOpportunistic(newOpportunistic, subId)).isTrue();
1513 
1514             // Verify that the given subscription is opportunistic subscription.
1515             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1516             assertThat(info.isOpportunistic()).isEqualTo(newOpportunistic);
1517         } finally {
1518             // Set back to original opportunistic property.
1519             mSubscriptionManager.setOpportunistic(oldOpportunistic, subId);
1520             info = mSubscriptionManager.getActiveSubscriptionInfo(subId);
1521             assertThat(info.isOpportunistic()).isEqualTo(oldOpportunistic);
1522 
1523             // As opportunistic subscription can not be the default data/voice/sms subscription,
1524             // when the test case set the active subscription as opportunistic, the default
1525             // subscription may set to INVALID_SUBSCRIPTION_ID. Although at the end, the test case
1526             // tries to recover it, it may take time to fully take effort and fail the following
1527             // test case. Add a polling check of carrier privilege on default subscription here to
1528             // make sure default subscription has recovered before ending the case.
1529             PollingCheck.waitFor(5000, () -> getContext().getSystemService(TelephonyManager.class)
1530                     .hasCarrierPrivileges(),
1531                     "Timeout when waiting to gain carrier privileges again.");
1532         }
1533     }
1534 
1535     /**
1536      * This test verifies that {@link TelephonyManager#iccExchangeSimIO(int, int, int, int, int,
1537      * String)} correctly transmits iccIO commands to the UICC card. First, the MF is selected via a
1538      * SELECT apdu via the basic channel, then a STATUS AT-command is sent.
1539      */
1540     @Test
testIccExchangeSimIO()1541     public void testIccExchangeSimIO() {
1542         // select the MF first. This makes sure the next STATUS AT-command returns a FCP template
1543         // for the right file.
1544         int cla = CLA_SELECT;
1545         int p1 = 0; // select EF by FID
1546         int p2 = 0x0C; // requesting FCP template
1547         int p3 = 2; // length of 'data' payload
1548         String data = MF_FILE_ID;
1549         String response =
1550                 mTelephonyManager.iccTransmitApduBasicChannel(
1551                         cla, COMMAND_SELECT, p1, p2, p3, data);
1552         assertThat(response).isEqualTo(STATUS_NORMAL_STRING);
1553 
1554         // The iccExchangeSimIO command implements the +CRSM command defined in TS 27.007 section
1555         // 8.18. A STATUS command is sent and the returned value will be an FCP template.
1556         byte[] result =
1557                 mTelephonyManager.iccExchangeSimIO(
1558                         0, // fileId: not required for STATUS
1559                         COMMAND_STATUS, // command: STATUS
1560                         0, // p1: not required for STATUS
1561                         0, // p2: not required for STATUS
1562                         0, // p3: not required for STATUS
1563                         ""); // filePath: not required for STATUS
1564         String resultString = bytesToHexString(result);
1565         FcpTemplate fcpTemplate = FcpTemplate.parseFcpTemplate(resultString);
1566         assertThat(containsFileId(fcpTemplate, MF_FILE_ID)).isTrue();
1567         assertWithMessage("iccExchangeSimIO returned non-normal Status byte: %s", resultString)
1568                 .that(fcpTemplate.getStatus())
1569                 .isEqualTo(STATUS_NORMAL_STRING);
1570     }
1571 
1572     /**
1573      * This test checks that a STATUS apdu can be sent as an encapsulated envelope to the UICC via
1574      * {@link TelephonyManager#sendEnvelopeWithStatus(String)}.
1575      */
1576     @Test
testSendEnvelopeWithStatus()1577     public void testSendEnvelopeWithStatus() {
1578         // STATUS apdu as hex String
1579         String envelope =
1580                 CLA_STATUS_STRING
1581                         + COMMAND_STATUS_STRING
1582                         + "00" // p1: no indication of application status
1583                         + "00"; // p2: identical parameters to
1584         String response = mTelephonyManager.sendEnvelopeWithStatus(envelope);
1585 
1586         // TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope
1587         assertWithMessage("sendEnvelopeWithStatus is null for envelope=%s", envelope)
1588                 .that(response)
1589                 .isNotNull();
1590     }
1591 
1592     /**
1593      * This test checks that applications with carrier privilege can set/clear signal strength
1594      * update request via {@link
1595      * TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)} and {@link
1596      * TelephonyManager#clearSignalStrengthUpdateRequest} without {@link
1597      * android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
1598      */
1599     @Test
testSetClearSignalStrengthUpdateRequest()1600     public void testSetClearSignalStrengthUpdateRequest() {
1601         final SignalStrengthUpdateRequest request =
1602                 new SignalStrengthUpdateRequest.Builder()
1603                         .setSignalThresholdInfos(
1604                                 List.of(
1605                                         new SignalThresholdInfo.Builder()
1606                                                 .setRadioAccessNetworkType(
1607                                                         AccessNetworkConstants.AccessNetworkType
1608                                                                 .GERAN)
1609                                                 .setSignalMeasurementType(
1610                                                         SignalThresholdInfo
1611                                                                 .SIGNAL_MEASUREMENT_TYPE_RSSI)
1612                                                 .setThresholds(new int[] {-113, -103, -97, -51})
1613                                                 .setHysteresisDb(1)
1614                                                 .build()))
1615                         .setReportingRequestedWhileIdle(true)
1616                         .build();
1617         try {
1618             mTelephonyManager.setSignalStrengthUpdateRequest(request);
1619         } finally {
1620             mTelephonyManager.clearSignalStrengthUpdateRequest(request);
1621         }
1622     }
1623 
verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response)1624     private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
1625         assertThat(response.getStatus()).isEqualTo(STATUS_NO_ERROR);
1626         assertThat(response.getSelectResponse()).isEqualTo(STATUS_NORMAL);
1627 
1628         // The assigned channel should be between the min and max allowed channel numbers
1629         int channel = response.getChannel();
1630         assertThat(channel).isIn(Range.closed(MIN_LOGICAL_CHANNEL, MAX_LOGICAL_CHANNEL));
1631     }
1632 
removeSubscriptionsFromGroup(ParcelUuid uuid)1633     private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
1634         List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1635                 mSubscriptionManager,
1636                 (sm) -> (sm.getSubscriptionsInGroup(uuid)));
1637         if (!infoList.isEmpty()) {
1638             List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
1639             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
1640                     (sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
1641         }
1642         infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
1643                 mSubscriptionManager,
1644                 (sm) -> (sm.getSubscriptionsInGroup(uuid)));
1645         assertThat(infoList).isEmpty();
1646     }
1647 
getSubscriptionIdList(List<SubscriptionInfo> subInfoList)1648     private List<Integer> getSubscriptionIdList(List<SubscriptionInfo> subInfoList) {
1649         if (subInfoList == null || subInfoList.isEmpty()) return Collections.EMPTY_LIST;
1650         return subInfoList.stream()
1651                 .map(info -> info.getSubscriptionId())
1652                 .collect(Collectors.toList());
1653     }
1654 
1655     /**
1656      * Checks whether the a {@code fcpTemplate} contains the given {@code fileId}.
1657      *
1658      * @param fcpTemplate The FCP Template to be checked.
1659      * @param fileId The file ID that is being searched for
1660      * @return true iff fcpTemplate contains fileId.
1661      */
containsFileId(FcpTemplate fcpTemplate, String fileId)1662     private boolean containsFileId(FcpTemplate fcpTemplate, String fileId) {
1663         return fcpTemplate.getTlvs().stream()
1664                 .anyMatch(tlv -> tlv.getTag() == FILE_IDENTIFIER && tlv.getValue().equals(fileId));
1665     }
1666 
1667     /**
1668      * Returns true iff {@code response} indicates an error with the previous APDU.
1669      *
1670      * @param response The APDU response to be checked.
1671      * @return true iff the given response indicates an error occurred
1672      */
isErrorResponse(@onnull String response)1673     private boolean isErrorResponse(@Nonnull String response) {
1674         return !(STATUS_NORMAL_STRING.equals(response)
1675                 || response.startsWith(STATUS_WARNING_A)
1676                 || response.startsWith(STATUS_WARNING_B)
1677                 || response.startsWith(STATUS_BYTES_REMAINING));
1678     }
1679 
1680     private static class IntentReceiver extends BroadcastReceiver {
1681         private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
1682 
1683         @Override
onReceive(Context context, Intent intent)1684         public void onReceive(Context context, Intent intent) {
1685             mReceiveLatch.countDown();
1686         }
1687 
waitForReceive()1688         public boolean waitForReceive() throws InterruptedException {
1689             return mReceiveLatch.await(30, TimeUnit.SECONDS);
1690         }
1691     }
1692 
1693     @Test
testEapSimAuthentication()1694     public void testEapSimAuthentication() {
1695         assumeTrue(
1696                 "testEapSimAuthentication requires a 2021 CTS UICC or newer",
1697                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1698         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1699         // n: 128 (Bits to use for RES value)
1700         // Format: [Length][RAND]
1701         String challenge = "10" + EAP_SIM_AKA_RAND;
1702         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1703         String base64Response = null;
1704         try {
1705             base64Response = mTelephonyManager.getIccAuthentication(
1706                     TelephonyManager.APPTYPE_USIM,
1707                     TelephonyManager.AUTHTYPE_EAP_SIM,
1708                     base64Challenge);
1709         } catch (UnsupportedOperationException e) {
1710             assumeNoException("EAP-SIM not supported", e);
1711         }
1712         assertWithMessage("UICC returned null for EAP-SIM auth").that(base64Response).isNotNull();
1713         byte[] response = Base64.decode(base64Response, Base64.DEFAULT);
1714         assertWithMessage("Results for AUTHTYPE_EAP_SIM failed")
1715                 .that(response)
1716                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_SIM_RESULT));
1717     }
1718 
1719     @Test
testEapAkaAuthentication()1720     public void testEapAkaAuthentication() {
1721         // Wear devices do not yet support EapAkaAuthentication, so skip this test for now
1722         // TODO: use REQUEST_NOT_SUPPORTED on Wear instead of skipping this test
1723         if (isWear()) {
1724             return;
1725         }
1726         assumeTrue(
1727                 "testEapAkaAuthentication requires a 2021 CTS UICC or newer",
1728                 UiccUtil.uiccHasCertificate(CTS_UICC_2021));
1729         // K: '000102030405060708090A0B0C0D0E0F', defined by TS 134 108#8.2
1730         // n: 128 (Bits to use for RES value)
1731         // Format: [Length][Rand][Length][Autn]
1732         String challenge = "10" + EAP_SIM_AKA_RAND + "10" + EAP_AKA_AUTN;
1733         String base64Challenge = Base64.encodeToString(hexStringToBytes(challenge), Base64.NO_WRAP);
1734         String base64Response = null;
1735         try {
1736             base64Response = mTelephonyManager.getIccAuthentication(
1737                     TelephonyManager.APPTYPE_USIM,
1738                     TelephonyManager.AUTHTYPE_EAP_AKA,
1739                     base64Challenge);
1740         } catch (UnsupportedOperationException ex) {
1741             assumeNoException("EAP-AKA not supported", ex);
1742         }
1743 
1744         assertWithMessage("UICC returned null for EAP-AKA auth").that(base64Response).isNotNull();
1745         byte[] response = Base64.decode(base64Response, Base64.NO_WRAP);
1746 
1747         // response may be formatted as: [DB][Length][RES][Length][CK][Length][IK][Length][Kc]
1748         byte[] akaResponse = Arrays.copyOfRange(response, 0, EAP_AKA_RESPONSE_LENGTH);
1749         assertWithMessage("Results for AUTHTYPE_EAP_AKA failed")
1750                 .that(akaResponse)
1751                 .isEqualTo(hexStringToBytes(EXPECTED_EAP_AKA_RESULT));
1752     }
1753 
1754     /**
1755      * This test checks that applications with carrier privilege can set/get data enable
1756      * state.
1757      */
1758     @Test
testDataEnableRequest()1759     public void testDataEnableRequest() {
1760         for (int i = DATA_ENABLED_REASON_USER; i <= DATA_ENABLED_REASON_THERMAL; i++) {
1761             mTelephonyManager.isDataEnabledForReason(i);
1762         }
1763         boolean isDataEnabled = mTelephonyManager.isDataEnabledForReason(
1764                 TelephonyManager.DATA_ENABLED_REASON_CARRIER);
1765         mTelephonyManager.setDataEnabledForReason(
1766                 TelephonyManager.DATA_ENABLED_REASON_CARRIER, !isDataEnabled);
1767         mTelephonyManager.setDataEnabledForReason(
1768                 TelephonyManager.DATA_ENABLED_REASON_CARRIER, isDataEnabled);
1769     }
1770 
1771     /**
1772      * This test checks that applications with carrier privileges can get network slicing
1773      * configuration.
1774      */
1775     @Test
testGetNetworkSlicingConfiguration()1776     public void testGetNetworkSlicingConfiguration() {
1777         CompletableFuture<NetworkSlicingConfig> resultFuture = new CompletableFuture<>();
1778         mTelephonyManager.getNetworkSlicingConfiguration(
1779                 AsyncTask.SERIAL_EXECUTOR, resultFuture::complete);
1780     }
1781 
isWear()1782     private boolean isWear() {
1783         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
1784     }
1785 
1786     /** Checks whether the telephony feature is supported. */
hasFeature(String feature)1787     private boolean hasFeature(String feature) {
1788         return mPackageManager == null ? false : mPackageManager.hasSystemFeature(feature);
1789     }
1790 
1791     /**
1792      * Tests that the device properly sets and pads the contents of EF_FPLMN
1793      */
1794     @Test
testSetForbiddenPlmns()1795     public void testSetForbiddenPlmns() {
1796         assumeTrue(supportSetFplmn());
1797 
1798         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
1799         assertNotNull(originalFplmns);
1800         try {
1801             int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(FPLMN_TEST);
1802             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
1803             assertEquals("Wrong return value for setFplmns with less than required fplmns: "
1804                     + numFplmnsSet, FPLMN_TEST.size(), numFplmnsSet);
1805             assertEquals("Wrong Fplmns content written", FPLMN_TEST, Arrays.asList(writtenFplmns));
1806         } finally {
1807             // Restore
1808             mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
1809         }
1810     }
1811 
1812     /**
1813      * Tests that the device properly truncates the contents of EF_FPLMN when provided size
1814      * is too big.
1815      */
1816     @Test
testSetForbiddenPlmnsTruncate()1817     public void testSetForbiddenPlmnsTruncate() {
1818         assumeTrue(supportSetFplmn());
1819 
1820         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
1821         assertNotNull(originalFplmns);
1822         try {
1823             List<String> targetFplmns = new ArrayList<>();
1824             for (int i = 0; i < MIN_FPLMN_NUM; i++) {
1825                 targetFplmns.add(PLMN_A);
1826             }
1827             for (int i = MIN_FPLMN_NUM; i < MAX_FPLMN_NUM; i++) {
1828                 targetFplmns.add(PLMN_B);
1829             }
1830             int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
1831             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
1832             assertTrue("Wrong return value for setFplmns with overflowing fplmns: " + numFplmnsSet,
1833                     numFplmnsSet < MAX_FPLMN_NUM);
1834             assertEquals("Number of Fplmns set does not equal number of Fplmns available",
1835                     numFplmnsSet, writtenFplmns.length);
1836             assertEquals("Wrong Fplmns content written", targetFplmns.subList(0, numFplmnsSet),
1837                     Arrays.asList(writtenFplmns));
1838         } finally {
1839             // Restore
1840             mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
1841         }
1842     }
1843 
1844     /**
1845      * Tests that the device properly deletes the contents of EF_FPLMN
1846      */
1847     @Test
testSetForbiddenPlmnsDelete()1848     public void testSetForbiddenPlmnsDelete() {
1849         assumeTrue(supportSetFplmn());
1850 
1851         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
1852         assertNotNull(originalFplmns);
1853         try {
1854             // Support test for empty SIM
1855             List<String> targetDummyFplmns = new ArrayList<>();
1856             for (int i = 0; i < MIN_FPLMN_NUM; i++) {
1857                 targetDummyFplmns.add(PLMN_A);
1858             }
1859             mTelephonyManager.setForbiddenPlmns(targetDummyFplmns);
1860             String[] writtenDummyFplmns = mTelephonyManager.getForbiddenPlmns();
1861             assertEquals(targetDummyFplmns, Arrays.asList(writtenDummyFplmns));
1862 
1863             List<String> targetFplmns = new ArrayList<>();
1864             int numFplmnsSet = mTelephonyManager.setForbiddenPlmns(targetFplmns);
1865             String[] writtenFplmns = mTelephonyManager.getForbiddenPlmns();
1866             assertEquals("Wrong return value for setFplmns with empty list", 0, numFplmnsSet);
1867             assertEquals("Wrong number of Fplmns written", 0, writtenFplmns.length);
1868             // TODO wait for 10 minutes or so for the FPLMNS list to grow back
1869         } finally {
1870             // Restore
1871             mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
1872         }
1873     }
1874 
1875     /**
1876      * Tests that setForbiddenPlmns properly handles null input
1877      */
1878     @Test
testSetForbiddenPlmnsVoid()1879     public void testSetForbiddenPlmnsVoid() {
1880         assumeTrue(supportSetFplmn());
1881 
1882         String[] originalFplmns = mTelephonyManager.getForbiddenPlmns();
1883         assertNotNull(originalFplmns);
1884         try {
1885             mTelephonyManager.setForbiddenPlmns(null);
1886             fail("Expected IllegalArgumentException. Null input is not allowed");
1887         } catch (IllegalArgumentException expected) {
1888         } finally {
1889             mTelephonyManager.setForbiddenPlmns(Arrays.asList(originalFplmns));
1890         }
1891     }
1892 
1893     @Test
testSetAndGetSubscriptionPlan()1894     public void testSetAndGetSubscriptionPlan() {
1895         final int subId = getFirstActivateCarrierPrivilegedSubscriptionId();
1896         // This test case requires subscription with carrier privileges
1897         assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1898 
1899         final SubscriptionPlan plan = createTestSubscriptionPlan();
1900         try {
1901             mSubscriptionManager.setSubscriptionPlans(
1902                     subId, List.of(plan), SUB_PLAN_EXPIRATION_DURATION);
1903         } catch (SecurityException se) {
1904             fail("setSubscriptionPlans with carrier privilege throws " + se);
1905         }
1906 
1907         try {
1908             List<SubscriptionPlan> plans = mSubscriptionManager.getSubscriptionPlans(subId);
1909             assertThat(plans).isNotEmpty();
1910             SubscriptionPlan retrievedPlan = plans.get(0);
1911             assertThat(retrievedPlan).isEqualTo(plan);
1912         } catch (SecurityException se) {
1913             fail("getSubscriptionPlans with carrier privilege throws " + se);
1914         }
1915     }
1916 
1917     @Test
testSetSubscriptionOverrideUnmetered()1918     public void testSetSubscriptionOverrideUnmetered() {
1919         final int subId = getFirstActivateCarrierPrivilegedSubscriptionId();
1920         // This test case requires subscription with carrier privileges
1921         assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1922 
1923         try {
1924             mSubscriptionManager.setSubscriptionOverrideUnmetered(
1925                     subId, true, SUB_PLAN_EXPIRATION_DURATION);
1926         } catch (SecurityException se) {
1927             fail("setSubscriptionOverrideUnmetered with carrier privilege throws " + se);
1928         }
1929     }
1930 
1931     @Test
testSetSubscriptionOverrideCongested()1932     public void testSetSubscriptionOverrideCongested() {
1933         final int subId = getFirstActivateCarrierPrivilegedSubscriptionId();
1934         // This test case requires subscription with carrier privileges
1935         assumeFalse(subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1936 
1937         SubscriptionPlan plan = createTestSubscriptionPlan();
1938         try {
1939             mSubscriptionManager.setSubscriptionPlans(
1940                     subId, List.of(plan), SUB_PLAN_EXPIRATION_DURATION);
1941             mSubscriptionManager.setSubscriptionOverrideCongested(
1942                     subId, true, SUB_PLAN_EXPIRATION_DURATION);
1943         } catch (SecurityException se) {
1944             fail("setSubscriptionOverrideCongested with carrier privilege throws " + se);
1945         }
1946     }
1947 
1948     /**
1949      * Verify that the phone is supporting the action of setForbiddenPlmn.
1950      *
1951      * @return whether to proceed the test
1952      */
supportSetFplmn()1953     private boolean supportSetFplmn() {
1954         if (!hasFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
1955             return false;
1956         }
1957         return mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM;
1958     }
1959 
createTestSubscriptionPlan()1960     private SubscriptionPlan createTestSubscriptionPlan() {
1961         return SubscriptionPlan.Builder.createNonrecurring(SUB_PLAN_START, SUB_PLAN_END)
1962                 .setDataLimit(SUB_PLAN_DATA_LIMIT_BYTES, SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
1963                 .setTitle(SUB_PLAN_TITLE)
1964                 .setSummary(SUB_PLAN_SUMMARY)
1965                 .build();
1966     }
1967 }
1968