diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp index 6bff61668e..d868f39c98 100644 --- a/Tethering/common/TetheringLib/Android.bp +++ b/Tethering/common/TetheringLib/Android.bp @@ -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" } diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt index 6ddb122936..0566040dd7 100644 --- a/Tethering/common/TetheringLib/api/module-lib-current.txt +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -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 getTetherableBluetoothRegexs(); - method @NonNull public java.util.List getTetherableUsbRegexs(); - method @NonNull public java.util.List getTetherableWifiRegexs(); + @Deprecated public static class TetheringManager.TetheringInterfaceRegexps { + method @Deprecated @NonNull public java.util.List getTetherableBluetoothRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableUsbRegexs(); + method @Deprecated @NonNull public java.util.List getTetherableWifiRegexs(); } } diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt index 105bab11d5..844ff6471a 100644 --- a/Tethering/common/TetheringLib/api/system-current.txt +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -19,6 +19,15 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator 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 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); 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); + method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.Set); method public default void onOffloadStatusChanged(int); method public default void onTetherableInterfacesChanged(@NonNull java.util.List); + method public default void onTetherableInterfacesChanged(@NonNull java.util.Set); method public default void onTetheredInterfacesChanged(@NonNull java.util.List); + method public default void onTetheredInterfacesChanged(@NonNull java.util.Set); method public default void onTetheringSupported(boolean); method public default void onUpstreamChanged(@Nullable android.net.Network); } diff --git a/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl index 3d842b3374..43262fb9d1 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl +++ b/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl @@ -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; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringInterface.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringInterface.aidl new file mode 100644 index 0000000000..715198447f --- /dev/null +++ b/Tethering/common/TetheringLib/src/android/net/TetheringInterface.aidl @@ -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; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringInterface.java b/Tethering/common/TetheringLib/src/android/net/TetheringInterface.java new file mode 100644 index 0000000000..84cdef1163 --- /dev/null +++ b/Tethering/common/TetheringLib/src/android/net/TetheringInterface.java @@ -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 CREATOR = new Creator() { + @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 + "}"; + } +} diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index bd0b1b96bf..edd141d383 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -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 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. + * + *

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 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. * *

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 interfaces) {} + /** + * Called when there was a change in the list of tethered interfaces. + * + *

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 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 interfaces) {} + /** + * Called when there was a change in the list of local-only interfaces. + * + *

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 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. + * + *

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 toIfaces(Collection tetherIfaces) { + final ArrayList 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 mErrorStates = new HashMap<>(); - private String[] mLastTetherableInterfaces = null; - private String[] mLastTetheredInterfaces = null; - private String[] mLastLocalOnlyInterfaces = null; + private final HashMap 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); } /** diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 0e8b2b5e71..759638083f 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -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 availableList = new ArrayList<>(); - final ArrayList tetherList = new ArrayList<>(); - final ArrayList localOnlyList = new ArrayList<>(); - final ArrayList erroredList = new ArrayList<>(); - final ArrayList lastErrorList = new ArrayList<>(); + final ArrayList available = new ArrayList<>(); + final ArrayList tethered = new ArrayList<>(); + final ArrayList localOnly = new ArrayList<>(); + final ArrayList errored = new ArrayList<>(); + final ArrayList 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 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 available, + final ArrayList localOnly, + final ArrayList tethered, + final ArrayList errored, + final ArrayList 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 available, + final ArrayList localOnly, + final ArrayList tethered, + final ArrayList 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; diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 69c17583a0..2b158665cc 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -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);