diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt index e24f5629267c5..2f060ffaf5d82 100644 --- a/wifi/api/system-current.txt +++ b/wifi/api/system-current.txt @@ -633,6 +633,7 @@ package android.net.wifi { method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability); method public default void onConnectedClientsChanged(@NonNull java.util.List); method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo); + method public default void onInfoListChanged(@NonNull java.util.List); method public default void onStateChanged(int, int); } diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl index f81bcb9e06d79..a28a8fb626b16 100644 --- a/wifi/java/android/net/wifi/ISoftApCallback.aidl +++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl @@ -53,6 +53,12 @@ oneway interface ISoftApCallback */ void onInfoChanged(in SoftApInfo softApInfo); + /** + * Service to manager callback providing informations of softap. + * + * @param softApInfoList is the list of the softap informations. {@link SoftApInfo} + */ + void onInfoListChanged(in List softApInfoList); /** * Service to manager callback providing capability of softap. diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java index 9a16facfec26a..c681ba9fd44fc 100644 --- a/wifi/java/android/net/wifi/SoftApInfo.java +++ b/wifi/java/android/net/wifi/SoftApInfo.java @@ -96,6 +96,10 @@ public final class SoftApInfo implements Parcelable { @Nullable private MacAddress mBssid; + /** The identifier of the AP instance which AP resides on with current info. */ + @Nullable + private String mApInstanceIdentifier; + /** * The operational mode of the AP. */ @@ -186,6 +190,28 @@ public final class SoftApInfo implements Parcelable { return mWifiStandard; } + /** + * Set the AP instance identifier. + * @hide + */ + public void setApInstanceIdentifier(@NonNull String apInstanceIdentifier) { + mApInstanceIdentifier = apInstanceIdentifier; + } + + /** + * Get the AP instance identifier. + * + * The AP instance identifier is a unique identity which can be used to + * associate the {@link SoftApInfo} to a specific {@link WifiClient} + * - see {@link WifiClient#getApInstanceIdentifier()} + * + * @hide + */ + @Nullable + public String getApInstanceIdentifier() { + return mApInstanceIdentifier; + } + /** * @hide */ @@ -195,6 +221,7 @@ public final class SoftApInfo implements Parcelable { mBandwidth = source.mBandwidth; mBssid = source.mBssid; mWifiStandard = source.mWifiStandard; + mApInstanceIdentifier = source.mApInstanceIdentifier; } } @@ -217,6 +244,7 @@ public final class SoftApInfo implements Parcelable { dest.writeInt(mBandwidth); dest.writeParcelable(mBssid, flags); dest.writeInt(mWifiStandard); + dest.writeString(mApInstanceIdentifier); } @NonNull @@ -228,6 +256,7 @@ public final class SoftApInfo implements Parcelable { info.mBandwidth = in.readInt(); info.mBssid = in.readParcelable(MacAddress.class.getClassLoader()); info.mWifiStandard = in.readInt(); + info.mApInstanceIdentifier = in.readString(); return info; } @@ -245,6 +274,7 @@ public final class SoftApInfo implements Parcelable { sbuf.append(", frequency= ").append(mFrequency); if (mBssid != null) sbuf.append(",bssid=").append(mBssid.toString()); sbuf.append(", wifiStandard= ").append(mWifiStandard); + sbuf.append(", mApInstanceIdentifier= ").append(mApInstanceIdentifier); sbuf.append("}"); return sbuf.toString(); } @@ -257,11 +287,12 @@ public final class SoftApInfo implements Parcelable { return mFrequency == softApInfo.mFrequency && mBandwidth == softApInfo.mBandwidth && Objects.equals(mBssid, softApInfo.mBssid) - && mWifiStandard == softApInfo.mWifiStandard; + && mWifiStandard == softApInfo.mWifiStandard + && Objects.equals(mApInstanceIdentifier, softApInfo.mApInstanceIdentifier); } @Override public int hashCode() { - return Objects.hash(mFrequency, mBandwidth, mBssid, mWifiStandard); + return Objects.hash(mFrequency, mBandwidth, mBssid, mWifiStandard, mApInstanceIdentifier); } } diff --git a/wifi/java/android/net/wifi/WifiClient.java b/wifi/java/android/net/wifi/WifiClient.java index 3794566f3d8f1..85e2b3312b293 100644 --- a/wifi/java/android/net/wifi/WifiClient.java +++ b/wifi/java/android/net/wifi/WifiClient.java @@ -30,6 +30,9 @@ public final class WifiClient implements Parcelable { private final MacAddress mMacAddress; + /** The identifier of the AP instance which the client connected. */ + private final String mApInstanceIdentifier; + /** * The mac address of this client. */ @@ -38,15 +41,30 @@ public final class WifiClient implements Parcelable { return mMacAddress; } + /** + * Get AP instance identifier. + * + * The AP instance identifier is a unique identity which can be used to + * associate the {@link SoftApInfo} to a specific {@link WifiClient} + * - see {@link SoftApInfo#getApInstanceIdentifier()} + * @hide + */ + @NonNull + public String getApInstanceIdentifier() { + return mApInstanceIdentifier; + } + private WifiClient(Parcel in) { mMacAddress = in.readParcelable(null); + mApInstanceIdentifier = in.readString(); } /** @hide */ - public WifiClient(@NonNull MacAddress macAddress) { + public WifiClient(@NonNull MacAddress macAddress, @NonNull String apInstanceIdentifier) { Objects.requireNonNull(macAddress, "mMacAddress must not be null."); this.mMacAddress = macAddress; + this.mApInstanceIdentifier = apInstanceIdentifier; } @Override @@ -57,6 +75,7 @@ public final class WifiClient implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeParcelable(mMacAddress, flags); + dest.writeString(mApInstanceIdentifier); } @NonNull @@ -75,6 +94,7 @@ public final class WifiClient implements Parcelable { public String toString() { return "WifiClient{" + "mMacAddress=" + mMacAddress + + "mApInstanceIdentifier=" + mApInstanceIdentifier + '}'; } @@ -83,13 +103,12 @@ public final class WifiClient implements Parcelable { if (this == o) return true; if (!(o instanceof WifiClient)) return false; WifiClient client = (WifiClient) o; - return mMacAddress.equals(client.mMacAddress); + return Objects.equals(mMacAddress, client.mMacAddress) + && mApInstanceIdentifier.equals(client.mApInstanceIdentifier); } @Override public int hashCode() { - return Objects.hash(mMacAddress); + return Objects.hash(mMacAddress, mApInstanceIdentifier); } } - - diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9fd70cbf6bc00..749145195db68 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -4016,12 +4016,35 @@ public class WifiManager { /** * Called when information of softap changes. * + * Note: this API is only valid when the Soft AP is configured as a single AP + * - not as a bridged AP (2 Soft APs). When the Soft AP is configured as bridged AP + * this callback will not be triggered - use the + * {@link #onInfoListChanged(List)} callback in bridged AP mode. + * * @param softApInfo is the softap information. {@link SoftApInfo} */ default void onInfoChanged(@NonNull SoftApInfo softApInfo) { // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI. } + /** + * Called when information of softap changes. + * + * The number of the information elements in the list depends on Soft AP configuration + * and state. + * For instance, an empty list will be returned when the Soft AP is disabled. + * One information element will be returned in the list when the Soft AP is configured + * as a single AP, and two information elements will be returned in the list + * when the Soft AP is configured in bridged mode. + * + * See {@link #isBridgedApConcurrencySupported()} for the detail of the bridged AP. + * + * @param softApInfoList is the list of the softap information elements. {@link SoftApInfo} + */ + default void onInfoListChanged(@NonNull List softApInfoList) { + // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI. + } + /** * Called when capability of softap changes. * @@ -4101,6 +4124,19 @@ public class WifiManager { }); } + @Override + public void onInfoListChanged(List softApInfoList) { + if (mVerboseLoggingEnabled) { + Log.v(TAG, "SoftApCallbackProxy: onInfoListChange: softApInfoList=" + + softApInfoList); + } + + Binder.clearCallingIdentity(); + mExecutor.execute(() -> { + mCallback.onInfoListChanged(softApInfoList); + }); + } + @Override public void onCapabilityChanged(SoftApCapability capability) { if (mVerboseLoggingEnabled) { diff --git a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java index 28758432119c2..2121d10121b0c 100644 --- a/wifi/tests/src/android/net/wifi/SoftApInfoTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApInfoTest.java @@ -32,17 +32,22 @@ import org.junit.Test; */ @SmallTest public class SoftApInfoTest { - + private static final String TEST_AP_INSTANCE = "wlan1"; + private static final int TEST_FREQUENCY = 2412; + private static final int TEST_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ; + private static final int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_LEGACY; + private static final MacAddress TEST_AP_MAC = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); /** * Verifies copy constructor. */ @Test public void testCopyOperator() throws Exception { SoftApInfo info = new SoftApInfo(); - info.setFrequency(2412); - info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ); - info.setBssid(MacAddress.fromString("aa:bb:cc:dd:ee:ff")); - info.setWifiStandard(ScanResult.WIFI_STANDARD_LEGACY); + info.setFrequency(TEST_FREQUENCY); + info.setBandwidth(TEST_BANDWIDTH); + info.setBssid(TEST_AP_MAC); + info.setWifiStandard(TEST_WIFI_STANDARD); + info.setApInstanceIdentifier(TEST_AP_INSTANCE); SoftApInfo copiedInfo = new SoftApInfo(info); @@ -57,10 +62,11 @@ public class SoftApInfoTest { @Test public void testParcelOperation() throws Exception { SoftApInfo info = new SoftApInfo(); - info.setFrequency(2412); - info.setBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ); - info.setBssid(MacAddress.fromString("aa:bb:cc:dd:ee:ff")); - info.setWifiStandard(ScanResult.WIFI_STANDARD_LEGACY); + info.setFrequency(TEST_FREQUENCY); + info.setBandwidth(TEST_BANDWIDTH); + info.setBssid(TEST_AP_MAC); + info.setWifiStandard(TEST_WIFI_STANDARD); + info.setApInstanceIdentifier(TEST_AP_INSTANCE); Parcel parcelW = Parcel.obtain(); info.writeToParcel(parcelW, 0); @@ -88,6 +94,27 @@ public class SoftApInfoTest { if (SdkLevel.isAtLeastS()) { assertEquals(info.getBssid(), null); assertEquals(info.getWifiStandard(), ScanResult.WIFI_STANDARD_UNKNOWN); + assertEquals(info.getApInstanceIdentifier(), null); + } + } + + /** + * Verifies the set/get method same as expected. + */ + @Test + public void testGetXXXAlignedWithSetXXX() throws Exception { + SoftApInfo info = new SoftApInfo(); + info.setFrequency(TEST_FREQUENCY); + info.setBandwidth(TEST_BANDWIDTH); + info.setBssid(TEST_AP_MAC); + info.setWifiStandard(TEST_WIFI_STANDARD); + info.setApInstanceIdentifier(TEST_AP_INSTANCE); + assertEquals(info.getFrequency(), TEST_FREQUENCY); + assertEquals(info.getBandwidth(), TEST_BANDWIDTH); + if (SdkLevel.isAtLeastS()) { + assertEquals(info.getBssid(), TEST_AP_MAC); + assertEquals(info.getWifiStandard(), TEST_WIFI_STANDARD); + assertEquals(info.getApInstanceIdentifier(), TEST_AP_INSTANCE); } } diff --git a/wifi/tests/src/android/net/wifi/WifiClientTest.java b/wifi/tests/src/android/net/wifi/WifiClientTest.java index 7a3baf9ebaf29..704656320a91d 100644 --- a/wifi/tests/src/android/net/wifi/WifiClientTest.java +++ b/wifi/tests/src/android/net/wifi/WifiClientTest.java @@ -42,9 +42,9 @@ public class WifiClientTest { */ @Test public void testWifiClientParcelWriteRead() throws Exception { - WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS); + WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME); - assertParcelSane(writeWifiClient, 1); + assertParcelSane(writeWifiClient, 2); } /** @@ -52,12 +52,12 @@ public class WifiClientTest { */ @Test public void testWifiClientEquals() throws Exception { - WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS); - WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS); + WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME); + WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS, INTERFACE_NAME); assertEquals(writeWifiClient, writeWifiClientEquals); assertEquals(writeWifiClient.hashCode(), writeWifiClientEquals.hashCode()); - assertFieldCountEquals(1, WifiClient.class); + assertFieldCountEquals(2, WifiClient.class); } /** @@ -66,8 +66,8 @@ public class WifiClientTest { @Test public void testWifiClientNotEquals() throws Exception { final MacAddress macAddressNotEquals = MacAddress.fromString("00:00:00:00:00:00"); - WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS); - WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals); + WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS, INTERFACE_NAME); + WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals, INTERFACE_NAME); assertNotEquals(writeWifiClient, writeWifiClientNotEquals); assertNotEquals(writeWifiClient.hashCode(), writeWifiClientNotEquals.hashCode()); diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 52e91394d8bf5..bd56e5b49ee6a 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -137,6 +137,7 @@ public class WifiManagerTest { private static final int TEST_AP_FREQUENCY = 2412; private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ; private static final int TEST_SUB_ID = 3; + private static final String TEST_AP_INSTANCE = "wlan1"; @Mock Context mContext; @Mock android.net.wifi.IWifiManager mWifiService; @@ -1111,6 +1112,27 @@ public class WifiManagerTest { verify(mSoftApCallback).onInfoChanged(testSoftApInfo); } + /* + * Verify client-provided callback is being called through callback proxy + */ + @Test + public void softApCallbackProxyCallsOnSoftApInfoListChanged() throws Exception { + SoftApInfo testSoftApInfo = new SoftApInfo(); + testSoftApInfo.setFrequency(TEST_AP_FREQUENCY); + testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH); + List infoList = new ArrayList<>(); + infoList.add(testSoftApInfo); + ArgumentCaptor callbackCaptor = + ArgumentCaptor.forClass(ISoftApCallback.Stub.class); + mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback); + verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(), + anyInt()); + + callbackCaptor.getValue().onInfoListChanged(infoList); + mLooper.dispatchAll(); + verify(mSoftApCallback).onInfoListChanged(infoList); + } + /* * Verify client-provided callback is being called through callback proxy @@ -1135,7 +1157,8 @@ public class WifiManagerTest { */ @Test public void softApCallbackProxyCallsOnBlockedClientConnecting() throws Exception { - WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77")); + WifiClient testWifiClient = new WifiClient(MacAddress.fromString("22:33:44:55:66:77"), + TEST_AP_INSTANCE); ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass(ISoftApCallback.Stub.class); mWifiManager.registerSoftApCallback(new HandlerExecutor(mHandler), mSoftApCallback); @@ -1157,6 +1180,8 @@ public class WifiManagerTest { SoftApInfo testSoftApInfo = new SoftApInfo(); testSoftApInfo.setFrequency(TEST_AP_FREQUENCY); testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH); + List infoList = new ArrayList<>(); + infoList.add(testSoftApInfo); SoftApCapability testSoftApCapability = new SoftApCapability(0); testSoftApCapability.setMaxSupportedClients(10); ArgumentCaptor callbackCaptor = @@ -1169,6 +1194,7 @@ public class WifiManagerTest { callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0); callbackCaptor.getValue().onConnectedClientsChanged(testClients); callbackCaptor.getValue().onInfoChanged(testSoftApInfo); + callbackCaptor.getValue().onInfoListChanged(infoList); callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); callbackCaptor.getValue().onCapabilityChanged(testSoftApCapability); @@ -1177,6 +1203,7 @@ public class WifiManagerTest { verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0); verify(mSoftApCallback).onConnectedClientsChanged(testClients); verify(mSoftApCallback).onInfoChanged(testSoftApInfo); + verify(mSoftApCallback).onInfoListChanged(infoList); verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL); verify(mSoftApCallback).onCapabilityChanged(testSoftApCapability); }