Merge "Add tethering event callback API" am: 5227285ad7
am: b14afc3a5f
Change-Id: I083910feb7abf3f554fd2b8dddbc13a7aed8e27c
This commit is contained in:
@@ -202,6 +202,7 @@ java_defaults {
|
|||||||
"core/java/android/net/INetworkStatsService.aidl",
|
"core/java/android/net/INetworkStatsService.aidl",
|
||||||
"core/java/android/net/INetworkStatsSession.aidl",
|
"core/java/android/net/INetworkStatsSession.aidl",
|
||||||
"core/java/android/net/ITestNetworkManager.aidl",
|
"core/java/android/net/ITestNetworkManager.aidl",
|
||||||
|
"core/java/android/net/ITetheringEventCallback.aidl",
|
||||||
"core/java/android/net/ITetheringStatsProvider.aidl",
|
"core/java/android/net/ITetheringStatsProvider.aidl",
|
||||||
"core/java/android/net/nsd/INsdManager.aidl",
|
"core/java/android/net/nsd/INsdManager.aidl",
|
||||||
"core/java/android/nfc/IAppCallback.aidl",
|
"core/java/android/nfc/IAppCallback.aidl",
|
||||||
|
|||||||
@@ -3100,11 +3100,13 @@ package android.net {
|
|||||||
method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
|
method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
|
||||||
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
|
||||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
|
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
|
||||||
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
|
||||||
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
|
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
|
||||||
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle);
|
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle);
|
||||||
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
|
||||||
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
|
||||||
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
|
||||||
|
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
|
||||||
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
|
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
|
||||||
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
|
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
|
||||||
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
|
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
|
||||||
@@ -3125,6 +3127,11 @@ package android.net {
|
|||||||
method public void onEntitlementResult(int);
|
method public void onEntitlementResult(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract static class ConnectivityManager.OnTetheringEventCallback {
|
||||||
|
ctor public ConnectivityManager.OnTetheringEventCallback();
|
||||||
|
method public void onUpstreamChanged(@Nullable android.net.Network);
|
||||||
|
}
|
||||||
|
|
||||||
public final class IpPrefix implements android.os.Parcelable {
|
public final class IpPrefix implements android.os.Parcelable {
|
||||||
ctor public IpPrefix(java.net.InetAddress, int);
|
ctor public IpPrefix(java.net.InetAddress, int);
|
||||||
ctor public IpPrefix(String);
|
ctor public IpPrefix(String);
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import android.util.ArrayMap;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.telephony.ITelephony;
|
import com.android.internal.telephony.ITelephony;
|
||||||
import com.android.internal.telephony.PhoneConstants;
|
import com.android.internal.telephony.PhoneConstants;
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
@@ -2541,6 +2542,94 @@ public class ConnectivityManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for use with {@link registerTetheringEventCallback} to find out tethering
|
||||||
|
* upstream status.
|
||||||
|
*
|
||||||
|
*@hide
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
public abstract static class OnTetheringEventCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when tethering upstream changed. This can be called multiple times and can be
|
||||||
|
* called any time.
|
||||||
|
*
|
||||||
|
* @param network the {@link Network} of tethering upstream. Null means tethering doesn't
|
||||||
|
* have any upstream.
|
||||||
|
*/
|
||||||
|
public void onUpstreamChanged(@Nullable Network network) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mTetheringEventCallbacks")
|
||||||
|
private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback>
|
||||||
|
mTetheringEventCallbacks = new ArrayMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start listening to tethering change events. Any new added callback will receive the last
|
||||||
|
* tethering status right away. If callback is registered when tethering loses its upstream or
|
||||||
|
* disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called
|
||||||
|
* with a null argument. The same callback object cannot be registered twice.
|
||||||
|
*
|
||||||
|
* @param executor the executor on which callback will be invoked.
|
||||||
|
* @param callback the callback to be called when tethering has change events.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
|
||||||
|
public void registerTetheringEventCallback(
|
||||||
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
|
@NonNull final OnTetheringEventCallback callback) {
|
||||||
|
Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
|
||||||
|
|
||||||
|
synchronized (mTetheringEventCallbacks) {
|
||||||
|
Preconditions.checkArgument(!mTetheringEventCallbacks.containsKey(callback),
|
||||||
|
"callback was already registered.");
|
||||||
|
ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
|
||||||
|
@Override
|
||||||
|
public void onUpstreamChanged(Network network) throws RemoteException {
|
||||||
|
Binder.withCleanCallingIdentity(() ->
|
||||||
|
executor.execute(() -> {
|
||||||
|
callback.onUpstreamChanged(network);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
String pkgName = mContext.getOpPackageName();
|
||||||
|
Log.i(TAG, "registerTetheringUpstreamCallback:" + pkgName);
|
||||||
|
mService.registerTetheringEventCallback(remoteCallback, pkgName);
|
||||||
|
mTetheringEventCallbacks.put(callback, remoteCallback);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove tethering event callback previously registered with
|
||||||
|
* {@link #registerTetheringEventCallback}.
|
||||||
|
*
|
||||||
|
* @param callback previously registered callback.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@SystemApi
|
||||||
|
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
|
||||||
|
public void unregisterTetheringEventCallback(
|
||||||
|
@NonNull final OnTetheringEventCallback callback) {
|
||||||
|
synchronized (mTetheringEventCallbacks) {
|
||||||
|
ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback);
|
||||||
|
Preconditions.checkNotNull(remoteCallback, "callback was not registered.");
|
||||||
|
try {
|
||||||
|
String pkgName = mContext.getOpPackageName();
|
||||||
|
Log.i(TAG, "unregisterTetheringEventCallback:" + pkgName);
|
||||||
|
mService.unregisterTetheringEventCallback(remoteCallback, pkgName);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of regular expressions that define any tetherable
|
* Get the list of regular expressions that define any tetherable
|
||||||
* USB network interfaces. If USB tethering is not supported by the
|
* USB network interfaces. If USB tethering is not supported by the
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package android.net;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.net.ConnectionInfo;
|
import android.net.ConnectionInfo;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
@@ -214,4 +215,7 @@ interface IConnectivityManager
|
|||||||
|
|
||||||
void getLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
|
void getLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
|
||||||
boolean showEntitlementUi, String callerPkg);
|
boolean showEntitlementUi, String callerPkg);
|
||||||
|
|
||||||
|
void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
|
||||||
|
void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
|
||||||
}
|
}
|
||||||
|
|||||||
28
core/java/android/net/ITetheringEventCallback.aidl
Normal file
28
core/java/android/net/ITetheringEventCallback.aidl
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.net;
|
||||||
|
|
||||||
|
import android.net.Network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback class for receiving tethering changed events
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
oneway interface ITetheringEventCallback
|
||||||
|
{
|
||||||
|
void onUpstreamChanged(in Network network);
|
||||||
|
}
|
||||||
@@ -71,6 +71,7 @@ import android.net.INetworkMonitorCallbacks;
|
|||||||
import android.net.INetworkPolicyListener;
|
import android.net.INetworkPolicyListener;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.InetAddresses;
|
import android.net.InetAddresses;
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
@@ -3764,6 +3765,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
|
mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Register tethering event callback. */
|
||||||
|
@Override
|
||||||
|
public void registerTetheringEventCallback(ITetheringEventCallback callback,
|
||||||
|
String callerPkg) {
|
||||||
|
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
|
||||||
|
mTethering.registerTetheringEventCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregister tethering event callback. */
|
||||||
|
@Override
|
||||||
|
public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
|
||||||
|
String callerPkg) {
|
||||||
|
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
|
||||||
|
mTethering.unregisterTetheringEventCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
// Called when we lose the default network and have no replacement yet.
|
// Called when we lose the default network and have no replacement yet.
|
||||||
// This will automatically be cleared after X seconds or a new default network
|
// This will automatically be cleared after X seconds or a new default network
|
||||||
// becomes CONNECTED, whichever happens first. The timer is started by the
|
// becomes CONNECTED, whichever happens first. The timer is started by the
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import android.content.res.Resources;
|
|||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
@@ -82,6 +83,7 @@ import android.os.INetworkManagementService;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.RemoteCallbackList;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@@ -184,6 +186,9 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private final VersionedBroadcastListener mDefaultSubscriptionChange;
|
private final VersionedBroadcastListener mDefaultSubscriptionChange;
|
||||||
private final TetheringDependencies mDeps;
|
private final TetheringDependencies mDeps;
|
||||||
private final EntitlementManager mEntitlementMgr;
|
private final EntitlementManager mEntitlementMgr;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
|
||||||
|
new RemoteCallbackList<>();
|
||||||
|
|
||||||
private volatile TetheringConfiguration mConfig;
|
private volatile TetheringConfiguration mConfig;
|
||||||
private InterfaceSet mCurrentUpstreamIfaceSet;
|
private InterfaceSet mCurrentUpstreamIfaceSet;
|
||||||
@@ -193,6 +198,7 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private boolean mRndisEnabled; // track the RNDIS function enabled state
|
private boolean mRndisEnabled; // track the RNDIS function enabled state
|
||||||
// True iff. WiFi tethering should be started when soft AP is ready.
|
// True iff. WiFi tethering should be started when soft AP is ready.
|
||||||
private boolean mWifiTetherRequested;
|
private boolean mWifiTetherRequested;
|
||||||
|
private Network mTetherUpstream;
|
||||||
|
|
||||||
public Tethering(Context context, INetworkManagementService nmService,
|
public Tethering(Context context, INetworkManagementService nmService,
|
||||||
INetworkStatsService statsService, INetworkPolicyManager policyManager,
|
INetworkStatsService statsService, INetworkPolicyManager policyManager,
|
||||||
@@ -213,9 +219,9 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
|
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
|
||||||
mTetherMasterSM.start();
|
mTetherMasterSM.start();
|
||||||
|
|
||||||
final Handler smHandler = mTetherMasterSM.getHandler();
|
mHandler = mTetherMasterSM.getHandler();
|
||||||
mOffloadController = new OffloadController(smHandler,
|
mOffloadController = new OffloadController(mHandler,
|
||||||
mDeps.getOffloadHardwareInterface(smHandler, mLog),
|
mDeps.getOffloadHardwareInterface(mHandler, mLog),
|
||||||
mContext.getContentResolver(), mNMService,
|
mContext.getContentResolver(), mNMService,
|
||||||
mLog);
|
mLog);
|
||||||
mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
|
mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
|
||||||
@@ -227,7 +233,7 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM,
|
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM,
|
||||||
mLog, systemProperties);
|
mLog, systemProperties);
|
||||||
mCarrierConfigChange = new VersionedBroadcastListener(
|
mCarrierConfigChange = new VersionedBroadcastListener(
|
||||||
"CarrierConfigChangeListener", mContext, smHandler, filter,
|
"CarrierConfigChangeListener", mContext, mHandler, filter,
|
||||||
(Intent ignored) -> {
|
(Intent ignored) -> {
|
||||||
mLog.log("OBSERVED carrier config change");
|
mLog.log("OBSERVED carrier config change");
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
@@ -237,7 +243,7 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
filter = new IntentFilter();
|
filter = new IntentFilter();
|
||||||
filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
|
filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
|
||||||
mDefaultSubscriptionChange = new VersionedBroadcastListener(
|
mDefaultSubscriptionChange = new VersionedBroadcastListener(
|
||||||
"DefaultSubscriptionChangeListener", mContext, smHandler, filter,
|
"DefaultSubscriptionChangeListener", mContext, mHandler, filter,
|
||||||
(Intent ignored) -> {
|
(Intent ignored) -> {
|
||||||
mLog.log("OBSERVED default data subscription change");
|
mLog.log("OBSERVED default data subscription change");
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
@@ -248,14 +254,13 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
// Load tethering configuration.
|
// Load tethering configuration.
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
|
|
||||||
startStateMachineUpdaters();
|
startStateMachineUpdaters(mHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startStateMachineUpdaters() {
|
private void startStateMachineUpdaters(Handler handler) {
|
||||||
mCarrierConfigChange.startListening();
|
mCarrierConfigChange.startListening();
|
||||||
mDefaultSubscriptionChange.startListening();
|
mDefaultSubscriptionChange.startListening();
|
||||||
|
|
||||||
final Handler handler = mTetherMasterSM.getHandler();
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(UsbManager.ACTION_USB_STATE);
|
filter.addAction(UsbManager.ACTION_USB_STATE);
|
||||||
filter.addAction(CONNECTIVITY_ACTION);
|
filter.addAction(CONNECTIVITY_ACTION);
|
||||||
@@ -1229,8 +1234,13 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
|
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mUpstreamNetworkMonitor.setCurrentUpstream((ns != null) ? ns.network : null);
|
|
||||||
setUpstreamNetwork(ns);
|
setUpstreamNetwork(ns);
|
||||||
|
final Network newUpstream = (ns != null) ? ns.network : null;
|
||||||
|
if (mTetherUpstream != newUpstream) {
|
||||||
|
mTetherUpstream = newUpstream;
|
||||||
|
mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream);
|
||||||
|
reportUpstreamChanged(mTetherUpstream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setUpstreamNetwork(NetworkState ns) {
|
protected void setUpstreamNetwork(NetworkState ns) {
|
||||||
@@ -1413,6 +1423,10 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mUpstreamNetworkMonitor.stop();
|
mUpstreamNetworkMonitor.stop();
|
||||||
notifyDownstreamsOfNewUpstreamIface(null);
|
notifyDownstreamsOfNewUpstreamIface(null);
|
||||||
handleNewUpstreamNetworkState(null);
|
handleNewUpstreamNetworkState(null);
|
||||||
|
if (mTetherUpstream != null) {
|
||||||
|
mTetherUpstream = null;
|
||||||
|
reportUpstreamChanged(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateUpstreamWanted() {
|
private boolean updateUpstreamWanted() {
|
||||||
@@ -1684,6 +1698,40 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Register tethering event callback */
|
||||||
|
public void registerTetheringEventCallback(ITetheringEventCallback callback) {
|
||||||
|
mHandler.post(() -> {
|
||||||
|
try {
|
||||||
|
callback.onUpstreamChanged(mTetherUpstream);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Not really very much to do here.
|
||||||
|
}
|
||||||
|
mTetheringEventCallbacks.register(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregister tethering event callback */
|
||||||
|
public void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
|
||||||
|
mHandler.post(() -> {
|
||||||
|
mTetheringEventCallbacks.unregister(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportUpstreamChanged(Network network) {
|
||||||
|
final int length = mTetheringEventCallbacks.beginBroadcast();
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
try {
|
||||||
|
mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Not really very much to do here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mTetheringEventCallbacks.finishBroadcast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||||
// Binder.java closes the resource for us.
|
// Binder.java closes the resource for us.
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import android.hardware.usb.UsbManager;
|
|||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.InterfaceConfiguration;
|
import android.net.InterfaceConfiguration;
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
@@ -123,6 +124,7 @@ import org.mockito.MockitoAnnotations;
|
|||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -918,6 +920,67 @@ public class TetheringTest {
|
|||||||
expectedInteractionsWithShowNotification);
|
expectedInteractionsWithShowNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestTetheringEventCallback extends ITetheringEventCallback.Stub {
|
||||||
|
private final ArrayList<Network> mActualUpstreams = new ArrayList<>();
|
||||||
|
|
||||||
|
public void expectUpstreamChanged(Network... networks) {
|
||||||
|
final ArrayList<Network> expectedUpstreams =
|
||||||
|
new ArrayList<Network>(Arrays.asList(networks));
|
||||||
|
for (Network upstream : expectedUpstreams) {
|
||||||
|
// throws OOB if no expectations
|
||||||
|
assertEquals(mActualUpstreams.remove(0), upstream);
|
||||||
|
}
|
||||||
|
assertNoCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpstreamChanged(Network network) {
|
||||||
|
mActualUpstreams.add(network);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void assertNoCallback() {
|
||||||
|
assertTrue(mActualUpstreams.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterTetheringEventCallback() throws Exception {
|
||||||
|
TestTetheringEventCallback callback1 = new TestTetheringEventCallback();
|
||||||
|
TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
|
||||||
|
|
||||||
|
// 1. Register one callback and run usb tethering.
|
||||||
|
mTethering.registerTetheringEventCallback(callback1);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
callback1.expectUpstreamChanged(new Network[] {null});
|
||||||
|
NetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||||
|
runUsbTethering(upstreamState);
|
||||||
|
callback1.expectUpstreamChanged(upstreamState.network);
|
||||||
|
// 2. Register second callback.
|
||||||
|
mTethering.registerTetheringEventCallback(callback2);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
callback2.expectUpstreamChanged(upstreamState.network);
|
||||||
|
// 3. Disable usb tethering.
|
||||||
|
mTethering.stopTethering(TETHERING_USB);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
sendUsbBroadcast(false, false, false);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
callback1.expectUpstreamChanged(new Network[] {null});
|
||||||
|
callback2.expectUpstreamChanged(new Network[] {null});
|
||||||
|
// 4. Unregister first callback and run hotspot.
|
||||||
|
mTethering.unregisterTetheringEventCallback(callback1);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
|
||||||
|
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
|
||||||
|
.thenReturn(upstreamState);
|
||||||
|
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
|
||||||
|
mTethering.startTethering(TETHERING_WIFI, null, false);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||||
|
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||||
|
mLooper.dispatchAll();
|
||||||
|
callback1.assertNoCallback();
|
||||||
|
callback2.expectUpstreamChanged(upstreamState.network);
|
||||||
|
}
|
||||||
|
|
||||||
// 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