Merge "Add onSupportedTetheringType callback"
This commit is contained in:
@@ -36,4 +36,5 @@ oneway interface ITetheringEventCallback
|
|||||||
void onTetherStatesChanged(in TetherStatesParcel states);
|
void onTetherStatesChanged(in TetherStatesParcel states);
|
||||||
void onTetherClientsChanged(in List<TetheredClient> clients);
|
void onTetherClientsChanged(in List<TetheredClient> clients);
|
||||||
void onOffloadStatusChanged(int status);
|
void onOffloadStatusChanged(int status);
|
||||||
|
void onSupportedTetheringTypes(long supportedBitmap);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.net.TetherStatesParcel;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
parcelable TetheringCallbackStartedParcel {
|
parcelable TetheringCallbackStartedParcel {
|
||||||
boolean tetheringSupported;
|
long supportedTypes;
|
||||||
Network upstreamNetwork;
|
Network upstreamNetwork;
|
||||||
TetheringConfigurationParcel config;
|
TetheringConfigurationParcel config;
|
||||||
TetherStatesParcel states;
|
TetherStatesParcel states;
|
||||||
|
|||||||
@@ -183,6 +183,12 @@ public class TetheringManager {
|
|||||||
*/
|
*/
|
||||||
public static final int TETHERING_WIGIG = 6;
|
public static final int TETHERING_WIGIG = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The int value of last tethering type.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final int MAX_TETHERING_TYPE = TETHERING_WIGIG;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef(value = {
|
@IntDef(value = {
|
||||||
@@ -519,6 +525,9 @@ public class TetheringManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSupportedTetheringTypes(long supportedBitmap) { }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpstreamChanged(Network network) { }
|
public void onUpstreamChanged(Network network) { }
|
||||||
|
|
||||||
@@ -1030,6 +1039,19 @@ public class TetheringManager {
|
|||||||
* upstream status.
|
* upstream status.
|
||||||
*/
|
*/
|
||||||
public interface TetheringEventCallback {
|
public interface TetheringEventCallback {
|
||||||
|
/**
|
||||||
|
* Called when tethering supported status changed.
|
||||||
|
*
|
||||||
|
* <p>This callback will be called immediately after the callback is
|
||||||
|
* registered, and never be called if there is changes afterward.
|
||||||
|
*
|
||||||
|
* <p>Tethering may be disabled via system properties, device configuration, or device
|
||||||
|
* policy restrictions.
|
||||||
|
*
|
||||||
|
* @param supported whether any tethering type is supported.
|
||||||
|
*/
|
||||||
|
default void onTetheringSupported(boolean supported) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when tethering supported status changed.
|
* Called when tethering supported status changed.
|
||||||
*
|
*
|
||||||
@@ -1039,9 +1061,10 @@ public class TetheringManager {
|
|||||||
* <p>Tethering may be disabled via system properties, device configuration, or device
|
* <p>Tethering may be disabled via system properties, device configuration, or device
|
||||||
* policy restrictions.
|
* policy restrictions.
|
||||||
*
|
*
|
||||||
* @param supported The new supported status
|
* @param supportedTypes a set of @TetheringType which is supported.
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
default void onTetheringSupported(boolean supported) {}
|
default void onSupportedTetheringTypes(@NonNull Set<Integer> supportedTypes) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when tethering upstream changed.
|
* Called when tethering upstream changed.
|
||||||
@@ -1339,7 +1362,8 @@ public class TetheringManager {
|
|||||||
@Override
|
@Override
|
||||||
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
|
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
callback.onTetheringSupported(parcel.tetheringSupported);
|
callback.onSupportedTetheringTypes(unpackBits(parcel.supportedTypes));
|
||||||
|
callback.onTetheringSupported(parcel.supportedTypes != 0);
|
||||||
callback.onUpstreamChanged(parcel.upstreamNetwork);
|
callback.onUpstreamChanged(parcel.upstreamNetwork);
|
||||||
sendErrorCallbacks(parcel.states);
|
sendErrorCallbacks(parcel.states);
|
||||||
sendRegexpsChanged(parcel.config);
|
sendRegexpsChanged(parcel.config);
|
||||||
@@ -1358,6 +1382,13 @@ public class TetheringManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSupportedTetheringTypes(long supportedBitmap) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
callback.onSupportedTetheringTypes(unpackBits(supportedBitmap));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
|
private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
|
||||||
callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
|
callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
|
||||||
parcel.tetherableBluetoothRegexs,
|
parcel.tetherableBluetoothRegexs,
|
||||||
@@ -1395,6 +1426,23 @@ public class TetheringManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack bitmap to a set of bit position intergers.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static ArraySet<Integer> unpackBits(long val) {
|
||||||
|
final ArraySet<Integer> result = new ArraySet<>(Long.bitCount(val));
|
||||||
|
int bitPos = 0;
|
||||||
|
while (val != 0) {
|
||||||
|
if ((val & 1) == 1) result.add(bitPos);
|
||||||
|
|
||||||
|
val = val >>> 1;
|
||||||
|
bitPos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove tethering event callback previously registered with
|
* Remove tethering event callback previously registered with
|
||||||
* {@link #registerTetheringEventCallback}.
|
* {@link #registerTetheringEventCallback}.
|
||||||
|
|||||||
@@ -278,6 +278,11 @@ public class Tethering {
|
|||||||
private BluetoothPan mBluetoothPan;
|
private BluetoothPan mBluetoothPan;
|
||||||
private PanServiceListener mBluetoothPanListener;
|
private PanServiceListener mBluetoothPanListener;
|
||||||
private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
|
private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
|
||||||
|
// AIDL doesn't support Set<Integer>. Maintain a int bitmap here. When the bitmap is passed to
|
||||||
|
// TetheringManager, TetheringManager would convert it to a set of Integer types.
|
||||||
|
// mSupportedTypeBitmap should always be updated inside tethering internal thread but it may be
|
||||||
|
// read from binder thread which called TetheringService directly.
|
||||||
|
private volatile long mSupportedTypeBitmap;
|
||||||
|
|
||||||
public Tethering(TetheringDependencies deps) {
|
public Tethering(TetheringDependencies deps) {
|
||||||
mLog.mark("Tethering.constructed");
|
mLog.mark("Tethering.constructed");
|
||||||
@@ -494,6 +499,8 @@ public class Tethering {
|
|||||||
mUpstreamNetworkMonitor.setUpstreamConfig(mConfig.chooseUpstreamAutomatically,
|
mUpstreamNetworkMonitor.setUpstreamConfig(mConfig.chooseUpstreamAutomatically,
|
||||||
mConfig.isDunRequired);
|
mConfig.isDunRequired);
|
||||||
reportConfigurationChanged(mConfig.toStableParcelable());
|
reportConfigurationChanged(mConfig.toStableParcelable());
|
||||||
|
|
||||||
|
updateSupportedDownstreams(mConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeDunSettingChanged() {
|
private void maybeDunSettingChanged() {
|
||||||
@@ -1513,26 +1520,6 @@ public class Tethering {
|
|||||||
return mConfig;
|
return mConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasAnySupportedDownstream() {
|
|
||||||
if ((mConfig.tetherableUsbRegexs.length != 0)
|
|
||||||
|| (mConfig.tetherableWifiRegexs.length != 0)
|
|
||||||
|| (mConfig.tetherableBluetoothRegexs.length != 0)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
|
|
||||||
// disabled (whole tethering settings would be hidden). This means tethering would also not
|
|
||||||
// support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
|
|
||||||
// some devices in the field rely on this to disable tethering entirely.
|
|
||||||
if (!SdkLevel.isAtLeastT()) return false;
|
|
||||||
|
|
||||||
return (mConfig.tetherableWifiP2pRegexs.length != 0)
|
|
||||||
|| (mConfig.tetherableNcmRegexs.length != 0)
|
|
||||||
|| isEthernetSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: using EtherentManager new API to check whether ethernet is supported when the API is
|
|
||||||
// ready to use.
|
|
||||||
private boolean isEthernetSupported() {
|
private boolean isEthernetSupported() {
|
||||||
return mContext.getSystemService(Context.ETHERNET_SERVICE) != null;
|
return mContext.getSystemService(Context.ETHERNET_SERVICE) != null;
|
||||||
}
|
}
|
||||||
@@ -2322,7 +2309,7 @@ public class Tethering {
|
|||||||
mHandler.post(() -> {
|
mHandler.post(() -> {
|
||||||
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
|
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
|
||||||
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
|
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
|
||||||
parcel.tetheringSupported = isTetheringSupported();
|
parcel.supportedTypes = mSupportedTypeBitmap;
|
||||||
parcel.upstreamNetwork = mTetherUpstream;
|
parcel.upstreamNetwork = mTetherUpstream;
|
||||||
parcel.config = mConfig.toStableParcelable();
|
parcel.config = mConfig.toStableParcelable();
|
||||||
parcel.states =
|
parcel.states =
|
||||||
@@ -2361,6 +2348,22 @@ public class Tethering {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reportTetheringSupportedChange(final long supportedBitmap) {
|
||||||
|
final int length = mTetheringEventCallbacks.beginBroadcast();
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
try {
|
||||||
|
mTetheringEventCallbacks.getBroadcastItem(i).onSupportedTetheringTypes(
|
||||||
|
supportedBitmap);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Not really very much to do here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mTetheringEventCallbacks.finishBroadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void reportUpstreamChanged(UpstreamNetworkState ns) {
|
private void reportUpstreamChanged(UpstreamNetworkState ns) {
|
||||||
final int length = mTetheringEventCallbacks.beginBroadcast();
|
final int length = mTetheringEventCallbacks.beginBroadcast();
|
||||||
final Network network = (ns != null) ? ns.network : null;
|
final Network network = (ns != null) ? ns.network : null;
|
||||||
@@ -2445,18 +2448,56 @@ public class Tethering {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSupportedDownstreams(final TetheringConfiguration config) {
|
||||||
|
final long preSupportedBitmap = mSupportedTypeBitmap;
|
||||||
|
|
||||||
|
if (!isTetheringAllowed() || mEntitlementMgr.isProvisioningNeededButUnavailable()) {
|
||||||
|
mSupportedTypeBitmap = 0;
|
||||||
|
} else {
|
||||||
|
mSupportedTypeBitmap = makeSupportedDownstreams(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preSupportedBitmap != mSupportedTypeBitmap) {
|
||||||
|
reportTetheringSupportedChange(mSupportedTypeBitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long makeSupportedDownstreams(final TetheringConfiguration config) {
|
||||||
|
long types = 0;
|
||||||
|
if (config.tetherableUsbRegexs.length != 0) types |= (1 << TETHERING_USB);
|
||||||
|
|
||||||
|
if (config.tetherableWifiRegexs.length != 0) types |= (1 << TETHERING_WIFI);
|
||||||
|
|
||||||
|
if (config.tetherableBluetoothRegexs.length != 0) types |= (1 << TETHERING_BLUETOOTH);
|
||||||
|
|
||||||
|
// Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
|
||||||
|
// disabled (whole tethering settings would be hidden). This means tethering would also not
|
||||||
|
// support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
|
||||||
|
// some devices in the field rely on this to disable tethering entirely.
|
||||||
|
if (!SdkLevel.isAtLeastT() && types == 0) return types;
|
||||||
|
|
||||||
|
if (config.tetherableNcmRegexs.length != 0) types |= (1 << TETHERING_NCM);
|
||||||
|
|
||||||
|
if (config.tetherableWifiP2pRegexs.length != 0) types |= (1 << TETHERING_WIFI_P2P);
|
||||||
|
|
||||||
|
if (isEthernetSupported()) types |= (1 << TETHERING_ETHERNET);
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
// if ro.tether.denied = true we default to no tethering
|
// if ro.tether.denied = true we default to no tethering
|
||||||
// gservices could set the secure setting to 1 though to enable it on a build where it
|
// gservices could set the secure setting to 1 though to enable it on a build where it
|
||||||
// had previously been turned off.
|
// had previously been turned off.
|
||||||
boolean isTetheringSupported() {
|
private boolean isTetheringAllowed() {
|
||||||
final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
|
final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
|
||||||
final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
|
final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
|
Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
|
||||||
final boolean tetherEnabledInSettings = tetherSupported
|
return tetherSupported
|
||||||
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
|
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
|
||||||
|
}
|
||||||
|
|
||||||
return tetherEnabledInSettings && hasAnySupportedDownstream()
|
boolean isTetheringSupported() {
|
||||||
&& !mEntitlementMgr.isProvisioningNeededButUnavailable();
|
return mSupportedTypeBitmap > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpBpf(IndentingPrintWriter pw) {
|
private void dumpBpf(IndentingPrintWriter pw) {
|
||||||
|
|||||||
@@ -168,12 +168,13 @@ public class EthernetTetheringTest {
|
|||||||
mUiAutomation.adoptShellPermissionIdentity(
|
mUiAutomation.adoptShellPermissionIdentity(
|
||||||
MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
|
MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
|
||||||
CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
|
CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
|
||||||
mRunTests = mTm.isTetheringSupported() && mEm != null;
|
|
||||||
assumeTrue(mRunTests);
|
|
||||||
|
|
||||||
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
mHandlerThread = new HandlerThread(getClass().getSimpleName());
|
||||||
mHandlerThread.start();
|
mHandlerThread.start();
|
||||||
mHandler = new Handler(mHandlerThread.getLooper());
|
mHandler = new Handler(mHandlerThread.getLooper());
|
||||||
|
|
||||||
|
mRunTests = isEthernetTetheringSupported();
|
||||||
|
assumeTrue(mRunTests);
|
||||||
|
|
||||||
mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
|
mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +202,6 @@ public class EthernetTetheringTest {
|
|||||||
mHandler.post(() -> reader.stop());
|
mHandler.post(() -> reader.stop());
|
||||||
mDownstreamReader = null;
|
mDownstreamReader = null;
|
||||||
}
|
}
|
||||||
mHandlerThread.quitSafely();
|
|
||||||
mTetheredInterfaceRequester.release();
|
mTetheredInterfaceRequester.release();
|
||||||
mEm.setIncludeTestInterfaces(false);
|
mEm.setIncludeTestInterfaces(false);
|
||||||
maybeDeleteTestInterface();
|
maybeDeleteTestInterface();
|
||||||
@@ -212,6 +212,7 @@ public class EthernetTetheringTest {
|
|||||||
try {
|
try {
|
||||||
if (mRunTests) cleanUp();
|
if (mRunTests) cleanUp();
|
||||||
} finally {
|
} finally {
|
||||||
|
mHandlerThread.quitSafely();
|
||||||
mUiAutomation.dropShellPermissionIdentity();
|
mUiAutomation.dropShellPermissionIdentity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,6 +401,23 @@ public class EthernetTetheringTest {
|
|||||||
// client, which is not possible in this test.
|
// client, which is not possible in this test.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isEthernetTetheringSupported() throws Exception {
|
||||||
|
final CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||||
|
final TetheringEventCallback callback = new TetheringEventCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSupportedTetheringTypes(Set<Integer> supportedTypes) {
|
||||||
|
future.complete(supportedTypes.contains(TETHERING_ETHERNET));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
mTm.registerTetheringEventCallback(mHandler::post, callback);
|
||||||
|
return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
} finally {
|
||||||
|
mTm.unregisterTetheringEventCallback(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final class MyTetheringEventCallback implements TetheringEventCallback {
|
private static final class MyTetheringEventCallback implements TetheringEventCallback {
|
||||||
private final TetheringManager mTm;
|
private final TetheringManager mTm;
|
||||||
private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
|
private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ import android.net.TetheredClient.AddressInfo;
|
|||||||
import android.net.TetheringCallbackStartedParcel;
|
import android.net.TetheringCallbackStartedParcel;
|
||||||
import android.net.TetheringConfigurationParcel;
|
import android.net.TetheringConfigurationParcel;
|
||||||
import android.net.TetheringInterface;
|
import android.net.TetheringInterface;
|
||||||
|
import android.net.TetheringManager;
|
||||||
import android.net.TetheringRequestParcel;
|
import android.net.TetheringRequestParcel;
|
||||||
import android.net.dhcp.DhcpLeaseParcelable;
|
import android.net.dhcp.DhcpLeaseParcelable;
|
||||||
import android.net.dhcp.DhcpServerCallbacks;
|
import android.net.dhcp.DhcpServerCallbacks;
|
||||||
@@ -175,6 +176,7 @@ import android.telephony.CarrierConfigManager;
|
|||||||
import android.telephony.PhoneStateListener;
|
import android.telephony.PhoneStateListener;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.test.mock.MockContentResolver;
|
import android.test.mock.MockContentResolver;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
@@ -211,6 +213,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -1696,6 +1699,7 @@ public class TetheringTest {
|
|||||||
private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
|
private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
|
private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
|
||||||
private final ArrayList<List<TetheredClient>> mTetheredClients = new ArrayList<>();
|
private final ArrayList<List<TetheredClient>> mTetheredClients = new ArrayList<>();
|
||||||
|
private final ArrayList<Long> mSupportedBitmaps = new ArrayList<>();
|
||||||
|
|
||||||
// This function will remove the recorded callbacks, so it must be called once for
|
// This function will remove the recorded callbacks, so it must be called once for
|
||||||
// each callback. If this is called after multiple callback, the order matters.
|
// each callback. If this is called after multiple callback, the order matters.
|
||||||
@@ -1748,6 +1752,10 @@ public class TetheringTest {
|
|||||||
assertTrue(leases.containsAll(result));
|
assertTrue(leases.containsAll(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void expectSupportedTetheringTypes(Set<Integer> expectedTypes) {
|
||||||
|
assertEquals(expectedTypes, TetheringManager.unpackBits(mSupportedBitmaps.remove(0)));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpstreamChanged(Network network) {
|
public void onUpstreamChanged(Network network) {
|
||||||
mActualUpstreams.add(network);
|
mActualUpstreams.add(network);
|
||||||
@@ -1780,11 +1788,17 @@ public class TetheringTest {
|
|||||||
mTetherStates.add(parcel.states);
|
mTetherStates.add(parcel.states);
|
||||||
mOffloadStatus.add(parcel.offloadStatus);
|
mOffloadStatus.add(parcel.offloadStatus);
|
||||||
mTetheredClients.add(parcel.tetheredClients);
|
mTetheredClients.add(parcel.tetheredClients);
|
||||||
|
mSupportedBitmaps.add(parcel.supportedTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCallbackStopped(int errorCode) { }
|
public void onCallbackStopped(int errorCode) { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSupportedTetheringTypes(long supportedBitmap) {
|
||||||
|
mSupportedBitmaps.add(supportedBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
public void assertNoUpstreamChangeCallback() {
|
public void assertNoUpstreamChangeCallback() {
|
||||||
assertTrue(mActualUpstreams.isEmpty());
|
assertTrue(mActualUpstreams.isEmpty());
|
||||||
}
|
}
|
||||||
@@ -2836,53 +2850,81 @@ public class TetheringTest {
|
|||||||
runStopUSBTethering();
|
runStopUSBTethering();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ArraySet<Integer> getAllSupportedTetheringTypes() {
|
||||||
|
return new ArraySet<>(new Integer[] { TETHERING_USB, TETHERING_NCM, TETHERING_WIFI,
|
||||||
|
TETHERING_WIFI_P2P, TETHERING_BLUETOOTH, TETHERING_ETHERNET });
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTetheringSupported() throws Exception {
|
public void testTetheringSupported() throws Exception {
|
||||||
|
final ArraySet<Integer> expectedTypes = getAllSupportedTetheringTypes();
|
||||||
|
// Check tethering is supported after initialization.
|
||||||
setTetheringSupported(true /* supported */);
|
setTetheringSupported(true /* supported */);
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
TestTetheringEventCallback callback = new TestTetheringEventCallback();
|
||||||
|
mTethering.registerTetheringEventCallback(callback);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
|
||||||
// Could disable tethering supported by settings.
|
// Could disable tethering supported by settings.
|
||||||
Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0);
|
Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0);
|
||||||
updateConfigAndVerifySupported(false /* supported */);
|
updateConfigAndVerifySupported(callback, new ArraySet<>());
|
||||||
|
|
||||||
// Could disable tethering supported by user restriction.
|
// Could disable tethering supported by user restriction.
|
||||||
setTetheringSupported(true /* supported */);
|
setTetheringSupported(true /* supported */);
|
||||||
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
when(mUserManager.hasUserRestriction(
|
when(mUserManager.hasUserRestriction(
|
||||||
UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true);
|
UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true);
|
||||||
updateConfigAndVerifySupported(false /* supported */);
|
updateConfigAndVerifySupported(callback, new ArraySet<>());
|
||||||
|
|
||||||
// Tethering is supported if it has any supported downstream.
|
// Tethering is supported if it has any supported downstream.
|
||||||
setTetheringSupported(true /* supported */);
|
setTetheringSupported(true /* supported */);
|
||||||
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
// Usb tethering is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_USB);
|
||||||
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||||
.thenReturn(new String[0]);
|
.thenReturn(new String[0]);
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
// Wifi tethering is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_WIFI);
|
||||||
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
|
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
|
||||||
.thenReturn(new String[0]);
|
.thenReturn(new String[0]);
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
// Bluetooth tethering is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_BLUETOOTH);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
||||||
|
.thenReturn(new String[0]);
|
||||||
|
|
||||||
if (isAtLeastT()) {
|
if (isAtLeastT()) {
|
||||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
.thenReturn(new String[0]);
|
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
// P2p tethering is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_WIFI_P2P);
|
||||||
when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
|
when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
|
||||||
.thenReturn(new String[0]);
|
.thenReturn(new String[0]);
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
// Ncm tethering is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_NCM);
|
||||||
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
|
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
|
||||||
.thenReturn(new String[0]);
|
.thenReturn(new String[0]);
|
||||||
updateConfigAndVerifySupported(true /* supported */);
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
|
// Ethernet tethering (last supported type) is not supported:
|
||||||
|
expectedTypes.remove(TETHERING_ETHERNET);
|
||||||
mForceEthernetServiceUnavailable = true;
|
mForceEthernetServiceUnavailable = true;
|
||||||
updateConfigAndVerifySupported(false /* supported */);
|
updateConfigAndVerifySupported(callback, new ArraySet<>());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
// If wifi, usb and bluetooth are all not supported, all the types are not supported.
|
||||||
.thenReturn(new String[0]);
|
expectedTypes.clear();
|
||||||
updateConfigAndVerifySupported(false /* supported */);
|
updateConfigAndVerifySupported(callback, expectedTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConfigAndVerifySupported(boolean supported) {
|
private void updateConfigAndVerifySupported(final TestTetheringEventCallback callback,
|
||||||
|
final ArraySet<Integer> expectedTypes) {
|
||||||
sendConfigurationChanged();
|
sendConfigurationChanged();
|
||||||
assertEquals(supported, mTethering.isTetheringSupported());
|
|
||||||
|
assertEquals(expectedTypes.size() > 0, mTethering.isTetheringSupported());
|
||||||
|
callback.expectSupportedTetheringTypes(expectedTypes);
|
||||||
}
|
}
|
||||||
// TODO: Test that a request for hotspot mode doesn't interfere with an
|
// TODO: Test that a request for hotspot mode doesn't interfere with an
|
||||||
// already operating tethering mode interface.
|
// already operating tethering mode interface.
|
||||||
|
|||||||
Reference in New Issue
Block a user