| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.telephony.cts; |
| |
| import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; |
| import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; |
| import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; |
| import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; |
| import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import android.annotation.Nullable; |
| import android.content.pm.PackageManager; |
| import android.net.ConnectivityManager; |
| import android.net.ConnectivityManager.NetworkCallback; |
| import android.net.Network; |
| import android.net.NetworkCapabilities; |
| import android.net.NetworkRequest; |
| import android.support.test.InstrumentationRegistry; |
| import android.support.test.runner.AndroidJUnit4; |
| import android.telephony.SubscriptionInfo; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.SubscriptionPlan; |
| |
| import com.android.compatibility.common.util.SystemUtil; |
| |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.time.Period; |
| import java.time.ZonedDateTime; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.function.Predicate; |
| |
| @RunWith(AndroidJUnit4.class) |
| public class SubscriptionManagerTest { |
| private SubscriptionManager mSm; |
| |
| private int mSubId; |
| private String mPackageName; |
| |
| @BeforeClass |
| public static void setUpClass() throws Exception { |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .executeShellCommand("svc wifi disable"); |
| } |
| |
| @AfterClass |
| public static void tearDownClass() throws Exception { |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .executeShellCommand("svc wifi enable"); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| mSm = InstrumentationRegistry.getContext().getSystemService(SubscriptionManager.class); |
| mSubId = SubscriptionManager.getDefaultDataSubscriptionId(); |
| mPackageName = InstrumentationRegistry.getContext().getPackageName(); |
| } |
| |
| /** |
| * Sanity check that the device has a cellular network and a valid default data subId |
| * when {@link PackageManager#FEATURE_TELEPHONY} support. |
| */ |
| @Test |
| public void testSanity() throws Exception { |
| if (!isSupported()) return; |
| |
| final boolean hasCellular = findCellularNetwork() != null; |
| if (!hasCellular) { |
| fail("Device claims to support " + PackageManager.FEATURE_TELEPHONY |
| + " but has no active cellular network, which is required for validation"); |
| } |
| |
| if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { |
| fail("Device must have a valid default data subId for validation"); |
| } |
| } |
| |
| @Test |
| public void testGetActiveSubscriptionInfoCount() throws Exception { |
| if (!isSupported()) return; |
| |
| assertTrue(mSm.getActiveSubscriptionInfoCount() <= |
| mSm.getActiveSubscriptionInfoCountMax()); |
| } |
| |
| @Test |
| public void testActiveSubscriptions() throws Exception { |
| if (!isSupported()) return; |
| |
| List<SubscriptionInfo> subList = mSm.getActiveSubscriptionInfoList(); |
| // Assert when there is no sim card present or detected |
| assertNotNull("Active subscriber required", subList); |
| assertFalse("Active subscriber required", subList.isEmpty()); |
| for (int i = 0; i < subList.size(); i++) { |
| assertTrue(subList.get(i).getSubscriptionId() >= 0); |
| assertTrue(subList.get(i).getSimSlotIndex() >= 0); |
| } |
| } |
| |
| @Test |
| public void testSubscriptionPlans() throws Exception { |
| if (!isSupported()) return; |
| |
| // Make ourselves the owner |
| setSubPlanOwner(mSubId, mPackageName); |
| |
| // Push empty list and we get empty back |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList()); |
| assertEquals(Arrays.asList(), mSm.getSubscriptionPlans(mSubId)); |
| |
| // Push simple plan and get it back |
| final SubscriptionPlan plan = buildValidSubscriptionPlan(); |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList(plan)); |
| assertEquals(Arrays.asList(plan), mSm.getSubscriptionPlans(mSubId)); |
| |
| // Now revoke our access |
| setSubPlanOwner(mSubId, null); |
| try { |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList()); |
| fail(); |
| } catch (SecurityException expected) { |
| } |
| try { |
| mSm.getSubscriptionPlans(mSubId); |
| fail(); |
| } catch (SecurityException expected) { |
| } |
| } |
| |
| @Test |
| public void testSubscriptionPlansOverrideCongested() throws Exception { |
| if (!isSupported()) return; |
| |
| final ConnectivityManager cm = InstrumentationRegistry.getContext() |
| .getSystemService(ConnectivityManager.class); |
| final Network net = findCellularNetwork(); |
| assertNotNull("Active cellular network required", net); |
| |
| // Make ourselves the owner |
| setSubPlanOwner(mSubId, mPackageName); |
| |
| // Missing plans means no overrides |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList()); |
| try { |
| mSm.setSubscriptionOverrideCongested(mSubId, true, 0); |
| fail(); |
| } catch (SecurityException | IllegalStateException expected) { |
| } |
| |
| // Defining plans means we get to override |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildValidSubscriptionPlan())); |
| |
| // Cellular is uncongested by default |
| assertTrue(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_CONGESTED)); |
| |
| // Override should make it go congested |
| { |
| final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> { |
| return !caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED); |
| }); |
| mSm.setSubscriptionOverrideCongested(mSubId, true, 0); |
| assertTrue(latch.await(10, TimeUnit.SECONDS)); |
| } |
| |
| // Clearing override should make it go uncongested |
| { |
| final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> { |
| return caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED); |
| }); |
| mSm.setSubscriptionOverrideCongested(mSubId, false, 0); |
| assertTrue(latch.await(10, TimeUnit.SECONDS)); |
| } |
| |
| // Now revoke our access |
| setSubPlanOwner(mSubId, null); |
| try { |
| mSm.setSubscriptionOverrideCongested(mSubId, true, 0); |
| fail(); |
| } catch (SecurityException | IllegalStateException expected) { |
| } |
| } |
| |
| @Test |
| public void testSubscriptionPlansOverrideUnmetered() throws Exception { |
| if (!isSupported()) return; |
| |
| final ConnectivityManager cm = InstrumentationRegistry.getContext() |
| .getSystemService(ConnectivityManager.class); |
| final Network net = findCellularNetwork(); |
| assertNotNull("Active cellular network required", net); |
| |
| // Make ourselves the owner and define some plans |
| setSubPlanOwner(mSubId, mPackageName); |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList(buildValidSubscriptionPlan())); |
| |
| // Cellular is metered by default |
| assertFalse(cm.getNetworkCapabilities(net).hasCapability(NET_CAPABILITY_NOT_METERED)); |
| |
| // Override should make it go unmetered |
| { |
| final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> { |
| return caps.hasCapability(NET_CAPABILITY_NOT_METERED); |
| }); |
| mSm.setSubscriptionOverrideUnmetered(mSubId, true, 0); |
| assertTrue(latch.await(10, TimeUnit.SECONDS)); |
| } |
| |
| // Clearing override should make it go metered |
| { |
| final CountDownLatch latch = waitForNetworkCapabilities(net, caps -> { |
| return !caps.hasCapability(NET_CAPABILITY_NOT_METERED); |
| }); |
| mSm.setSubscriptionOverrideUnmetered(mSubId, false, 0); |
| assertTrue(latch.await(10, TimeUnit.SECONDS)); |
| } |
| } |
| |
| @Test |
| public void testSubscriptionPlansInvalid() throws Exception { |
| if (!isSupported()) return; |
| |
| // Make ourselves the owner |
| setSubPlanOwner(mSubId, mPackageName); |
| |
| // Empty plans can't override |
| assertOverrideFails(); |
| |
| // Nonrecurring plan in the past can't override |
| assertOverrideFails(SubscriptionPlan.Builder |
| .createNonrecurring(ZonedDateTime.now().minusDays(14), |
| ZonedDateTime.now().minusDays(7)) |
| .setTitle("CTS") |
| .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) |
| .build()); |
| |
| // Plan with undefined limit can't override |
| assertOverrideFails(SubscriptionPlan.Builder |
| .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), |
| Period.ofMonths(1)) |
| .setTitle("CTS") |
| .build()); |
| |
| // We can override when there is an active plan somewhere |
| final SubscriptionPlan older = SubscriptionPlan.Builder |
| .createNonrecurring(ZonedDateTime.now().minusDays(14), |
| ZonedDateTime.now().minusDays(7)) |
| .setTitle("CTS") |
| .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) |
| .build(); |
| final SubscriptionPlan newer = SubscriptionPlan.Builder |
| .createNonrecurring(ZonedDateTime.now().minusDays(7), |
| ZonedDateTime.now().plusDays(7)) |
| .setTitle("CTS") |
| .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) |
| .build(); |
| assertOverrideSuccess(older, newer); |
| } |
| |
| private void assertOverrideSuccess(SubscriptionPlan... plans) { |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList(plans)); |
| mSm.setSubscriptionOverrideCongested(mSubId, false, 0); |
| } |
| |
| private void assertOverrideFails(SubscriptionPlan... plans) { |
| mSm.setSubscriptionPlans(mSubId, Arrays.asList(plans)); |
| try { |
| mSm.setSubscriptionOverrideCongested(mSubId, false, 0); |
| fail(); |
| } catch (SecurityException | IllegalStateException expected) { |
| } |
| } |
| |
| public static CountDownLatch waitForNetworkCapabilities(Network network, |
| Predicate<NetworkCapabilities> predicate) { |
| final CountDownLatch latch = new CountDownLatch(1); |
| final ConnectivityManager cm = InstrumentationRegistry.getContext() |
| .getSystemService(ConnectivityManager.class); |
| cm.registerNetworkCallback(new NetworkRequest.Builder().build(), |
| new NetworkCallback() { |
| @Override |
| public void onCapabilitiesChanged(Network net, NetworkCapabilities caps) { |
| if (net.equals(network) && predicate.test(caps)) { |
| latch.countDown(); |
| cm.unregisterNetworkCallback(this); |
| } |
| } |
| }); |
| return latch; |
| } |
| |
| private static SubscriptionPlan buildValidSubscriptionPlan() { |
| return SubscriptionPlan.Builder |
| .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), |
| Period.ofMonths(1)) |
| .setTitle("CTS") |
| .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) |
| .setDataUsage(500_000_000, System.currentTimeMillis()) |
| .build(); |
| } |
| |
| private static @Nullable Network findCellularNetwork() { |
| final ConnectivityManager cm = InstrumentationRegistry.getContext() |
| .getSystemService(ConnectivityManager.class); |
| for (Network net : cm.getAllNetworks()) { |
| final NetworkCapabilities caps = cm.getNetworkCapabilities(net); |
| if (caps != null && caps.hasTransport(TRANSPORT_CELLULAR) |
| && caps.hasCapability(NET_CAPABILITY_INTERNET) |
| && caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { |
| return net; |
| } |
| } |
| return null; |
| } |
| |
| private static boolean isSupported() { |
| return InstrumentationRegistry.getContext().getPackageManager() |
| .hasSystemFeature(PackageManager.FEATURE_TELEPHONY); |
| } |
| |
| private static void setSubPlanOwner(int subId, String packageName) throws Exception { |
| SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), |
| "cmd netpolicy set sub-plan-owner " + subId + " " + packageName); |
| } |
| } |