Add the tethering type to TetheringEventCallback methods
Before this change, tethering always report a list of tethered interfaces and the caller need to use each tethering type's interface regex to matching tethered list to manual implement the mapping of tethering type and interface. This change allow caller to get rid of tethering interface regex. Bug: 162920185 Bug: 152203943 Test: atest CtsTetheringTest on S Ignore-AOSP-First: Currently aosp would automerge to mainlne-prod, merge to sc-dev first to avoid adding new API to mainline-prod CTS-Coverage-Bug: I already add cts test(ag/14622456), but Lint still complaint because my cts is under packages/modules/Connectivity/ but it only check whether CL touching platform/cts Change-Id: I91bcccd676d109c1b974497ac29bd366a41b8899
This commit is contained in:
@@ -57,6 +57,8 @@ filegroup {
|
||||
"src/android/net/TetheringConfigurationParcel.aidl",
|
||||
"src/android/net/TetheringRequestParcel.aidl",
|
||||
"src/android/net/TetherStatesParcel.aidl",
|
||||
"src/android/net/TetheringInterface.aidl",
|
||||
"src/android/net/TetheringInterface.java",
|
||||
],
|
||||
path: "src"
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ package android.net {
|
||||
}
|
||||
|
||||
public static interface TetheringManager.TetheringEventCallback {
|
||||
method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
|
||||
method @Deprecated public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
|
||||
}
|
||||
|
||||
public static class TetheringManager.TetheringInterfaceRegexps {
|
||||
method @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
|
||||
method @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
|
||||
method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
|
||||
@Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
|
||||
method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
|
||||
method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
|
||||
method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,15 @@ package android.net {
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
|
||||
}
|
||||
|
||||
public final class TetheringInterface implements android.os.Parcelable {
|
||||
ctor public TetheringInterface(int, @NonNull String);
|
||||
method public int describeContents();
|
||||
method @NonNull public String getInterface();
|
||||
method public int getType();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheringInterface> CREATOR;
|
||||
}
|
||||
|
||||
public class TetheringManager {
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
|
||||
@@ -26,7 +35,7 @@ package android.net {
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
|
||||
field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
|
||||
field @Deprecated public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
|
||||
field public static final int CONNECTIVITY_SCOPE_GLOBAL = 1; // 0x1
|
||||
field public static final int CONNECTIVITY_SCOPE_LOCAL = 2; // 0x2
|
||||
field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
|
||||
@@ -74,10 +83,14 @@ package android.net {
|
||||
public static interface TetheringManager.TetheringEventCallback {
|
||||
method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
|
||||
method public default void onError(@NonNull String, int);
|
||||
method public default void onError(@NonNull android.net.TetheringInterface, int);
|
||||
method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||
method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
|
||||
method public default void onOffloadStatusChanged(int);
|
||||
method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||
method public default void onTetherableInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
|
||||
method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||
method public default void onTetheredInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
|
||||
method public default void onTetheringSupported(boolean);
|
||||
method public default void onUpstreamChanged(@Nullable android.net.Network);
|
||||
}
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.net.TetheringInterface;
|
||||
|
||||
/**
|
||||
* Status details for tethering downstream interfaces.
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable TetherStatesParcel {
|
||||
String[] availableList;
|
||||
String[] tetheredList;
|
||||
String[] localOnlyList;
|
||||
String[] erroredIfaceList;
|
||||
TetheringInterface[] availableList;
|
||||
TetheringInterface[] tetheredList;
|
||||
TetheringInterface[] localOnlyList;
|
||||
TetheringInterface[] erroredIfaceList;
|
||||
// List of Last error code corresponding to each errored iface in erroredIfaceList. */
|
||||
// TODO: Improve this as b/143122247.
|
||||
int[] lastErrorList;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable TetheringInterface;
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.net.TetheringManager.TetheringType;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The mapping of tethering interface and type.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class TetheringInterface implements Parcelable {
|
||||
private final int mType;
|
||||
private final String mInterface;
|
||||
|
||||
public TetheringInterface(@TetheringType int type, @NonNull String iface) {
|
||||
Objects.requireNonNull(iface);
|
||||
mType = type;
|
||||
mInterface = iface;
|
||||
}
|
||||
|
||||
private TetheringInterface(@NonNull Parcel in) {
|
||||
this(in.readInt(), in.readString());
|
||||
}
|
||||
|
||||
/** Get tethering type. */
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/** Get tethering interface. */
|
||||
@NonNull
|
||||
public String getInterface() {
|
||||
return mInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mType);
|
||||
dest.writeString(mInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mType, mInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (!(obj instanceof TetheringInterface)) return false;
|
||||
final TetheringInterface other = (TetheringInterface) obj;
|
||||
return mType == other.mType && mInterface.equals(other.mInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<TetheringInterface> CREATOR = new Creator<TetheringInterface>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public TetheringInterface createFromParcel(@NonNull Parcel in) {
|
||||
return new TetheringInterface(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TetheringInterface[] newArray(int size) {
|
||||
return new TetheringInterface[size];
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TetheringInterface {mType=" + mType
|
||||
+ ", mInterface=" + mInterface + "}";
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -43,6 +44,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -83,7 +85,10 @@ public class TetheringManager {
|
||||
* {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
|
||||
* the current state of tethering. Each include a list of
|
||||
* interface names in that state (may be empty).
|
||||
*
|
||||
* @deprecated New client should use TetheringEventCallback instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String ACTION_TETHER_STATE_CHANGED =
|
||||
"android.net.conn.TETHER_STATE_CHANGED";
|
||||
|
||||
@@ -531,7 +536,7 @@ public class TetheringManager {
|
||||
/**
|
||||
* Attempt to both alter the mode of USB and Tethering of USB.
|
||||
*
|
||||
* @deprecated New client should not use this API anymore. All clients should use
|
||||
* @deprecated New clients should not use this API anymore. All clients should use
|
||||
* #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
|
||||
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
|
||||
* not have any upstream.
|
||||
@@ -978,8 +983,13 @@ public class TetheringManager {
|
||||
* multiple times later upon changes.
|
||||
* @param reg The new regular expressions.
|
||||
*
|
||||
* @deprecated New clients should use the callbacks with {@link TetheringInterface} which
|
||||
* has the mapping between tethering type and interface. InterfaceRegex is no longer needed
|
||||
* to determine the mapping of tethering type and interface.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
|
||||
|
||||
@@ -993,15 +1003,43 @@ public class TetheringManager {
|
||||
*/
|
||||
default void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
|
||||
|
||||
/**
|
||||
* Called when there was a change in the list of tetherable interfaces. Tetherable
|
||||
* interface means this interface is available and can be used for tethering.
|
||||
*
|
||||
* <p>This will be called immediately after the callback is registered, and may be called
|
||||
* multiple times later upon changes.
|
||||
* @param interfaces The set of TetheringInterface of currently tetherable interface.
|
||||
*/
|
||||
default void onTetherableInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
|
||||
// By default, the new callback calls the old callback, so apps
|
||||
// implementing the old callback just work.
|
||||
onTetherableInterfacesChanged(toIfaces(interfaces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there was a change in the list of tethered interfaces.
|
||||
*
|
||||
* <p>This will be called immediately after the callback is registered, and may be called
|
||||
* multiple times later upon changes.
|
||||
* @param interfaces The list of 0 or more String of currently tethered interface names.
|
||||
* @param interfaces The lit of 0 or more String of currently tethered interface names.
|
||||
*/
|
||||
default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
|
||||
|
||||
/**
|
||||
* Called when there was a change in the list of tethered interfaces.
|
||||
*
|
||||
* <p>This will be called immediately after the callback is registered, and may be called
|
||||
* multiple times later upon changes.
|
||||
* @param interfaces The set of 0 or more TetheringInterface of currently tethered
|
||||
* interface.
|
||||
*/
|
||||
default void onTetheredInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
|
||||
// By default, the new callback calls the old callback, so apps
|
||||
// implementing the old callback just work.
|
||||
onTetheredInterfacesChanged(toIfaces(interfaces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there was a change in the list of local-only interfaces.
|
||||
*
|
||||
@@ -1011,6 +1049,20 @@ public class TetheringManager {
|
||||
*/
|
||||
default void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) {}
|
||||
|
||||
/**
|
||||
* Called when there was a change in the list of local-only interfaces.
|
||||
*
|
||||
* <p>This will be called immediately after the callback is registered, and may be called
|
||||
* multiple times later upon changes.
|
||||
* @param interfaces The set of 0 or more TetheringInterface of active local-only
|
||||
* interface.
|
||||
*/
|
||||
default void onLocalOnlyInterfacesChanged(@NonNull Set<TetheringInterface> interfaces) {
|
||||
// By default, the new callback calls the old callback, so apps
|
||||
// implementing the old callback just work.
|
||||
onLocalOnlyInterfacesChanged(toIfaces(interfaces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an error occurred configuring tethering.
|
||||
*
|
||||
@@ -1021,6 +1073,20 @@ public class TetheringManager {
|
||||
*/
|
||||
default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
|
||||
|
||||
/**
|
||||
* Called when an error occurred configuring tethering.
|
||||
*
|
||||
* <p>This will be called immediately after the callback is registered if the latest status
|
||||
* on the interface is an error, and may be called multiple times later upon changes.
|
||||
* @param iface The interface that experienced the error.
|
||||
* @param error One of {@code TetheringManager#TETHER_ERROR_*}.
|
||||
*/
|
||||
default void onError(@NonNull TetheringInterface iface, @TetheringIfaceError int error) {
|
||||
// By default, the new callback calls the old callback, so apps
|
||||
// implementing the old callback just work.
|
||||
onError(iface.getInterface(), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the list of tethered clients changes.
|
||||
*
|
||||
@@ -1044,9 +1110,37 @@ public class TetheringManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular expressions used to identify tethering interfaces.
|
||||
* Covert DownStreamInterface collection to interface String array list. Internal use only.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static ArrayList<String> toIfaces(Collection<TetheringInterface> tetherIfaces) {
|
||||
final ArrayList<String> ifaces = new ArrayList<>();
|
||||
for (TetheringInterface tether : tetherIfaces) {
|
||||
ifaces.add(tether.getInterface());
|
||||
}
|
||||
|
||||
return ifaces;
|
||||
}
|
||||
|
||||
private static String[] toIfaces(TetheringInterface[] tetherIfaces) {
|
||||
final String[] ifaces = new String[tetherIfaces.length];
|
||||
for (int i = 0; i < tetherIfaces.length; i++) {
|
||||
ifaces[i] = tetherIfaces[i].getInterface();
|
||||
}
|
||||
|
||||
return ifaces;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Regular expressions used to identify tethering interfaces.
|
||||
*
|
||||
* @deprecated Instead of using regex to determine tethering type. New client could use the
|
||||
* callbacks with {@link TetheringInterface} which has the mapping of type and interface.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public static class TetheringInterfaceRegexps {
|
||||
private final String[] mTetherableBluetoothRegexs;
|
||||
@@ -1114,10 +1208,10 @@ public class TetheringManager {
|
||||
}
|
||||
final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
|
||||
// Only accessed with a lock on this object
|
||||
private final HashMap<String, Integer> mErrorStates = new HashMap<>();
|
||||
private String[] mLastTetherableInterfaces = null;
|
||||
private String[] mLastTetheredInterfaces = null;
|
||||
private String[] mLastLocalOnlyInterfaces = null;
|
||||
private final HashMap<TetheringInterface, Integer> mErrorStates = new HashMap<>();
|
||||
private TetheringInterface[] mLastTetherableInterfaces = null;
|
||||
private TetheringInterface[] mLastTetheredInterfaces = null;
|
||||
private TetheringInterface[] mLastLocalOnlyInterfaces = null;
|
||||
|
||||
@Override
|
||||
public void onUpstreamChanged(Network network) throws RemoteException {
|
||||
@@ -1128,14 +1222,14 @@ public class TetheringManager {
|
||||
|
||||
private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
|
||||
for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
|
||||
final String iface = newStates.erroredIfaceList[i];
|
||||
final Integer lastError = mErrorStates.get(iface);
|
||||
final TetheringInterface tetherIface = newStates.erroredIfaceList[i];
|
||||
final Integer lastError = mErrorStates.get(tetherIface);
|
||||
final int newError = newStates.lastErrorList[i];
|
||||
if (newError != TETHER_ERROR_NO_ERROR
|
||||
&& !Objects.equals(lastError, newError)) {
|
||||
callback.onError(iface, newError);
|
||||
callback.onError(tetherIface, newError);
|
||||
}
|
||||
mErrorStates.put(iface, newError);
|
||||
mErrorStates.put(tetherIface, newError);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,7 +1238,7 @@ public class TetheringManager {
|
||||
if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
|
||||
mLastTetherableInterfaces = newStates.availableList.clone();
|
||||
callback.onTetherableInterfacesChanged(
|
||||
Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
|
||||
Collections.unmodifiableSet((new ArraySet(mLastTetherableInterfaces))));
|
||||
}
|
||||
|
||||
private synchronized void maybeSendTetheredIfacesChangedCallback(
|
||||
@@ -1152,7 +1246,7 @@ public class TetheringManager {
|
||||
if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
|
||||
mLastTetheredInterfaces = newStates.tetheredList.clone();
|
||||
callback.onTetheredInterfacesChanged(
|
||||
Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
|
||||
Collections.unmodifiableSet((new ArraySet(mLastTetheredInterfaces))));
|
||||
}
|
||||
|
||||
private synchronized void maybeSendLocalOnlyIfacesChangedCallback(
|
||||
@@ -1160,7 +1254,7 @@ public class TetheringManager {
|
||||
if (Arrays.equals(mLastLocalOnlyInterfaces, newStates.localOnlyList)) return;
|
||||
mLastLocalOnlyInterfaces = newStates.localOnlyList.clone();
|
||||
callback.onLocalOnlyInterfacesChanged(
|
||||
Collections.unmodifiableList(Arrays.asList(mLastLocalOnlyInterfaces)));
|
||||
Collections.unmodifiableSet((new ArraySet(mLastLocalOnlyInterfaces))));
|
||||
}
|
||||
|
||||
// Called immediately after the callbacks are registered.
|
||||
@@ -1262,8 +1356,8 @@ public class TetheringManager {
|
||||
if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
|
||||
|
||||
int i = 0;
|
||||
for (String errored : mTetherStatesParcel.erroredIfaceList) {
|
||||
if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
|
||||
for (TetheringInterface errored : mTetherStatesParcel.erroredIfaceList) {
|
||||
if (iface.equals(errored.getInterface())) return mTetherStatesParcel.lastErrorList[i];
|
||||
|
||||
i++;
|
||||
}
|
||||
@@ -1327,7 +1421,7 @@ public class TetheringManager {
|
||||
mCallback.waitForStarted();
|
||||
if (mTetherStatesParcel == null) return new String[0];
|
||||
|
||||
return mTetherStatesParcel.availableList;
|
||||
return toIfaces(mTetherStatesParcel.availableList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1341,7 +1435,7 @@ public class TetheringManager {
|
||||
mCallback.waitForStarted();
|
||||
if (mTetherStatesParcel == null) return new String[0];
|
||||
|
||||
return mTetherStatesParcel.tetheredList;
|
||||
return toIfaces(mTetherStatesParcel.tetheredList);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1361,7 +1455,7 @@ public class TetheringManager {
|
||||
mCallback.waitForStarted();
|
||||
if (mTetherStatesParcel == null) return new String[0];
|
||||
|
||||
return mTetherStatesParcel.erroredIfaceList;
|
||||
return toIfaces(mTetherStatesParcel.erroredIfaceList);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,7 @@ import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
|
||||
import static android.net.TetheringManager.toIfaces;
|
||||
import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
||||
@@ -92,6 +93,7 @@ import android.net.TetherStatesParcel;
|
||||
import android.net.TetheredClient;
|
||||
import android.net.TetheringCallbackStartedParcel;
|
||||
import android.net.TetheringConfigurationParcel;
|
||||
import android.net.TetheringInterface;
|
||||
import android.net.TetheringManager.TetheringRequest;
|
||||
import android.net.TetheringRequestParcel;
|
||||
import android.net.ip.IpServer;
|
||||
@@ -143,7 +145,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -854,26 +855,27 @@ public class Tethering {
|
||||
private void sendTetherStateChangedBroadcast() {
|
||||
if (!isTetheringSupported()) return;
|
||||
|
||||
final ArrayList<String> availableList = new ArrayList<>();
|
||||
final ArrayList<String> tetherList = new ArrayList<>();
|
||||
final ArrayList<String> localOnlyList = new ArrayList<>();
|
||||
final ArrayList<String> erroredList = new ArrayList<>();
|
||||
final ArrayList<Integer> lastErrorList = new ArrayList<>();
|
||||
final ArrayList<TetheringInterface> available = new ArrayList<>();
|
||||
final ArrayList<TetheringInterface> tethered = new ArrayList<>();
|
||||
final ArrayList<TetheringInterface> localOnly = new ArrayList<>();
|
||||
final ArrayList<TetheringInterface> errored = new ArrayList<>();
|
||||
final ArrayList<Integer> lastErrors = new ArrayList<>();
|
||||
|
||||
final TetheringConfiguration cfg = mConfig;
|
||||
mTetherStatesParcel = new TetherStatesParcel();
|
||||
|
||||
int downstreamTypesMask = DOWNSTREAM_NONE;
|
||||
for (int i = 0; i < mTetherStates.size(); i++) {
|
||||
TetherState tetherState = mTetherStates.valueAt(i);
|
||||
String iface = mTetherStates.keyAt(i);
|
||||
final TetherState tetherState = mTetherStates.valueAt(i);
|
||||
final int type = tetherState.ipServer.interfaceType();
|
||||
final String iface = mTetherStates.keyAt(i);
|
||||
final TetheringInterface tetheringIface = new TetheringInterface(type, iface);
|
||||
if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
|
||||
erroredList.add(iface);
|
||||
lastErrorList.add(tetherState.lastError);
|
||||
errored.add(tetheringIface);
|
||||
lastErrors.add(tetherState.lastError);
|
||||
} else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
|
||||
availableList.add(iface);
|
||||
available.add(tetheringIface);
|
||||
} else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
|
||||
localOnlyList.add(iface);
|
||||
localOnly.add(tetheringIface);
|
||||
} else if (tetherState.lastState == IpServer.STATE_TETHERED) {
|
||||
if (cfg.isUsb(iface)) {
|
||||
downstreamTypesMask |= (1 << TETHERING_USB);
|
||||
@@ -882,40 +884,63 @@ public class Tethering {
|
||||
} else if (cfg.isBluetooth(iface)) {
|
||||
downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
|
||||
}
|
||||
tetherList.add(iface);
|
||||
tethered.add(tetheringIface);
|
||||
}
|
||||
}
|
||||
|
||||
mTetherStatesParcel.availableList = availableList.toArray(new String[0]);
|
||||
mTetherStatesParcel.tetheredList = tetherList.toArray(new String[0]);
|
||||
mTetherStatesParcel.localOnlyList = localOnlyList.toArray(new String[0]);
|
||||
mTetherStatesParcel.erroredIfaceList = erroredList.toArray(new String[0]);
|
||||
mTetherStatesParcel.lastErrorList = new int[lastErrorList.size()];
|
||||
Iterator<Integer> iterator = lastErrorList.iterator();
|
||||
for (int i = 0; i < lastErrorList.size(); i++) {
|
||||
mTetherStatesParcel.lastErrorList[i] = iterator.next().intValue();
|
||||
}
|
||||
mTetherStatesParcel = buildTetherStatesParcel(available, localOnly, tethered, errored,
|
||||
lastErrors);
|
||||
reportTetherStateChanged(mTetherStatesParcel);
|
||||
|
||||
final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
|
||||
bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
|
||||
bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
|
||||
bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
|
||||
bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
|
||||
bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
|
||||
mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
|
||||
mContext.sendStickyBroadcastAsUser(buildStateChangeIntent(available, localOnly, tethered,
|
||||
errored), UserHandle.ALL);
|
||||
if (DBG) {
|
||||
Log.d(TAG, String.format(
|
||||
"sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
|
||||
"avail", TextUtils.join(",", availableList),
|
||||
"local_only", TextUtils.join(",", localOnlyList),
|
||||
"tether", TextUtils.join(",", tetherList),
|
||||
"error", TextUtils.join(",", erroredList)));
|
||||
"reportTetherStateChanged %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
|
||||
"avail", TextUtils.join(",", available),
|
||||
"local_only", TextUtils.join(",", localOnly),
|
||||
"tether", TextUtils.join(",", tethered),
|
||||
"error", TextUtils.join(",", errored)));
|
||||
}
|
||||
|
||||
mNotificationUpdater.onDownstreamChanged(downstreamTypesMask);
|
||||
}
|
||||
|
||||
private TetherStatesParcel buildTetherStatesParcel(
|
||||
final ArrayList<TetheringInterface> available,
|
||||
final ArrayList<TetheringInterface> localOnly,
|
||||
final ArrayList<TetheringInterface> tethered,
|
||||
final ArrayList<TetheringInterface> errored,
|
||||
final ArrayList<Integer> lastErrors) {
|
||||
final TetherStatesParcel parcel = new TetherStatesParcel();
|
||||
|
||||
parcel.availableList = available.toArray(new TetheringInterface[0]);
|
||||
parcel.tetheredList = tethered.toArray(new TetheringInterface[0]);
|
||||
parcel.localOnlyList = localOnly.toArray(new TetheringInterface[0]);
|
||||
parcel.erroredIfaceList = errored.toArray(new TetheringInterface[0]);
|
||||
parcel.lastErrorList = new int[lastErrors.size()];
|
||||
for (int i = 0; i < lastErrors.size(); i++) {
|
||||
parcel.lastErrorList[i] = lastErrors.get(i);
|
||||
}
|
||||
|
||||
return parcel;
|
||||
}
|
||||
|
||||
private Intent buildStateChangeIntent(final ArrayList<TetheringInterface> available,
|
||||
final ArrayList<TetheringInterface> localOnly,
|
||||
final ArrayList<TetheringInterface> tethered,
|
||||
final ArrayList<TetheringInterface> errored) {
|
||||
final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
|
||||
bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
|
||||
|
||||
bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, toIfaces(available));
|
||||
bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, toIfaces(localOnly));
|
||||
bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, toIfaces(tethered));
|
||||
bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, toIfaces(errored));
|
||||
|
||||
return bcast;
|
||||
}
|
||||
|
||||
private class StateReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context content, Intent intent) {
|
||||
@@ -2082,10 +2107,10 @@ public class Tethering {
|
||||
|
||||
private TetherStatesParcel emptyTetherStatesParcel() {
|
||||
final TetherStatesParcel parcel = new TetherStatesParcel();
|
||||
parcel.availableList = new String[0];
|
||||
parcel.tetheredList = new String[0];
|
||||
parcel.localOnlyList = new String[0];
|
||||
parcel.erroredIfaceList = new String[0];
|
||||
parcel.availableList = new TetheringInterface[0];
|
||||
parcel.tetheredList = new TetheringInterface[0];
|
||||
parcel.localOnlyList = new TetheringInterface[0];
|
||||
parcel.erroredIfaceList = new TetheringInterface[0];
|
||||
parcel.lastErrorList = new int[0];
|
||||
|
||||
return parcel;
|
||||
|
||||
@@ -132,6 +132,7 @@ import android.net.TetheredClient;
|
||||
import android.net.TetheredClient.AddressInfo;
|
||||
import android.net.TetheringCallbackStartedParcel;
|
||||
import android.net.TetheringConfigurationParcel;
|
||||
import android.net.TetheringInterface;
|
||||
import android.net.TetheringRequestParcel;
|
||||
import android.net.dhcp.DhcpLeaseParcelable;
|
||||
import android.net.dhcp.DhcpServerCallbacks;
|
||||
@@ -1779,6 +1780,8 @@ public class TetheringTest {
|
||||
public void testRegisterTetheringEventCallback() throws Exception {
|
||||
TestTetheringEventCallback callback = new TestTetheringEventCallback();
|
||||
TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
|
||||
final TetheringInterface wifiIface = new TetheringInterface(
|
||||
TETHERING_WIFI, TEST_WLAN_IFNAME);
|
||||
|
||||
// 1. Register one callback before running any tethering.
|
||||
mTethering.registerTetheringEventCallback(callback);
|
||||
@@ -1797,12 +1800,12 @@ public class TetheringTest {
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
mLooper.dispatchAll();
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
|
||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
tetherState = callback.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
|
||||
assertArrayEquals(tetherState.tetheredList, new TetheringInterface[] {wifiIface});
|
||||
callback.expectUpstreamChanged(upstreamState.network);
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
|
||||
|
||||
@@ -1814,7 +1817,7 @@ public class TetheringTest {
|
||||
callback2.expectConfigurationChanged(
|
||||
mTethering.getTetheringConfiguration().toStableParcelable());
|
||||
tetherState = callback2.pollTetherStatesChanged();
|
||||
assertEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
|
||||
assertEquals(tetherState.tetheredList, new TetheringInterface[] {wifiIface});
|
||||
callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
|
||||
|
||||
// 4. Unregister first callback and disable wifi tethering
|
||||
@@ -1823,7 +1826,7 @@ public class TetheringTest {
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
|
||||
tetherState = callback2.pollTetherStatesChanged();
|
||||
assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
|
||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||
mLooper.dispatchAll();
|
||||
callback2.expectUpstreamChanged(new Network[] {null});
|
||||
callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||
|
||||
Reference in New Issue
Block a user