WifiInfo: Add info elements for connected bssid
Also, remove isAtLeastS() from WifiInfoTest (we're no longer guarding unit
tests using SDK version).
Bug: 175853962
Test: atest android.net.wifi
Change-Id: I384c9321e1f74bf4ad4431b6dbe8f8fc2392dff9
diff --git a/framework/api/current.txt b/framework/api/current.txt
index a8bf4ce..421b9fd 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -51,11 +51,14 @@
field @Deprecated public CharSequence venueName;
}
- public static class ScanResult.InformationElement {
+ public static class ScanResult.InformationElement implements android.os.Parcelable {
ctor public ScanResult.InformationElement(@NonNull android.net.wifi.ScanResult.InformationElement);
+ method public int describeContents();
method @NonNull public java.nio.ByteBuffer getBytes();
method public int getId();
method public int getIdExt();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.ScanResult.InformationElement> CREATOR;
}
public final class SoftApConfiguration implements android.os.Parcelable {
@@ -276,6 +279,7 @@
method public static android.net.NetworkInfo.DetailedState getDetailedStateOf(android.net.wifi.SupplicantState);
method public int getFrequency();
method public boolean getHiddenSSID();
+ method @Nullable public java.util.List<android.net.wifi.ScanResult.InformationElement> getInformationElements();
method @Deprecated public int getIpAddress();
method public int getLinkSpeed();
method public String getMacAddress();
diff --git a/framework/java/android/net/wifi/ScanResult.java b/framework/java/android/net/wifi/ScanResult.java
index 783be1f..b483c5f 100644
--- a/framework/java/android/net/wifi/ScanResult.java
+++ b/framework/java/android/net/wifi/ScanResult.java
@@ -26,6 +26,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.modules.utils.build.SdkLevel;
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -789,7 +791,7 @@
/**
* information elements from beacon.
*/
- public static class InformationElement {
+ public static class InformationElement implements Parcelable {
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int EID_SSID = 0;
@@ -885,6 +887,57 @@
public ByteBuffer getBytes() {
return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
}
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(id);
+ dest.writeInt(idExt);
+ dest.writeByteArray(bytes);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<InformationElement> CREATOR =
+ new Creator<InformationElement>() {
+ public InformationElement createFromParcel(Parcel in) {
+ InformationElement informationElement = new InformationElement();
+ informationElement.id = in.readInt();
+ informationElement.idExt = in.readInt();
+ informationElement.bytes = in.createByteArray();
+ return informationElement;
+ }
+
+ public InformationElement[] newArray(int size) {
+ return new InformationElement[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) return true;
+
+ // Potential API behavior change, so don't change behavior on older devices.
+ if (!SdkLevel.isAtLeastS()) return false;
+
+ if (!(that instanceof InformationElement)) return false;
+
+ InformationElement thatIE = (InformationElement) that;
+ return id == thatIE.id
+ && idExt == thatIE.idExt
+ && Arrays.equals(bytes, thatIE.bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ // Potential API behavior change, so don't change behavior on older devices.
+ if (!SdkLevel.isAtLeastS()) return System.identityHashCode(this);
+
+ return Objects.hash(id, idExt, Arrays.hashCode(bytes));
+ }
}
/**
@@ -1094,18 +1147,7 @@
dest.writeString((venueName != null) ? venueName.toString() : "");
dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
dest.writeLong(this.flags);
-
- if (informationElements != null) {
- dest.writeInt(informationElements.length);
- for (int i = 0; i < informationElements.length; i++) {
- dest.writeInt(informationElements[i].id);
- dest.writeInt(informationElements[i].idExt);
- dest.writeInt(informationElements[i].bytes.length);
- dest.writeByteArray(informationElements[i].bytes);
- }
- } else {
- dest.writeInt(0);
- }
+ dest.writeTypedArray(informationElements, flags);
if (anqpLines != null) {
dest.writeInt(anqpLines.size());
@@ -1174,20 +1216,9 @@
sr.venueName = in.readString();
sr.operatorFriendlyName = in.readString();
sr.flags = in.readLong();
- int n = in.readInt();
- if (n != 0) {
- sr.informationElements = new InformationElement[n];
- for (int i = 0; i < n; i++) {
- sr.informationElements[i] = new InformationElement();
- sr.informationElements[i].id = in.readInt();
- sr.informationElements[i].idExt = in.readInt();
- int len = in.readInt();
- sr.informationElements[i].bytes = new byte[len];
- in.readByteArray(sr.informationElements[i].bytes);
- }
- }
+ sr.informationElements = in.createTypedArray(InformationElement.CREATOR);
- n = in.readInt();
+ int n = in.readInt();
if (n != 0) {
sr.anqpLines = new ArrayList<String>();
for (int i = 0; i < n; i++) {
diff --git a/framework/java/android/net/wifi/WifiInfo.java b/framework/java/android/net/wifi/WifiInfo.java
index dca2fbf..64d6d6c 100644
--- a/framework/java/android/net/wifi/WifiInfo.java
+++ b/framework/java/android/net/wifi/WifiInfo.java
@@ -42,7 +42,9 @@
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.EnumMap;
+import java.util.List;
import java.util.Locale;
import java.util.Objects;
@@ -57,6 +59,7 @@
* {@link #getNetworkId()} will return {@code -1}.
* {@link #getPasspointFqdn()} will return null.
* {@link #getPasspointProviderFriendlyName()} will return null.
+ * {@link #getInformationElements()} will return null.
*/
public class WifiInfo implements TransportInfo, Parcelable {
private static final String TAG = "WifiInfo";
@@ -340,6 +343,12 @@
*/
private String mPasspointUniqueId;
+ /**
+ * information elements found in the beacon of the connected bssid.
+ */
+ @Nullable
+ private List<ScanResult.InformationElement> mInformationElements;
+
/** @hide */
@UnsupportedAppUsage
public WifiInfo() {
@@ -385,6 +394,7 @@
setProviderFriendlyName(null);
setPasspointUniqueId(null);
setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ setInformationElements(null);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -447,6 +457,9 @@
mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed;
mMaxSupportedRxLinkSpeed = source.mMaxSupportedRxLinkSpeed;
mPasspointUniqueId = source.mPasspointUniqueId;
+ if (source.mInformationElements != null) {
+ mInformationElements = new ArrayList<>(source.mInformationElements);
+ }
}
}
@@ -1147,6 +1160,9 @@
dest.writeInt(mMaxSupportedRxLinkSpeed);
dest.writeString(mParcelLocationSenstiveFields ? mPasspointUniqueId : null);
dest.writeInt(mSubscriptionId);
+ if (SdkLevel.isAtLeastS()) {
+ dest.writeTypedList(mParcelLocationSenstiveFields ? mInformationElements : null);
+ }
}
/** Implement the Parcelable interface {@hide} */
@@ -1196,6 +1212,10 @@
info.mMaxSupportedRxLinkSpeed = in.readInt();
info.mPasspointUniqueId = in.readString();
info.mSubscriptionId = in.readInt();
+ if (SdkLevel.isAtLeastS()) {
+ info.mInformationElements = in.createTypedArrayList(
+ ScanResult.InformationElement.CREATOR);
+ }
return info;
}
@@ -1224,6 +1244,36 @@
return mPasspointUniqueId;
}
+ /**
+ * Set the information elements found in the becaon of the connected bssid.
+ * @hide
+ */
+ public void setInformationElements(@Nullable List<ScanResult.InformationElement> infoElements) {
+ if (infoElements == null) {
+ mInformationElements = null;
+ return;
+ }
+ mInformationElements = new ArrayList<>(infoElements);
+ }
+
+ /**
+ * Get all information elements found in the beacon of the connected bssid.
+ * <p>
+ * The information elements will be {@code null} if there is no network currently connected or
+ * if the caller has insufficient permissions to access the info elements.
+ * </p>
+ *
+ * @return List of information elements {@link ScanResult.InformationElement} or null.
+ */
+ @Nullable
+ public List<ScanResult.InformationElement> getInformationElements() {
+ if (!SdkLevel.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ if (mInformationElements == null) return null;
+ return new ArrayList<>(mInformationElements);
+ }
+
@Override
public boolean equals(Object that) {
if (this == that) return true;
@@ -1271,7 +1321,8 @@
&& Objects.equals(mWifiStandard, thatWifiInfo.mWifiStandard)
&& Objects.equals(mMaxSupportedTxLinkSpeed, thatWifiInfo.mMaxSupportedTxLinkSpeed)
&& Objects.equals(mMaxSupportedRxLinkSpeed, thatWifiInfo.mMaxSupportedRxLinkSpeed)
- && Objects.equals(mPasspointUniqueId, thatWifiInfo.mPasspointUniqueId);
+ && Objects.equals(mPasspointUniqueId, thatWifiInfo.mPasspointUniqueId)
+ && Objects.equals(mInformationElements, thatWifiInfo.mInformationElements);
}
@Override
@@ -1313,7 +1364,8 @@
mWifiStandard,
mMaxSupportedTxLinkSpeed,
mMaxSupportedRxLinkSpeed,
- mPasspointUniqueId);
+ mPasspointUniqueId,
+ mInformationElements);
}
/**
diff --git a/framework/tests/src/android/net/wifi/WifiInfoTest.java b/framework/tests/src/android/net/wifi/WifiInfoTest.java
index 16e6e2e..b107bd3 100644
--- a/framework/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/framework/tests/src/android/net/wifi/WifiInfoTest.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -23,18 +24,17 @@
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import android.os.Parcel;
import android.telephony.SubscriptionManager;
import androidx.test.filters.SmallTest;
-import com.android.modules.utils.build.SdkLevel;
-
import org.junit.Test;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
/**
* Unit tests for {@link android.net.wifi.WifiInfo}.
@@ -63,8 +63,6 @@
*/
@Test
public void testWifiInfoParcelWriteReadWithLocationSensitiveInfo() throws Exception {
- assumeTrue(SdkLevel.isAtLeastS());
-
WifiInfo writeWifiInfo = new WifiInfo();
writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
writeWifiInfo.txRetries = TEST_TX_RETRIES;
@@ -85,6 +83,8 @@
writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
writeWifiInfo.setSubscriptionId(TEST_SUB_ID);
+ List<ScanResult.InformationElement> informationElements = generateIes();
+ writeWifiInfo.setInformationElements(informationElements);
// Make a copy which allows parcelling of location sensitive data.
WifiInfo writeWifiInfoWithLocationSensitiveInfo = writeWifiInfo.makeCopy(true);
@@ -118,6 +118,19 @@
assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
assertEquals(TEST_SUB_ID, readWifiInfo.getSubscriptionId());
+ assertEquals(2, readWifiInfo.getInformationElements().size());
+ assertEquals(informationElements.get(0).id,
+ readWifiInfo.getInformationElements().get(0).id);
+ assertEquals(informationElements.get(0).idExt,
+ readWifiInfo.getInformationElements().get(0).idExt);
+ assertArrayEquals(informationElements.get(0).bytes,
+ readWifiInfo.getInformationElements().get(0).bytes);
+ assertEquals(informationElements.get(1).id,
+ readWifiInfo.getInformationElements().get(1).id);
+ assertEquals(informationElements.get(1).idExt,
+ readWifiInfo.getInformationElements().get(1).idExt);
+ assertArrayEquals(informationElements.get(1).bytes,
+ readWifiInfo.getInformationElements().get(1).bytes);
}
/**
@@ -125,8 +138,6 @@
*/
@Test
public void testWifiInfoParcelWriteReadWithoutLocationSensitiveInfo() throws Exception {
- assumeTrue(SdkLevel.isAtLeastS());
-
WifiInfo writeWifiInfo = new WifiInfo();
writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
writeWifiInfo.txRetries = TEST_TX_RETRIES;
@@ -147,6 +158,7 @@
writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
writeWifiInfo.setSubscriptionId(TEST_SUB_ID);
+ writeWifiInfo.setInformationElements(generateIes());
// Make a copy which allows parcelling of location sensitive data.
WifiInfo writeWifiInfoWithoutLocationSensitiveInfo = writeWifiInfo.makeCopy(false);
@@ -180,6 +192,45 @@
assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
assertEquals(TEST_SUB_ID, readWifiInfo.getSubscriptionId());
+ assertNull(readWifiInfo.getInformationElements());
+ }
+
+ /**
+ * Verify parcel write/read with WifiInfo.
+ */
+ @Test
+ public void testWifiInfoParcelWriteReadWithNullInfoElements() throws Exception {
+ WifiInfo writeWifiInfo = new WifiInfo();
+ writeWifiInfo.setInformationElements(null);
+
+ // Make a copy which allows parcelling of location sensitive data.
+ WifiInfo writeWifiInfoWithoutLocationSensitiveInfo = writeWifiInfo.makeCopy(true);
+
+ Parcel parcel = Parcel.obtain();
+ writeWifiInfoWithoutLocationSensitiveInfo.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel);
+ assertNull(readWifiInfo.getInformationElements());
+ }
+
+ /**
+ * Verify parcel write/read with WifiInfo.
+ */
+ @Test
+ public void testWifiInfoParcelWriteReadWithEmptyInfoElements() throws Exception {
+ WifiInfo writeWifiInfo = new WifiInfo();
+ writeWifiInfo.setInformationElements(new ArrayList<>());
+
+ // Make a copy which allows parcelling of location sensitive data.
+ WifiInfo writeWifiInfoWithoutLocationSensitiveInfo = writeWifiInfo.makeCopy(true);
+
+ Parcel parcel = Parcel.obtain();
+ writeWifiInfoWithoutLocationSensitiveInfo.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel);
+ assertTrue(readWifiInfo.getInformationElements().isEmpty());
}
@Test
@@ -295,33 +346,37 @@
WifiInfo info1 = builder.build();
WifiInfo info2 = builder.build();
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1, info2);
- } else {
- assertNotEquals(info1, info2);
- }
+ assertEquals(info1, info2);
info1.setSubscriptionId(TEST_SUB_ID);
- // Same behavior pre-S & post-S.
assertNotEquals(info1, info2);
info2.setSubscriptionId(TEST_SUB_ID);
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1, info2);
- } else {
- assertNotEquals(info1, info2);
- }
+ assertEquals(info1, info2);
info1.setSSID(WifiSsid.createFromHex(null));
- // Same behavior pre-S & post-S.
assertNotEquals(info1, info2);
info2.setSSID(WifiSsid.createFromHex(null));
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1, info2);
- } else {
- assertNotEquals(info1, info2);
- }
+ assertEquals(info1, info2);
+ }
+
+ @Test
+ public void testWifiInfoEqualsWithInfoElements() throws Exception {
+ WifiInfo.Builder builder = new WifiInfo.Builder()
+ .setSsid(TEST_SSID.getBytes(StandardCharsets.UTF_8))
+ .setBssid(TEST_BSSID)
+ .setRssi(TEST_RSSI)
+ .setNetworkId(TEST_NETWORK_ID);
+
+ WifiInfo info1 = builder.build();
+ WifiInfo info2 = builder.build();
+ assertEquals(info1, info2);
+
+ info1.setInformationElements(generateIes());
+ info2.setInformationElements(generateIes());
+
+ assertEquals(info1, info2);
}
@Test
@@ -334,32 +389,36 @@
WifiInfo info1 = builder.build();
WifiInfo info2 = builder.build();
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1.hashCode(), info2.hashCode());
- } else {
- assertNotEquals(info1.hashCode(), info2.hashCode());
- }
+ assertEquals(info1.hashCode(), info2.hashCode());
info1.setSubscriptionId(TEST_SUB_ID);
- // Same behavior pre-S & post-S.
assertNotEquals(info1.hashCode(), info2.hashCode());
info2.setSubscriptionId(TEST_SUB_ID);
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1.hashCode(), info2.hashCode());
- } else {
- assertNotEquals(info1.hashCode(), info2.hashCode());
- }
+ assertEquals(info1.hashCode(), info2.hashCode());
info1.setSSID(WifiSsid.createFromHex(null));
- // Same behavior pre-S & post-S.
assertNotEquals(info1.hashCode(), info2.hashCode());
info2.setSSID(WifiSsid.createFromHex(null));
- if (SdkLevel.isAtLeastS()) {
- assertEquals(info1.hashCode(), info2.hashCode());
- } else {
- assertNotEquals(info1.hashCode(), info2.hashCode());
- }
+ assertEquals(info1.hashCode(), info2.hashCode());
+ }
+
+ private static List<ScanResult.InformationElement> generateIes() {
+ List<ScanResult.InformationElement> informationElements = new ArrayList<>();
+ ScanResult.InformationElement informationElement = new ScanResult.InformationElement();
+ informationElement.id = ScanResult.InformationElement.EID_HT_OPERATION;
+ informationElement.idExt = 0;
+ informationElement.bytes = new byte[]{0x11, 0x22, 0x33};
+ informationElements.add(informationElement);
+
+ informationElement = new ScanResult.InformationElement();
+ informationElement.id = ScanResult.InformationElement.EID_EXTENSION_PRESENT;
+ informationElement.idExt = ScanResult.InformationElement.EID_EXT_HE_OPERATION;
+ informationElement.bytes = new byte[]{0x44, 0x55, 0x66};
+ informationElements.add(informationElement);
+
+ return informationElements;
+
}
}