Merge "Add a carrier config to block tethering." am: 1c12d0790e

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1967167

Change-Id: Icdd36a3e7325b11cefbb4962ec66e1a031b3a773
This commit is contained in:
Tom Hsu 2022-03-16 07:54:00 +00:00 • committed by Automerger Merge Worker
commit b9331a8fd1
3 changed files with 257 additions and 72 deletions

View file

@ -16,6 +16,7 @@
package com.android.networkstack.tethering;
import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
@ -32,6 +33,9 @@ import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI;
import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@ -39,6 +43,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.util.SharedLog;
import android.os.Bundle;
import android.os.Handler;
@ -52,6 +57,7 @@ import android.telephony.CarrierConfigManager;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import java.io.PrintWriter;
import java.util.BitSet;
@ -74,6 +80,13 @@ public class EntitlementManager {
protected static final String ACTION_PROVISIONING_ALARM =
"com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
// Indicate tether provisioning is not required by carrier.
private static final int TETHERING_PROVISIONING_REQUIRED = 1000;
// Indicate tether provisioning is required by carrier.
private static final int TETHERING_PROVISIONING_NOT_REQUIRED = 1001;
// Indicate tethering is not supported by carrier.
private static final int TETHERING_PROVISIONING_CARRIER_UNSUPPORT = 1002;
private final ComponentName mSilentProvisioningService;
private static final int MS_PER_HOUR = 60 * 60 * 1000;
private static final int DUMP_TIMEOUT = 10_000;
@ -96,7 +109,7 @@ public class EntitlementManager {
private boolean mLastCellularUpstreamPermitted = true;
private boolean mUsingCellularAsUpstream = false;
private boolean mNeedReRunProvisioningUi = false;
private OnUiEntitlementFailedListener mListener;
private OnTetherProvisioningFailedListener mListener;
private TetheringConfigurationFetcher mFetcher;
public EntitlementManager(Context ctx, Handler h, SharedLog log,
@ -115,18 +128,20 @@ public class EntitlementManager {
mContext.getResources().getString(R.string.config_wifi_tether_enable));
}
public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
public void setOnTetherProvisioningFailedListener(
final OnTetherProvisioningFailedListener listener) {
mListener = listener;
}
/** Callback fired when UI entitlement failed. */
public interface OnUiEntitlementFailedListener {
public interface OnTetherProvisioningFailedListener {
/**
* Ui entitlement check fails in |downstream|.
*
* @param downstream tethering type from TetheringManager.TETHERING_{@code *}.
* @param reason Failed reason.
*/
void onUiEntitlementFailed(int downstream);
void onTetherProvisioningFailed(int downstream, String reason);
}
public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) {
@ -153,6 +168,9 @@ public class EntitlementManager {
}
private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) {
// If #getTetherProvisioningCondition return TETHERING_PROVISIONING_CARRIER_UNSUPPORT,
// that means cellular upstream is not supported and entitlement check result is empty
// because entitlement check should not be run.
if (!isTetherProvisioningRequired(config)) return true;
// If provisioning is required and EntitlementManager doesn't know any downstreams, cellular
@ -199,11 +217,7 @@ public class EntitlementManager {
// If upstream is not cellular, provisioning app would not be launched
// till upstream change to cellular.
if (mUsingCellularAsUpstream) {
if (showProvisioningUi) {
runUiTetherProvisioning(downstreamType, config);
} else {
runSilentTetherProvisioning(downstreamType, config);
}
runTetheringProvisioning(showProvisioningUi, downstreamType, config);
mNeedReRunProvisioningUi = false;
} else {
mNeedReRunProvisioningUi |= showProvisioningUi;
@ -262,17 +276,50 @@ public class EntitlementManager {
// the change and get the new correct value.
for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0;
downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) {
// If tethering provisioning is required but entitlement check result is empty,
// this means tethering may need to run entitlement check or carrier network
// is not supported.
if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
if (mNeedReRunProvisioningUi) {
mNeedReRunProvisioningUi = false;
runUiTetherProvisioning(downstream, config);
} else {
runSilentTetherProvisioning(downstream, config);
}
runTetheringProvisioning(mNeedReRunProvisioningUi, downstream, config);
mNeedReRunProvisioningUi = false;
}
}
}
/**
* Tether provisioning has these conditions to control provisioning behavior.
* 1st priority : Uses system property to disable any provisioning behavior.
* 2nd priority : Uses {@code CarrierConfigManager#KEY_CARRIER_SUPPORTS_TETHERING_BOOL} to
* decide current carrier support cellular upstream tethering or not.
* If value is true, it means check follow up condition to know whether
* provisioning is required.
* If value is false, it means tethering could not use cellular as upstream.
* 3rd priority : Uses {@code CarrierConfigManager#KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL} to
* decide current carrier require the provisioning.
* 4th priority : Checks whether provisioning is required from RRO configuration.
*
* @param config
* @return integer {@see #TETHERING_PROVISIONING_NOT_REQUIRED,
* #TETHERING_PROVISIONING_REQUIRED,
* #TETHERING_PROVISIONING_CARRIER_UNSUPPORT}
*/
private int getTetherProvisioningCondition(final TetheringConfiguration config) {
if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)) {
return TETHERING_PROVISIONING_NOT_REQUIRED;
}
// TODO: Find a way to avoid get carrier config twice.
if (carrierConfigAffirmsCarrierNotSupport(config)) {
// To block tethering, behave as if running provisioning check and failed.
return TETHERING_PROVISIONING_CARRIER_UNSUPPORT;
}
if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
return TETHERING_PROVISIONING_NOT_REQUIRED;
}
return (config.provisioningApp.length == 2)
? TETHERING_PROVISIONING_REQUIRED : TETHERING_PROVISIONING_NOT_REQUIRED;
}
/**
* Check if the device requires a provisioning check in order to enable tethering.
*
@ -281,14 +328,26 @@ public class EntitlementManager {
*/
@VisibleForTesting
protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
|| config.provisioningApp.length == 0) {
return getTetherProvisioningCondition(config) != TETHERING_PROVISIONING_NOT_REQUIRED;
}
/**
* Confirms the need of tethering provisioning but no entitlement package exists.
*/
public boolean isProvisioningNeededButUnavailable() {
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
return getTetherProvisioningCondition(config) == TETHERING_PROVISIONING_REQUIRED
&& !doesEntitlementPackageExist(config);
}
private boolean doesEntitlementPackageExist(final TetheringConfiguration config) {
final PackageManager pm = mContext.getPackageManager();
try {
pm.getPackageInfo(config.provisioningApp[0], GET_ACTIVITIES);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
return false;
}
return (config.provisioningApp.length == 2);
return true;
}
/**
@ -310,9 +369,7 @@ public class EntitlementManager {
mEntitlementCacheValue.clear();
mCurrentEntitlementResults.clear();
// TODO: refine provisioning check to isTetherProvisioningRequired() ??
if (!config.hasMobileHotspotProvisionApp()
|| carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
if (!isTetherProvisioningRequired(config)) {
evaluateCellularPermission(config);
return;
}
@ -327,8 +384,8 @@ public class EntitlementManager {
* @param config an object that encapsulates the various tethering configuration elements.
* */
public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
final CarrierConfigManager configManager = (CarrierConfigManager) mContext
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
final CarrierConfigManager configManager = mContext
.getSystemService(CarrierConfigManager.class);
if (configManager == null) return null;
final PersistableBundle carrierConfig = configManager.getConfigForSubId(
@ -346,6 +403,7 @@ public class EntitlementManager {
//
// TODO: find a better way to express this, or alter the checking process
// entirely so that this is more intuitive.
// TODO: Find a way to avoid using getCarrierConfig everytime.
private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
final TetheringConfiguration config) {
// Check carrier config for entitlement checks
@ -358,16 +416,29 @@ public class EntitlementManager {
return !isEntitlementCheckRequired;
}
private boolean carrierConfigAffirmsCarrierNotSupport(final TetheringConfiguration config) {
if (!SdkLevel.isAtLeastT()) {
return false;
}
// Check carrier config for entitlement checks
final PersistableBundle carrierConfig = getCarrierConfig(config);
if (carrierConfig == null) return false;
// A CarrierConfigManager was found and it has a config.
final boolean mIsCarrierSupport = carrierConfig.getBoolean(
KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true);
return !mIsCarrierSupport;
}
/**
* Run no UI tethering provisioning check.
* @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
*/
@VisibleForTesting
protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) {
protected Intent runSilentTetherProvisioning(
int type, final TetheringConfiguration config, ResultReceiver receiver) {
if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
// For silent provisioning, settings would stop tethering when entitlement fail.
ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@ -383,11 +454,6 @@ public class EntitlementManager {
return intent;
}
private void runUiTetherProvisioning(int type, final TetheringConfiguration config) {
ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
runUiTetherProvisioning(type, config, receiver);
}
/**
* Run the UI-enabled tethering provisioning check.
* @param type tethering type from TetheringManager.TETHERING_{@code *}
@ -411,6 +477,35 @@ public class EntitlementManager {
return intent;
}
private void runTetheringProvisioning(
boolean showProvisioningUi, int downstreamType, final TetheringConfiguration config) {
if (carrierConfigAffirmsCarrierNotSupport(config)) {
mListener.onTetherProvisioningFailed(downstreamType, "Carrier does not support.");
if (showProvisioningUi) {
showCarrierUnsupportedDialog();
}
return;
}
ResultReceiver receiver =
buildProxyReceiver(downstreamType, showProvisioningUi/* notifyFail */, null);
if (showProvisioningUi) {
runUiTetherProvisioning(downstreamType, config, receiver);
} else {
runSilentTetherProvisioning(downstreamType, config, receiver);
}
}
private void showCarrierUnsupportedDialog() {
// This is only used when carrierConfigAffirmsCarrierNotSupport() is true.
if (!SdkLevel.isAtLeastT()) {
return;
}
Intent intent = new Intent(ACTION_TETHER_UNSUPPORTED_CARRIER_UI);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
@VisibleForTesting
PendingIntent createRecheckAlarmIntent() {
final Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
@ -576,7 +671,8 @@ public class EntitlementManager {
int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
addDownstreamMapping(type, updatedCacheValue);
if (updatedCacheValue == TETHER_ERROR_PROVISIONING_FAILED && notifyFail) {
mListener.onUiEntitlementFailed(type);
mListener.onTetherProvisioningFailed(
type, "Tethering provisioning failed.");
}
if (receiver != null) receiver.send(updatedCacheValue, null);
}
@ -632,9 +728,14 @@ public class EntitlementManager {
}
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
if (!isTetherProvisioningRequired(config)) {
receiver.send(TETHER_ERROR_NO_ERROR, null);
return;
switch (getTetherProvisioningCondition(config)) {
case TETHERING_PROVISIONING_NOT_REQUIRED:
receiver.send(TETHER_ERROR_NO_ERROR, null);
return;
case TETHERING_PROVISIONING_CARRIER_UNSUPPORT:
receiver.send(TETHER_ERROR_PROVISIONING_FAILED, null);
return;
}
final int cacheValue = mEntitlementCacheValue.get(

View file

@ -18,7 +18,6 @@ package com.android.networkstack.tethering;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
@ -319,8 +318,8 @@ public class Tethering {
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
() -> mTetherMainSM.sendMessage(
TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
mEntitlementMgr.setOnTetherProvisioningFailedListener((downstream, reason) -> {
mLog.log("OBSERVED OnTetherProvisioningFailed : " + reason);
stopTethering(downstream);
});
mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
@ -995,30 +994,11 @@ public class Tethering {
return tetherState.lastError;
}
private boolean isProvisioningNeededButUnavailable() {
return isTetherProvisioningRequired() && !doesEntitlementPackageExist();
}
boolean isTetherProvisioningRequired() {
final TetheringConfiguration cfg = mConfig;
return mEntitlementMgr.isTetherProvisioningRequired(cfg);
}
private boolean doesEntitlementPackageExist() {
// provisioningApp must contain package and class name.
if (mConfig.provisioningApp.length != 2) {
return false;
}
final PackageManager pm = mContext.getPackageManager();
try {
pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
return true;
}
private int getRequestedState(int type) {
final TetheringRequestParcel request = mActiveTetheringRequests.get(type);
@ -2476,7 +2456,7 @@ public class Tethering {
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
return tetherEnabledInSettings && hasAnySupportedDownstream()
&& !isProvisioningNeededButUnavailable();
&& !mEntitlementMgr.isProvisioningNeededButUnavailable();
}
private void dumpBpf(IndentingPrintWriter pw) {

View file

@ -37,6 +37,9 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -47,6 +50,7 @@ import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@ -77,9 +81,12 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.modules.utils.build.SdkLevel;
import com.android.testutils.DevSdkIgnoreRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@ -96,6 +103,7 @@ public final class EntitlementManagerTest {
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
private static final String PROVISIONING_APP_RESPONSE = "app_response";
private static final String TEST_PACKAGE_NAME = "com.android.tethering.test";
private static final String FAILED_TETHERING_REASON = "Tethering provisioning failed.";
private static final int RECHECK_TIMER_HOURS = 24;
@Mock private CarrierConfigManager mCarrierConfigManager;
@ -103,10 +111,14 @@ public final class EntitlementManagerTest {
@Mock private Resources mResources;
@Mock private SharedLog mLog;
@Mock private PackageManager mPm;
@Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
@Mock private EntitlementManager
.OnTetherProvisioningFailedListener mTetherProvisioningFailedListener;
@Mock private AlarmManager mAlarmManager;
@Mock private PendingIntent mAlarmIntent;
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle();
@ -179,8 +191,8 @@ public final class EntitlementManagerTest {
@Override
protected Intent runSilentTetherProvisioning(int type,
final TetheringConfiguration config) {
Intent intent = super.runSilentTetherProvisioning(type, config);
final TetheringConfiguration config, final ResultReceiver receiver) {
Intent intent = super.runSilentTetherProvisioning(type, config, receiver);
assertSilentTetherProvisioning(type, config, intent);
silentProvisionCount++;
addDownstreamMapping(type, fakeEntitlementResult);
@ -245,7 +257,7 @@ public final class EntitlementManagerTest {
mPermissionChangeCallback = spy(() -> { });
mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog,
mPermissionChangeCallback);
mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
mEnMgr.setOnTetherProvisioningFailedListener(mTetherProvisioningFailedListener);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
mEnMgr.setTetheringConfigurationFetcher(() -> {
return mConfig;
@ -268,14 +280,23 @@ public final class EntitlementManagerTest {
when(mResources.getInteger(R.integer.config_mobile_hotspot_provision_check_period))
.thenReturn(RECHECK_TIMER_HOURS);
// Act like the CarrierConfigManager is present and ready unless told otherwise.
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager);
mockService(Context.CARRIER_CONFIG_SERVICE,
CarrierConfigManager.class, mCarrierConfigManager);
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig);
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
}
private void setupCarrierConfig(boolean carrierSupported) {
mCarrierConfig.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, carrierSupported);
}
private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
when(mMockContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
when(mMockContext.getSystemService(serviceName)).thenReturn(service);
}
@Test
public void canRequireProvisioning() {
setupForRequiredProvisioning();
@ -285,8 +306,7 @@ public final class EntitlementManagerTest {
@Test
public void toleratesCarrierConfigManagerMissing() {
setupForRequiredProvisioning();
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(null);
mockService(Context.CARRIER_CONFIG_SERVICE, CarrierConfigManager.class, null);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
// Therefore provisioning still be required.
@ -613,14 +633,16 @@ public final class EntitlementManagerTest {
@Test
public void testCallStopTetheringWhenUiProvisioningFail() {
setupForRequiredProvisioning();
verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
verify(mTetherProvisioningFailedListener, times(0))
.onTetherProvisioningFailed(TETHERING_WIFI, FAILED_TETHERING_REASON);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
verify(mTetherProvisioningFailedListener, times(1))
.onTetherProvisioningFailed(TETHERING_WIFI, FAILED_TETHERING_REASON);
}
@Test
@ -644,7 +666,8 @@ public final class EntitlementManagerTest {
// When second downstream is down, exempted downstream can use cellular upstream.
assertEquals(1, mEnMgr.uiProvisionCount);
verify(mEntitlementFailedListener).onUiEntitlementFailed(TETHERING_USB);
verify(mTetherProvisioningFailedListener).onTetherProvisioningFailed(TETHERING_USB,
FAILED_TETHERING_REASON);
mEnMgr.stopProvisioningIfNeeded(TETHERING_USB);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
@ -678,4 +701,85 @@ public final class EntitlementManagerTest {
verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
eq(mAlarmIntent));
}
@Test
@IgnoreUpTo(SC_V2)
public void requestLatestTetheringEntitlementResult_carrierDoesNotSupport_noProvisionCount()
throws Exception {
setupForRequiredProvisioning();
setupCarrierConfig(false);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
ResultReceiver receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode);
}
};
mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
mEnMgr.reset();
}
@Test
@IgnoreUpTo(SC_V2)
public void reevaluateSimCardProvisioning_carrierUnsupportAndSimswitch() {
setupForRequiredProvisioning();
// Start a tethering with cellular data without provisioning.
mEnMgr.notifyUpstream(true);
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
mLooper.dispatchAll();
// Tear down mobile, then switch SIM.
mEnMgr.notifyUpstream(false);
mLooper.dispatchAll();
setupCarrierConfig(false);
mEnMgr.reevaluateSimCardProvisioning(mConfig);
// Turn on upstream.
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
verify(mTetherProvisioningFailedListener)
.onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
}
@Test
@IgnoreUpTo(SC_V2)
public void startProvisioningIfNeeded_carrierUnsupport()
throws Exception {
setupForRequiredProvisioning();
setupCarrierConfig(false);
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
verify(mTetherProvisioningFailedListener, never())
.onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
verify(mTetherProvisioningFailedListener)
.onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
reset(mTetherProvisioningFailedListener);
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
verify(mTetherProvisioningFailedListener)
.onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
}
@Test
public void isTetherProvisioningRequired_carrierUnSupport() {
setupForRequiredProvisioning();
setupCarrierConfig(false);
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(new String[0]);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
if (SdkLevel.isAtLeastT()) {
assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
} else {
assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
}
}
}