Merge "Add a carrier config to block tethering."
This commit is contained in:
commit
1c12d0790e
3 changed files with 257 additions and 72 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue