blob: 4e1cb8bff32b11b20bb155e9da4ac3b4ab1d085d [file] [log] [blame]
/*
* 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);
}
}