• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.telephony.cts;
18 
19 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
20 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
21 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
23 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
24 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
25 
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31 import static org.junit.Assert.fail;
32 
33 import android.annotation.Nullable;
34 import android.content.pm.PackageManager;
35 import android.net.ConnectivityManager;
36 import android.net.ConnectivityManager.NetworkCallback;
37 import android.net.Network;
38 import android.net.NetworkCapabilities;
39 import android.net.NetworkRequest;
40 import android.os.ParcelUuid;
41 import android.telephony.SubscriptionInfo;
42 import android.telephony.SubscriptionManager;
43 import android.telephony.SubscriptionPlan;
44 import android.telephony.TelephonyManager;
45 
46 import androidx.test.InstrumentationRegistry;
47 
48 import com.android.compatibility.common.util.ShellIdentityUtils;
49 import com.android.compatibility.common.util.SystemUtil;
50 import com.android.internal.util.ArrayUtils;
51 
52 import org.junit.AfterClass;
53 import org.junit.Before;
54 import org.junit.BeforeClass;
55 import org.junit.Test;
56 
57 import java.time.Period;
58 import java.time.ZonedDateTime;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.List;
62 import java.util.UUID;
63 import java.util.concurrent.CountDownLatch;
64 import java.util.concurrent.Executor;
65 import java.util.concurrent.LinkedBlockingQueue;
66 import java.util.concurrent.TimeUnit;
67 import java.util.function.Consumer;
68 import java.util.function.Predicate;
69 import java.util.stream.Collectors;
70 
71 public class SubscriptionManagerTest {
72     private SubscriptionManager mSm;
73 
74     private int mSubId;
75     private String mPackageName;
76 
77     /**
78      * Callback used in testRegisterNetworkCallback that allows caller to block on
79      * {@code onAvailable}.
80      */
81     private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
82         private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
83 
waitForAvailable()84         public void waitForAvailable() throws InterruptedException {
85             assertTrue("Cellular network did not come up after 5 seconds",
86                     mAvailableLatch.await(5, TimeUnit.SECONDS));
87         }
88 
89         @Override
onAvailable(Network network)90         public void onAvailable(Network network) {
91             mAvailableLatch.countDown();
92         }
93     }
94 
95     @BeforeClass
setUpClass()96     public static void setUpClass() throws Exception {
97         if (!isSupported()) return;
98 
99         InstrumentationRegistry.getInstrumentation().getUiAutomation()
100                 .executeShellCommand("svc wifi disable");
101 
102         final TestNetworkCallback callback = new TestNetworkCallback();
103         final ConnectivityManager cm = InstrumentationRegistry.getContext()
104                 .getSystemService(ConnectivityManager.class);
105         cm.registerNetworkCallback(new NetworkRequest.Builder()
106                 .addTransportType(TRANSPORT_CELLULAR)
107                 .addCapability(NET_CAPABILITY_INTERNET)
108                 .build(), callback);
109         try {
110             // Wait to get callback for availability of internet
111             callback.waitForAvailable();
112         } catch (InterruptedException e) {
113             fail("NetworkCallback wait was interrupted.");
114         } finally {
115             cm.unregisterNetworkCallback(callback);
116         }
117     }
118 
119     @AfterClass
tearDownClass()120     public static void tearDownClass() throws Exception {
121         if (!isSupported()) return;
122 
123         InstrumentationRegistry.getInstrumentation().getUiAutomation()
124                 .executeShellCommand("svc wifi enable");
125     }
126 
127     @Before
setUp()128     public void setUp() throws Exception {
129         if (!isSupported()) return;
130 
131         mSm = InstrumentationRegistry.getContext().getSystemService(SubscriptionManager.class);
132         mSubId = SubscriptionManager.getDefaultDataSubscriptionId();
133         mPackageName = InstrumentationRegistry.getContext().getPackageName();
134     }
135 
136     /**
137      * Sanity check that the device has a cellular network and a valid default data subId
138      * when {@link PackageManager#FEATURE_TELEPHONY} support.
139      */
140     @Test
testSanity()141     public void testSanity() throws Exception {
142         if (!isSupported()) return;
143 
144         final boolean hasCellular = findCellularNetwork() != null;
145         if (!hasCellular) {
146             fail("Device claims to support " + PackageManager.FEATURE_TELEPHONY
147                     + " but has no active cellular network, which is required for validation");
148         }
149 
150         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
151             fail("Device must have a valid default data subId for validation");
152         }
153     }
154 
155     @Test
testGetActiveSubscriptionInfoCount()156     public void testGetActiveSubscriptionInfoCount() throws Exception {
157         if (!isSupported()) return;
158         assertTrue(mSm.getActiveSubscriptionInfoCount() <=
159                 mSm.getActiveSubscriptionInfoCountMax());
160     }
161 
162     @Test
testIsActiveSubscriptionId()163     public void testIsActiveSubscriptionId() throws Exception {
164         if (!isSupported()) return;
165         assertTrue(mSm.isActiveSubscriptionId(mSubId));
166     }
167 
168     @Test
testGetSubscriptionIds()169     public void testGetSubscriptionIds() throws Exception {
170         if (!isSupported()) return;
171         int slotId = SubscriptionManager.getSlotIndex(mSubId);
172         int[] subIds = mSm.getSubscriptionIds(slotId);
173         assertNotNull(subIds);
174         assertTrue(ArrayUtils.contains(subIds, mSubId));
175     }
176 
177     @Test
testIsUsableSubscriptionId()178     public void testIsUsableSubscriptionId() throws Exception {
179         if (!isSupported()) return;
180         assertTrue(SubscriptionManager.isUsableSubscriptionId(mSubId));
181     }
182 
183     @Test
testActiveSubscriptions()184     public void testActiveSubscriptions() throws Exception {
185         if (!isSupported()) return;
186 
187         List<SubscriptionInfo> subList = mSm.getActiveSubscriptionInfoList();
188         // Assert when there is no sim card present or detected
189         assertNotNull("Active subscriber required", subList);
190         assertFalse("Active subscriber required", subList.isEmpty());
191         for (int i = 0; i < subList.size(); i++) {
192             assertTrue(subList.get(i).getSubscriptionId() >= 0);
193             assertTrue(subList.get(i).getSimSlotIndex() >= 0);
194             if (i >= 1) {
195                 assertTrue(subList.get(i - 1).getSimSlotIndex()
196                         <= subList.get(i).getSimSlotIndex());
197                 assertTrue(subList.get(i - 1).getSimSlotIndex() < subList.get(i).getSimSlotIndex()
198                         || subList.get(i - 1).getSubscriptionId()
199                         < subList.get(i).getSubscriptionId());
200             }
201         }
202     }
203 
204     @Test
205     public void testSubscriptionPlans() throws Exception {
206         if (!isSupported()) return;
207 
208         // Make ourselves the owner
209         setSubPlanOwner(mSubId, mPackageName);
210 
211         // Push empty list and we get empty back
212         mSm.setSubscriptionPlans(mSubId, Arrays.asList());
213         assertEquals(Arrays.asList(), mSm.getSubscriptionPlans(mSubId));
214 
215         // Push simple plan and get it back
216         final SubscriptionPlan plan = buildValidSubscriptionPlan();
217         mSm.setSubscriptionPlans(mSubId, Arrays.asList(plan));
218         assertEquals(Arrays.asList(plan), mSm.getSubscriptionPlans(mSubId));
219 
220         // Now revoke our access
221         setSubPlanOwner(mSubId, null);
222         try {
223             mSm.setSubscriptionPlans(mSubId, Arrays.asList());
224             fail();
225         } catch (SecurityException expected) {
226         }
227         try {
228             mSm.getSubscriptionPlans(mSubId);
229             fail();
230         } catch (SecurityException expected) {
231         }
232     }
233 
234     @Test
235     public void testSubscriptionPlansOverrideCongested() throws Exception {
236         if (!isSupported()) return;
237 
238         final ConnectivityManager cm = InstrumentationRegistry.getContext()
239                 .getSystemService(ConnectivityManager.class);
240         final Network net = findCellularNetwork();
241         assertNotNull("Active cellular network required", net);
242 
243         // Make ourselves the owner
244         setSubPlanOwner(mSubId, mPackageName);
245 
246         // Missing plans means no overrides
247         mSm.setSubscriptionPlans(mSubId, Arrays.asList());
248         try {
249             mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
250             fail();
251         } catch (SecurityException | IllegalStateException expected) {
252         }
253 
254         // Defining plans means we get to override
255         mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildValidSubscriptionPlan()));
256 
257         // Cellular is uncongested by default
258         assertTrue(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_CONGESTED));
259 
260         // Override should make it go congested
261         {
262             final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
263                 return !caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
264             });
265             mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
266             assertTrue(latch.await(10, TimeUnit.SECONDS));
267         }
268 
269         // Clearing override should make it go uncongested
270         {
271             final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
272                 return caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
273             });
274             mSm.setSubscriptionOverrideCongested(mSubId, false, 0);
275             assertTrue(latch.await(10, TimeUnit.SECONDS));
276         }
277 
278         // Now revoke our access
279         setSubPlanOwner(mSubId, null);
280         try {
281             mSm.setSubscriptionOverrideCongested(mSubId, true, 0);
282             fail();
283         } catch (SecurityException | IllegalStateException expected) {
284         }
285     }
286 
287     @Test
testSubscriptionPlansOverrideUnmetered()288     public void testSubscriptionPlansOverrideUnmetered() throws Exception {
289         if (!isSupported()) return;
290 
291         final ConnectivityManager cm = InstrumentationRegistry.getContext()
292                 .getSystemService(ConnectivityManager.class);
293         final Network net = findCellularNetwork();
294         assertNotNull("Active cellular network required", net);
295 
296         // Make ourselves the owner and define some plans
297         setSubPlanOwner(mSubId, mPackageName);
298         mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildValidSubscriptionPlan()));
299 
300         // Cellular is metered by default
301         assertFalse(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_METERED));
302 
303         // Override should make it go unmetered
304         {
305             final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
306                 return caps.hasCapability(NET_CAPABILITY_NOT_METERED);
307             });
308             mSm.setSubscriptionOverrideUnmetered(mSubId, true, 0);
309             assertTrue(latch.await(10, TimeUnit.SECONDS));
310         }
311 
312         // Clearing override should make it go metered
313         {
314             final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> {
315                 return !caps.hasCapability(NET_CAPABILITY_NOT_METERED);
316             });
317             mSm.setSubscriptionOverrideUnmetered(mSubId, false, 0);
318             assertTrue(latch.await(10, TimeUnit.SECONDS));
319         }
320     }
321 
322     @Test
testSubscriptionPlansInvalid()323     public void testSubscriptionPlansInvalid() throws Exception {
324         if (!isSupported()) return;
325 
326         // Make ourselves the owner
327         setSubPlanOwner(mSubId, mPackageName);
328 
329         // Empty plans can't override
330         assertOverrideFails();
331 
332         // Nonrecurring plan in the past can't override
333         assertOverrideFails(SubscriptionPlan.Builder
334                 .createNonrecurring(ZonedDateTime.now().minusDays(14),
335                         ZonedDateTime.now().minusDays(7))
336                 .setTitle("CTS")
337                 .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
338                 .build());
339 
340         // Plan with undefined limit can't override
341         assertOverrideFails(SubscriptionPlan.Builder
342                 .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
343                         Period.ofMonths(1))
344                 .setTitle("CTS")
345                 .build());
346 
347         // We can override when there is an active plan somewhere
348         final SubscriptionPlan older = SubscriptionPlan.Builder
349                 .createNonrecurring(ZonedDateTime.now().minusDays(14),
350                         ZonedDateTime.now().minusDays(7))
351                 .setTitle("CTS")
352                 .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
353                 .build();
354         final SubscriptionPlan newer = SubscriptionPlan.Builder
355                 .createNonrecurring(ZonedDateTime.now().minusDays(7),
356                         ZonedDateTime.now().plusDays(7))
357                 .setTitle("CTS")
358                 .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
359                 .build();
360         assertOverrideSuccess(older, newer);
361     }
362 
363     @Test
testSubscriptionGrouping()364     public void testSubscriptionGrouping() throws Exception {
365         if (!isSupported()) return;
366 
367         // Set subscription group with current sub Id. This should fail
368         // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
369         List<Integer> subGroup = new ArrayList();
370         subGroup.add(mSubId);
371         try {
372             mSm.createSubscriptionGroup(subGroup);
373             fail();
374         } catch (SecurityException expected) {
375         }
376 
377         // Getting subscriptions in group should return null as setSubscriptionGroup
378         // should fail.
379         SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
380         assertNull(info.getGroupUuid());
381 
382         // Remove from subscription group with current sub Id. This should fail
383         // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
384         try {
385             mSm.addSubscriptionsIntoGroup(subGroup, null);
386             fail();
387         } catch (NullPointerException expected) {
388         }
389 
390         // Add into subscription group that doesn't exist. This should fail
391         // with IllegalArgumentException.
392         try {
393             ParcelUuid groupUuid = new ParcelUuid(UUID.randomUUID());
394             mSm.addSubscriptionsIntoGroup(subGroup, groupUuid);
395             fail();
396         } catch (IllegalArgumentException expected) {
397         }
398 
399         // Remove from subscription group with current sub Id. This should fail
400         // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
401         try {
402             mSm.removeSubscriptionsFromGroup(subGroup, null);
403             fail();
404         } catch (NullPointerException expected) {
405         }
406     }
407 
408     @Test
testSubscriptionGroupingWithPermission()409     public void testSubscriptionGroupingWithPermission() throws Exception {
410         if (!isSupported()) return;
411 
412         // Set subscription group with current sub Id.
413         List<Integer> subGroup = new ArrayList();
414         subGroup.add(mSubId);
415         ParcelUuid uuid = ShellIdentityUtils.invokeMethodWithShellPermissions(mSm,
416                 (sm) -> sm.createSubscriptionGroup(subGroup));
417 
418         // Getting subscriptions in group.
419         List<SubscriptionInfo> infoList = mSm.getSubscriptionsInGroup(uuid);
420         assertNotNull(infoList);
421         assertEquals(1, infoList.size());
422         assertEquals(uuid, infoList.get(0).getGroupUuid());
423 
424         List<SubscriptionInfo> availableInfoList = mSm.getAvailableSubscriptionInfoList();
425         if (availableInfoList.size() > 1) {
426             List<Integer> availableSubGroup = availableInfoList.stream()
427                     .map(info -> info.getSubscriptionId())
428                     .filter(subId -> subId != mSubId)
429                     .collect(Collectors.toList());
430 
431             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
432                     (sm) -> sm.addSubscriptionsIntoGroup(availableSubGroup, uuid));
433 
434             infoList = mSm.getSubscriptionsInGroup(uuid);
435             assertNotNull(infoList);
436             assertEquals(availableInfoList.size(), infoList.size());
437 
438             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
439                     (sm) -> sm.removeSubscriptionsFromGroup(availableSubGroup, uuid));
440         }
441 
442         // Remove from subscription group with current sub Id.
443         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
444                 (sm) -> sm.removeSubscriptionsFromGroup(subGroup, uuid));
445 
446         infoList = mSm.getSubscriptionsInGroup(uuid);
447         assertNotNull(infoList);
448         assertTrue(infoList.isEmpty());
449     }
450 
451     @Test
testSettingOpportunisticSubscription()452     public void testSettingOpportunisticSubscription() throws Exception {
453         if (!isSupported()) return;
454 
455         // Set subscription to be opportunistic. This should fail
456         // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
457         try {
458             mSm.setOpportunistic(true, mSubId);
459             fail();
460         } catch (SecurityException expected) {
461         }
462 
463         // Shouldn't crash.
464         SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
465         info.isOpportunistic();
466     }
467 
468     @Test
testMccMncString()469     public void testMccMncString() {
470         if (!isSupported()) return;
471 
472         SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
473         String mcc = info.getMccString();
474         String mnc = info.getMncString();
475         assertTrue(mcc == null || mcc.length() <= 3);
476         assertTrue(mnc == null || mnc.length() <= 3);
477     }
478 
479     @Test
testSubscriptionInfoCarrierId()480     public void testSubscriptionInfoCarrierId() {
481         if (!isSupported()) return;
482 
483         SubscriptionInfo info = mSm.getActiveSubscriptionInfo(mSubId);
484         int carrierId = info.getCarrierId();
485         assertTrue(carrierId >= TelephonyManager.UNKNOWN_CARRIER_ID);
486     }
487 
488     @Test
testGetOpportunisticSubscriptions()489     public void testGetOpportunisticSubscriptions() throws Exception {
490         if (!isSupported()) return;
491 
492         List<SubscriptionInfo> infoList = mSm.getOpportunisticSubscriptions();
493 
494         for (SubscriptionInfo info : infoList) {
495             assertTrue(info.isOpportunistic());
496         }
497     }
498 
499     @Test
testGetEnabledSubscriptionId()500     public void testGetEnabledSubscriptionId() {
501         if (!isSupported()) return;
502         int slotId = SubscriptionManager.getSlotIndex(mSubId);
503         if (!SubscriptionManager.isValidSlotIndex(slotId)) {
504             fail("Invalid slot id " + slotId + " for subscription id " + mSubId);
505         }
506         int enabledSubId = executeWithShellPermissionAndDefault(-1, mSm,
507                 (sm) -> sm.getEnabledSubscriptionId(slotId));
508         assertEquals(mSubId, enabledSubId);
509     }
510 
511     @Test
testSetAndCheckSubscriptionEnabled()512     public void testSetAndCheckSubscriptionEnabled() {
513         if (!isSupported()) return;
514         boolean enabled = executeWithShellPermissionAndDefault(false, mSm,
515                 (sm) -> sm.isSubscriptionEnabled(mSubId));
516         if (isDSDS()) {
517             // Change it to a different value
518             changeAndVerifySubscriptionEnabledValue(mSubId, !enabled);
519             // Reset it back to original
520             changeAndVerifySubscriptionEnabledValue(mSubId, enabled);
521         } else {
522             boolean changeSuccessfully = executeWithShellPermissionAndDefault(false, mSm,
523                     (sm) -> sm.setSubscriptionEnabled(mSubId, !enabled));
524             assertFalse(changeSuccessfully);
525         }
526     }
527 
528     @Test
testSetPreferredDataSubscriptionId()529     public void testSetPreferredDataSubscriptionId() {
530         if (!isSupported()) return;
531         int preferredSubId = executeWithShellPermissionAndDefault(-1, mSm,
532                 (sm) -> sm.getPreferredDataSubscriptionId());
533 
534         final LinkedBlockingQueue<Integer> resultQueue = new LinkedBlockingQueue<>(1);
535         Executor executor = new Executor() {
536             @Override
537             public void execute(Runnable command) {
538                 command.run();
539             }
540         };
541 
542         Consumer<Integer> consumer = new Consumer<Integer>() {
543             @Override
544             public void accept(Integer res) {
545                 if (res == null) {
546                     resultQueue.offer(-1);
547                 } else {
548                     resultQueue.offer(res);
549                 }
550             }
551         };
552 
553         List<SubscriptionInfo> subscriptionInfos = mSm.getActiveSubscriptionInfoList();
554         boolean changes = false;
555 
556         for (SubscriptionInfo subInfo : subscriptionInfos) {
557             int subId = subInfo.getSubscriptionId();
558             if (subId != preferredSubId) {
559                 int newPreferredSubId = subId;
560                 // Change to a new value.
561                 ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
562                         (sm) -> sm.setPreferredDataSubscriptionId(newPreferredSubId, false,
563                                 executor, consumer));
564                 int res = -1;
565                 try {
566                     res = resultQueue.poll(2, TimeUnit.SECONDS);
567                 } catch (InterruptedException e) {
568                     fail("Cannot get the modem result in time");
569                 }
570                 assertEquals(SET_OPPORTUNISTIC_SUB_SUCCESS, res);
571                 int newGetValue = executeWithShellPermissionAndDefault(-1, mSm,
572                         (sm) -> sm.getPreferredDataSubscriptionId());
573                 assertEquals(newPreferredSubId, newGetValue);
574                 changes = true;
575                 break;
576             }
577         }
578 
579         // Reset back, or set the duplicate.
580         if (SubscriptionManager.isValidSubscriptionId(preferredSubId)) {
581             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSm,
582                     (sm) -> sm.setPreferredDataSubscriptionId(preferredSubId, false,
583                             executor, consumer));
584             int res = -1;
585             try {
586                 res = resultQueue.poll(2, TimeUnit.SECONDS);
587             } catch (InterruptedException e) {
588                 fail("Cannot get the modem result in time");
589             }
590             // Duplicate setting ends up with nothing.
591             if (!changes) {
592                 assertEquals(-1, res);
593             } else {
594                 assertEquals(SET_OPPORTUNISTIC_SUB_SUCCESS, res);
595                 int resetGetValue = executeWithShellPermissionAndDefault(-1, mSm,
596                         (sm) -> sm.getPreferredDataSubscriptionId());
597                 assertEquals(resetGetValue, preferredSubId);
598             }
599         }
600     }
601 
changeAndVerifySubscriptionEnabledValue(int subId, boolean targetValue)602     private void changeAndVerifySubscriptionEnabledValue(int subId, boolean targetValue) {
603         boolean changeSuccessfully = executeWithShellPermissionAndDefault(false, mSm,
604                 (sm) -> sm.setSubscriptionEnabled(subId, targetValue));
605         if (!changeSuccessfully) {
606             fail("Cannot change subscription " + subId
607                     + " from " + !targetValue + " to " + targetValue);
608         }
609         boolean res = executeWithShellPermissionAndDefault(targetValue, mSm,
610                 (sm) -> sm.isSubscriptionEnabled(subId));
611         assertEquals(targetValue, res);
612     }
613 
executeWithShellPermissionAndDefault(T defaultValue, U targetObject, ShellIdentityUtils.ShellPermissionMethodHelper<T, U> helper)614     private <T, U> T executeWithShellPermissionAndDefault(T defaultValue, U targetObject,
615             ShellIdentityUtils.ShellPermissionMethodHelper<T, U> helper) {
616         try {
617             return ShellIdentityUtils.invokeMethodWithShellPermissions(targetObject, helper);
618         } catch (Exception e) {
619             // do nothing, return default
620         }
621         return defaultValue;
622     }
623 
assertOverrideSuccess(SubscriptionPlan... plans)624     private void assertOverrideSuccess(SubscriptionPlan... plans) {
625         mSm.setSubscriptionPlans(mSubId, Arrays.asList(plans));
626         mSm.setSubscriptionOverrideCongested(mSubId, false, 0);
627     }
628 
assertOverrideFails(SubscriptionPlan... plans)629     private void assertOverrideFails(SubscriptionPlan... plans) {
630         mSm.setSubscriptionPlans(mSubId, Arrays.asList(plans));
631         try {
632             mSm.setSubscriptionOverrideCongested(mSubId, false, 0);
633             fail();
634         } catch (SecurityException | IllegalStateException expected) {
635         }
636     }
637 
waitForNetworkCapabilities(Network network, Predicate<NetworkCapabilities> predicate)638     public static CountDownLatch waitForNetworkCapabilities(Network network,
639             Predicate<NetworkCapabilities> predicate) {
640         final CountDownLatch latch = new CountDownLatch(1);
641         final ConnectivityManager cm = InstrumentationRegistry.getContext()
642                 .getSystemService(ConnectivityManager.class);
643         cm.registerNetworkCallback(new NetworkRequest.Builder().build(),
644                 new NetworkCallback() {
645                     @Override
646                     public void onCapabilitiesChanged(Network net, NetworkCapabilities caps) {
647                         if (net.equals(network) && predicate.test(caps)) {
648                             latch.countDown();
649                             cm.unregisterNetworkCallback(this);
650                         }
651                     }
652                 });
653         return latch;
654     }
655 
buildValidSubscriptionPlan()656     private static SubscriptionPlan buildValidSubscriptionPlan() {
657         return SubscriptionPlan.Builder
658                 .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"),
659                         Period.ofMonths(1))
660                 .setTitle("CTS")
661                 .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
662                 .setDataUsage(500_000_000, System.currentTimeMillis())
663                 .build();
664     }
665 
findCellularNetwork()666     private static @Nullable Network findCellularNetwork() {
667         final ConnectivityManager cm = InstrumentationRegistry.getContext()
668                 .getSystemService(ConnectivityManager.class);
669         for (Network net : cm.getAllNetworks()) {
670             final NetworkCapabilities caps = cm.getNetworkCapabilities(net);
671             if (caps != null && caps.hasTransport(TRANSPORT_CELLULAR)
672                     && caps.hasCapability(NET_CAPABILITY_INTERNET)
673                     && caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
674                 return net;
675             }
676         }
677         return null;
678     }
679 
isSupported()680     private static boolean isSupported() {
681         return InstrumentationRegistry.getContext().getPackageManager()
682                 .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
683     }
684 
isDSDS()685     private static boolean isDSDS() {
686         TelephonyManager tm = InstrumentationRegistry.getContext()
687                 .getSystemService(TelephonyManager.class);
688         return tm != null && tm.getPhoneCount() > 1;
689     }
690 
setSubPlanOwner(int subId, String packageName)691     private static void setSubPlanOwner(int subId, String packageName) throws Exception {
692         SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
693                 "cmd netpolicy set sub-plan-owner " + subId + " " + packageName);
694     }
695 }
696