diff options
Diffstat (limited to 'wifi/java/android')
27 files changed, 1858 insertions, 661 deletions
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index a3a1054f869e..0dd964c0ef46 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -21,6 +21,7 @@ import android.content.pm.ParceledListSlice; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; @@ -62,6 +63,8 @@ interface IWifiManager WifiConfiguration getMatchingWifiConfig(in ScanResult scanResult); + List<WifiConfiguration> getAllMatchingWifiConfigs(in ScanResult scanResult); + List<OsuProvider> getMatchingOsuProviders(in ScanResult scanResult); int addOrUpdateNetwork(in WifiConfiguration config); @@ -100,7 +103,7 @@ interface IWifiManager int getWifiEnabledState(); - void setCountryCode(String country, boolean persist); + void setCountryCode(String country); String getCountryCode(); @@ -126,8 +129,6 @@ interface IWifiManager void releaseMulticastLock(); - void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable); - void updateInterfaceIpState(String ifaceName, int mode); boolean startSoftAp(in WifiConfiguration wifiConfig); @@ -163,12 +164,6 @@ interface IWifiManager void enableAggressiveHandover(int enabled); int getAggressiveHandover(); - void setAllowScansWithTraffic(int enabled); - int getAllowScansWithTraffic(); - - boolean setEnableAutoJoinWhenAssociated(boolean enabled); - boolean getEnableAutoJoinWhenAssociated(); - void enableWifiConnectivityManager(boolean enabled); WifiConnectionStatistics getConnectionStatistics(); @@ -184,5 +179,7 @@ interface IWifiManager void restoreBackupData(in byte[] data); void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData); + + void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback); } diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index a367b2310721..3eb13ce6f8b1 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -22,7 +22,6 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; import android.text.TextUtils; -import java.lang.Math; import java.net.InetAddress; import java.net.Inet4Address; import java.net.UnknownHostException; @@ -126,143 +125,35 @@ public class WifiInfo implements Parcelable { public long rxSuccess; /** - * Average rate of lost transmitted packets, in units of packets per 5 seconds. + * Average rate of lost transmitted packets, in units of packets per second. * @hide */ public double txBadRate; /** - * Average rate of transmitted retry packets, in units of packets per 5 seconds. + * Average rate of transmitted retry packets, in units of packets per second. * @hide */ public double txRetriesRate; /** - * Average rate of successfully transmitted unicast packets, in units of packets per 5 seconds. + * Average rate of successfully transmitted unicast packets, in units of packets per second. * @hide */ public double txSuccessRate; /** - * Average rate of received unicast data packets, in units of packets per 5 seconds. + * Average rate of received unicast data packets, in units of packets per second. * @hide */ public double rxSuccessRate; - private static final long RESET_TIME_STAMP = Long.MIN_VALUE; - private static final long FILTER_TIME_CONSTANT = 3000; - /** - * This factor is used to adjust the rate output under the new algorithm - * such that the result is comparable to the previous algorithm. - * This actually converts from unit 'packets per second' to 'packets per 5 seconds'. - */ - private static final long OUTPUT_SCALE_FACTOR = 5; - private long mLastPacketCountUpdateTimeStamp; - - /** - * @hide - */ - public int badRssiCount; - - /** - * @hide - */ - public int linkStuckCount; - - /** - * @hide - */ - public int lowRssiCount; - /** * @hide */ public int score; /** - * @hide + * Flag indicating that AP has hinted that upstream connection is metered, + * and sensitive to heavy data transfers. */ - public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) { - if (stats != null) { - long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo; - long txretries = stats.retries_be + stats.retries_bk - + stats.retries_vi + stats.retries_vo; - long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo; - long txbad = stats.lostmpdu_be + stats.lostmpdu_bk - + stats.lostmpdu_vi + stats.lostmpdu_vo; - - if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP - && mLastPacketCountUpdateTimeStamp < timeStamp - && txBad <= txbad - && txSuccess <= txgood - && rxSuccess <= rxgood - && txRetries <= txretries) { - long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp; - double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT); - double currentSampleWeight = 1.0 - lastSampleWeight; - - txBadRate = txBadRate * lastSampleWeight - + (txbad - txBad) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta - * currentSampleWeight; - txSuccessRate = txSuccessRate * lastSampleWeight - + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta - * currentSampleWeight; - rxSuccessRate = rxSuccessRate * lastSampleWeight - + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta - * currentSampleWeight; - txRetriesRate = txRetriesRate * lastSampleWeight - + (txretries - txRetries) * OUTPUT_SCALE_FACTOR * 1000/ timeDelta - * currentSampleWeight; - } else { - txBadRate = 0; - txSuccessRate = 0; - rxSuccessRate = 0; - txRetriesRate = 0; - } - txBad = txbad; - txSuccess = txgood; - rxSuccess = rxgood; - txRetries = txretries; - mLastPacketCountUpdateTimeStamp = timeStamp; - } else { - txBad = 0; - txSuccess = 0; - rxSuccess = 0; - txRetries = 0; - txBadRate = 0; - txSuccessRate = 0; - rxSuccessRate = 0; - txRetriesRate = 0; - mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; - } - } - - - /** - * This function is less powerful and used if the WifiLinkLayerStats API is not implemented - * at the Wifi HAL - * @hide - */ - public void updatePacketRates(long txPackets, long rxPackets) { - //paranoia - txBad = 0; - txRetries = 0; - txBadRate = 0; - txRetriesRate = 0; - if (txSuccess <= txPackets && rxSuccess <= rxPackets) { - txSuccessRate = (txSuccessRate * 0.5) - + ((double) (txPackets - txSuccess) * 0.5); - rxSuccessRate = (rxSuccessRate * 0.5) - + ((double) (rxPackets - rxSuccess) * 0.5); - } else { - txBadRate = 0; - txRetriesRate = 0; - } - txSuccess = txPackets; - rxSuccess = rxPackets; - } - - /** - * Flag indicating that AP has hinted that upstream connection is metered, - * and sensitive to heavy data transfers. - */ private boolean mMeteredHint; /** @hide */ @@ -274,7 +165,6 @@ public class WifiInfo implements Parcelable { mRssi = INVALID_RSSI; mLinkSpeed = -1; mFrequency = -1; - mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; } /** @hide */ @@ -296,11 +186,7 @@ public class WifiInfo implements Parcelable { txSuccessRate = 0; rxSuccessRate = 0; txRetriesRate = 0; - lowRssiCount = 0; - badRssiCount = 0; - linkStuckCount = 0; score = 0; - mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP; } /** @@ -328,12 +214,7 @@ public class WifiInfo implements Parcelable { txRetriesRate = source.txRetriesRate; txSuccessRate = source.txSuccessRate; rxSuccessRate = source.rxSuccessRate; - mLastPacketCountUpdateTimeStamp = - source.mLastPacketCountUpdateTimeStamp; score = source.score; - badRssiCount = source.badRssiCount; - lowRssiCount = source.lowRssiCount; - linkStuckCount = source.linkStuckCount; } } @@ -348,6 +229,9 @@ public class WifiInfo implements Parcelable { * quotation marks. Otherwise, it is returned as a string of hex digits. The * SSID may be <unknown ssid> if there is no network currently connected, * or if the caller has insufficient permissions to access the SSID. + * + * Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method + * always returned the SSID with no quotes around it. * @return the SSID */ public String getSSID() { @@ -449,22 +333,6 @@ public class WifiInfo implements Parcelable { } /** - * @hide - * This returns txSuccessRate in packets per second. - */ - public double getTxSuccessRatePps() { - return txSuccessRate / OUTPUT_SCALE_FACTOR; - } - - /** - * @hide - * This returns rxSuccessRate in packets per second. - */ - public double getRxSuccessRatePps() { - return rxSuccessRate / OUTPUT_SCALE_FACTOR; - } - - /** * Record the MAC address of the WLAN interface * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form * @hide @@ -655,8 +523,6 @@ public class WifiInfo implements Parcelable { dest.writeDouble(txRetriesRate); dest.writeDouble(txBadRate); dest.writeDouble(rxSuccessRate); - dest.writeInt(badRssiCount); - dest.writeInt(lowRssiCount); mSupplicantState.writeToParcel(dest, flags); } @@ -686,8 +552,6 @@ public class WifiInfo implements Parcelable { info.txRetriesRate = in.readDouble(); info.txBadRate = in.readDouble(); info.rxSuccessRate = in.readDouble(); - info.badRssiCount = in.readInt(); - info.lowRssiCount = in.readInt(); info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); return info; } diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java deleted file mode 100644 index edd400b56238..000000000000 --- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2014 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.wifi; - -import android.os.Parcelable; -import android.os.Parcel; - -import java.util.Arrays; - -/** - * A class representing link layer statistics collected over a Wifi Interface. - */ -/** {@hide} */ -public class WifiLinkLayerStats implements Parcelable { - private static final String TAG = "WifiLinkLayerStats"; - - /** - * The current status of this network configuration entry. - * @see Status - */ - /** {@hide} */ - public int status; - - /** - * The network's SSID. Can either be an ASCII string, - * which must be enclosed in double quotation marks - * (e.g., {@code "MyNetwork"}, or a string of - * hex digits,which are not enclosed in quotes - * (e.g., {@code 01a243f405}). - */ - /** {@hide} */ - public String SSID; - /** - * When set. this is the BSSID the radio is currently associated with. - * The value is a string in the format of an Ethernet MAC address, e.g., - * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit. - */ - /** {@hide} */ - public String BSSID; - - /* number beacons received from our own AP */ - /** {@hide} */ - public int beacon_rx; - - /* RSSI taken on management frames */ - /** {@hide} */ - public int rssi_mgmt; - - /* packets counters */ - /** {@hide} */ - /* WME Best Effort Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries)*/ - public long rxmpdu_be; - /** {@hide} */ - public long txmpdu_be; - /** {@hide} */ - public long lostmpdu_be; - /** {@hide} */ - public long retries_be; - /** {@hide} */ - /* WME Background Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ - public long rxmpdu_bk; - /** {@hide} */ - public long txmpdu_bk; - /** {@hide} */ - public long lostmpdu_bk; - /** {@hide} */ - public long retries_bk; - /** {@hide} */ - /* WME Video Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ - public long rxmpdu_vi; - /** {@hide} */ - public long txmpdu_vi; - /** {@hide} */ - public long lostmpdu_vi; - /** {@hide} */ - public long retries_vi; - /** {@hide} */ - /* WME Voice Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ - public long rxmpdu_vo; - /** {@hide} */ - public long txmpdu_vo; - /** {@hide} */ - public long lostmpdu_vo; - /** {@hide} */ - public long retries_vo; - - /** {@hide} */ - public int on_time; - /** {@hide} */ - public int tx_time; - /** {@hide} */ - public int[] tx_time_per_level; - /** {@hide} */ - public int rx_time; - /** {@hide} */ - public int on_time_scan; - - /** {@hide} */ - public WifiLinkLayerStats() { - } - - @Override - /** {@hide} */ - public String toString() { - StringBuilder sbuf = new StringBuilder(); - sbuf.append(" WifiLinkLayerStats: ").append('\n'); - - if (this.SSID != null) { - sbuf.append(" SSID: ").append(this.SSID).append('\n'); - } - if (this.BSSID != null) { - sbuf.append(" BSSID: ").append(this.BSSID).append('\n'); - } - - sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n'); - sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n'); - sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be)) - .append(" tx=").append(Long.toString(this.txmpdu_be)) - .append(" lost=").append(Long.toString(this.lostmpdu_be)) - .append(" retries=").append(Long.toString(this.retries_be)).append('\n'); - sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk)) - .append(" tx=").append(Long.toString(this.txmpdu_bk)) - .append(" lost=").append(Long.toString(this.lostmpdu_bk)) - .append(" retries=").append(Long.toString(this.retries_bk)).append('\n'); - sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi)) - .append(" tx=").append(Long.toString(this.txmpdu_vi)) - .append(" lost=").append(Long.toString(this.lostmpdu_vi)) - .append(" retries=").append(Long.toString(this.retries_vi)).append('\n'); - sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo)) - .append(" tx=").append(Long.toString(this.txmpdu_vo)) - .append(" lost=").append(Long.toString(this.lostmpdu_vo)) - .append(" retries=").append(Long.toString(this.retries_vo)).append('\n'); - sbuf.append(" on_time : ").append(Integer.toString(this.on_time)) - .append(" rx_time=").append(Integer.toString(this.rx_time)) - .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n') - .append(" tx_time=").append(Integer.toString(this.tx_time)) - .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level)); - return sbuf.toString(); - } - - /** Implement the Parcelable interface {@hide} */ - public int describeContents() { - return 0; - } - - /** {@hide} */ - public String getPrintableSsid() { - if (SSID == null) return ""; - final int length = SSID.length(); - if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') { - return SSID.substring(1, length - 1); - } - - /** The ascii-encoded string format is P"<ascii-encoded-string>" - * The decoding is implemented in the supplicant for a newly configured - * network. - */ - if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') && - (SSID.charAt(length-1) == '"')) { - WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded( - SSID.substring(2, length - 1)); - return wifiSsid.toString(); - } - return SSID; - } - - /** Implement the Parcelable interface {@hide} */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(SSID); - dest.writeString(BSSID); - dest.writeInt(on_time); - dest.writeInt(tx_time); - dest.writeIntArray(tx_time_per_level); - dest.writeInt(rx_time); - dest.writeInt(on_time_scan); - } - - /** Implement the Parcelable interface {@hide} */ - public static final Creator<WifiLinkLayerStats> CREATOR = - new Creator<WifiLinkLayerStats>() { - public WifiLinkLayerStats createFromParcel(Parcel in) { - WifiLinkLayerStats stats = new WifiLinkLayerStats(); - stats.SSID = in.readString(); - stats.BSSID = in.readString(); - stats.on_time = in.readInt(); - stats.tx_time = in.readInt(); - stats.tx_time_per_level = in.createIntArray(); - stats.rx_time = in.readInt(); - stats.on_time_scan = in.readInt(); - return stats; - }; - public WifiLinkLayerStats[] newArray(int size) { - return new WifiLinkLayerStats[size]; - } - - }; -} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index e9e20caa7dfe..a158d94b646e 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -16,6 +16,7 @@ package android.net.wifi; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -32,6 +33,8 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; +import android.net.wifi.hotspot2.IProvisioningCallback; +import android.net.wifi.hotspot2.ProvisioningCallback; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -970,8 +973,7 @@ public class WifiManager { * <li>allowedGroupCiphers</li> * </ul> * @return a list of network configurations in the form of a list - * of {@link WifiConfiguration} objects. Upon failure to fetch or - * when Wi-Fi is turned off, it can be null. + * of {@link WifiConfiguration} objects. */ public List<WifiConfiguration> getConfiguredNetworks() { try { @@ -1033,6 +1035,26 @@ public class WifiManager { } /** + * Return all matching WifiConfigurations for this ScanResult. + * + * An empty list will be returned when no configurations are installed or if no configurations + * match the ScanResult. + * + * @param scanResult scanResult that represents the BSSID + * @return A list of {@link WifiConfiguration} + * @throws UnsupportedOperationException if Passpoint is not enabled on the device. + * @hide + */ + public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) { + try { + return mService.getAllMatchingWifiConfigs(scanResult); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + + /** * Returns a list of Hotspot 2.0 OSU (Online Sign-Up) providers associated with the given AP. * * An empty list will be returned if no match is found. @@ -1729,13 +1751,12 @@ public class WifiManager { /** * Set the country code. * @param countryCode country code in ISO 3166 format. - * @param persist {@code true} if this needs to be remembered * * @hide */ - public void setCountryCode(String country, boolean persist) { + public void setCountryCode(@NonNull String country) { try { - mService.setCountryCode(country, persist); + mService.setCountryCode(country); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1784,18 +1805,14 @@ public class WifiManager { /** * Enable or disable Wi-Fi. - * - * Note: This method will return false if wifi cannot be enabled (e.g., an incompatible mode - * where the user has enabled tethering or Airplane Mode). - * - * Applications need to have the {@link android.Manifest.permission#CHANGE_WIFI_STATE} - * permission to toggle wifi. Callers without the permissions will trigger a - * {@link java.lang.SecurityException}. + * <p> + * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE} + * permission to toggle wifi. * * @param enabled {@code true} to enable, {@code false} to disable. - * @return {@code true} if the operation succeeds (or if the existing state - * is the same as the requested state). False if wifi cannot be toggled on/off when the - * request is made. + * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is + * either already in the requested state, or in progress toward the requested state. + * @throws {@link java.lang.SecurityException} if the caller is missing required permissions. */ public boolean setWifiEnabled(boolean enabled) { try { @@ -1875,32 +1892,6 @@ public class WifiManager { } /** - * This call is deprecated and removed. It is no longer used to - * start WiFi Tethering. Please use {@link ConnectivityManager#startTethering(int, boolean, - * ConnectivityManager#OnStartTetheringCallback)} if - * the caller has proper permissions. Callers can also use the LocalOnlyHotspot feature for a - * hotspot capable of communicating with co-located devices {@link - * WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}. - * - * @param wifiConfig SSID, security and channel details as - * part of WifiConfiguration - * @return {@code false} - * - * @hide - * @deprecated This API is nolonger supported. - * @removed - */ - @SystemApi - @Deprecated - @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) - public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { - String packageName = mContext.getOpPackageName(); - - Log.w(TAG, packageName + " attempted call to setWifiApEnabled: enabled = " + enabled); - return false; - } - - /** * Call allowing ConnectivityService to update WifiService with interface mode changes. * * The possible modes include: {@link IFACE_IP_MODE_TETHERED}, @@ -3448,6 +3439,7 @@ public class WifiManager { * Set wifi verbose log. Called from developer settings. * @hide */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void enableVerboseLogging (int verbose) { try { mService.enableVerboseLogging(verbose); @@ -3496,27 +3488,23 @@ public class WifiManager { } /** - * Set setting for allowing Scans when traffic is ongoing. + * Deprecated + * Does nothing * @hide + * @deprecated */ public void setAllowScansWithTraffic(int enabled) { - try { - mService.setAllowScansWithTraffic(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return; } /** - * Get setting for allowing Scans when traffic is ongoing. + * Deprecated + * returns value for 'disabled' * @hide + * @deprecated */ public int getAllowScansWithTraffic() { - try { - return mService.getAllowScansWithTraffic(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return 0; } /** @@ -3546,29 +3534,23 @@ public class WifiManager { } /** - * Framework layer autojoin enable/disable when device is associated - * this will enable/disable autojoin scan and switch network when connected - * @return true -- if set successful false -- if set failed + * Deprecated + * returns false * @hide + * @deprecated */ public boolean setEnableAutoJoinWhenAssociated(boolean enabled) { - try { - return mService.setEnableAutoJoinWhenAssociated(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return false; } /** - * Get setting for Framework layer autojoin enable status + * Deprecated + * returns false * @hide + * @deprecated */ public boolean getEnableAutoJoinWhenAssociated() { - try { - return mService.getEnableAutoJoinWhenAssociated(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return false; } /** @@ -3620,4 +3602,45 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } + + /** + * Start subscription provisioning flow + * @param provider {@link OsuProvider} to provision with + * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow + * @hide + */ + public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback, + @Nullable Handler handler) { + Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); + try { + mService.startSubscriptionProvisioning(provider, + new ProvisioningCallbackProxy(looper, callback)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub { + private final Handler mHandler; + private final ProvisioningCallback mCallback; + + ProvisioningCallbackProxy(Looper looper, ProvisioningCallback callback) { + mHandler = new Handler(looper); + mCallback = callback; + } + + @Override + public void onProvisioningStatus(int status) { + mHandler.post(() -> { + mCallback.onProvisioningStatus(status); + }); + } + + @Override + public void onProvisioningFailure(int status) { + mHandler.post(() -> { + mCallback.onProvisioningFailure(status); + }); + } + } } diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index f47d5caf182b..e3752ac77a5e 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -1105,8 +1105,6 @@ public class WifiScanner { private static final int BASE = Protocol.BASE_WIFI_SCANNER; /** @hide */ - public static final int CMD_SCAN = BASE + 0; - /** @hide */ public static final int CMD_START_BACKGROUND_SCAN = BASE + 2; /** @hide */ public static final int CMD_STOP_BACKGROUND_SCAN = BASE + 3; @@ -1115,20 +1113,10 @@ public class WifiScanner { /** @hide */ public static final int CMD_SCAN_RESULT = BASE + 5; /** @hide */ - public static final int CMD_AP_FOUND = BASE + 9; - /** @hide */ - public static final int CMD_AP_LOST = BASE + 10; - /** @hide */ - public static final int CMD_WIFI_CHANGE_DETECTED = BASE + 15; - /** @hide */ - public static final int CMD_WIFI_CHANGES_STABILIZED = BASE + 16; - /** @hide */ public static final int CMD_OP_SUCCEEDED = BASE + 17; /** @hide */ public static final int CMD_OP_FAILED = BASE + 18; /** @hide */ - public static final int CMD_PERIOD_CHANGED = BASE + 19; - /** @hide */ public static final int CMD_FULL_SCAN_RESULT = BASE + 20; /** @hide */ public static final int CMD_START_SINGLE_SCAN = BASE + 21; @@ -1359,25 +1347,6 @@ public class WifiScanner { ScanResult result = (ScanResult) msg.obj; ((ScanListener) listener).onFullResult(result); return; - case CMD_PERIOD_CHANGED: - ((ScanListener) listener).onPeriodChanged(msg.arg1); - return; - case CMD_AP_FOUND: - ((BssidListener) listener).onFound( - ((ParcelableScanResults) msg.obj).getResults()); - return; - case CMD_AP_LOST: - ((BssidListener) listener).onLost( - ((ParcelableScanResults) msg.obj).getResults()); - return; - case CMD_WIFI_CHANGE_DETECTED: - ((WifiChangeListener) listener).onChanging( - ((ParcelableScanResults) msg.obj).getResults()); - return; - case CMD_WIFI_CHANGES_STABILIZED: - ((WifiChangeListener) listener).onQuiescence( - ((ParcelableScanResults) msg.obj).getResults()); - return; case CMD_SINGLE_SCAN_COMPLETED: if (DBG) Log.d(TAG, "removing listener for single scan"); removeListener(msg.arg2); diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java index 357f76e37d28..9f7362234ad8 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.NetworkSpecifier; -import android.net.wifi.RttManager; import android.util.Log; import dalvik.system.CloseGuard; @@ -224,37 +223,6 @@ public class DiscoverySession implements AutoCloseable { } /** - * Start a ranging operation with the specified peers. The peer IDs are obtained from an - * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, - * byte[], java.util.List)} or - * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, - * byte[])} operation - can - * only range devices which are part of an ongoing discovery session. - * - * @param params RTT parameters - each corresponding to a specific peer ID (the array sizes - * must be identical). The - * {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to - * a peer ID - not to a MAC address. - * @param listener The listener to receive the results of the ranging session. - * @hide - * [TODO: b/28847998 - track RTT API & visilibity] - */ - public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) { - if (mTerminated) { - Log.w(TAG, "startRanging: called on terminated session"); - return; - } - - WifiAwareManager mgr = mMgr.get(); - if (mgr == null) { - Log.w(TAG, "startRanging: called post GC on WifiAwareManager"); - return; - } - - mgr.startRanging(mClientId, mSessionId, params, listener); - } - - /** * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for * an unencrypted WiFi Aware connection (link) to the specified peer. The * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java index 115b86d156e5..aa2c268cab88 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java @@ -113,6 +113,32 @@ public class DiscoverySessionCallback { } /** + * Called when a discovery (publish or subscribe) operation results in a + * service discovery. Called when a Subscribe service was configured with a range requirement + * {@link SubscribeConfig.Builder#setMinDistanceMm(int)} and/or + * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)}. A discovery will only be declared + * (i.e. this callback called) if the range of the publisher is within the specified distance + * constraints. + * + * @param peerHandle An opaque handle to the peer matching our discovery operation. + * @param serviceSpecificInfo The service specific information (arbitrary + * byte array) provided by the peer as part of its discovery + * configuration. + * @param matchFilter The filter which resulted in this service discovery. For + * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}, + * {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE} discovery sessions this is the publisher's + * match filter. For {@link PublishConfig#PUBLISH_TYPE_SOLICITED}, + * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} discovery sessions this + * is the subscriber's match filter. + * @param distanceMm The measured distance to the Publisher in mm. + * @hide + */ + public void onServiceDiscoveredWithinRange(PeerHandle peerHandle, + byte[] serviceSpecificInfo, List<byte[]> matchFilter, int distanceMm) { + /* empty */ + } + + /** * Called in response to * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} * when a message is transmitted successfully - i.e. when it was received successfully by the diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl index 8ff38425d5e0..421a8af2073e 100644 --- a/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl +++ b/wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl @@ -29,6 +29,8 @@ oneway interface IWifiAwareDiscoverySessionCallback void onSessionTerminated(int reason); void onMatch(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter); + void onMatchWithDistance(int peerId, in byte[] serviceSpecificInfo, in byte[] matchFilter, + int distanceMm); void onMessageSendSuccess(int messageId); void onMessageSendFail(int messageId, int reason); diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl index 30dd64dd28f4..b646567512ac 100644 --- a/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl +++ b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl @@ -17,7 +17,6 @@ package android.net.wifi.aware; import android.net.wifi.aware.ConfigRequest; -import android.net.wifi.RttManager; /** * Callback interface that WifiAwareManager implements @@ -29,8 +28,4 @@ oneway interface IWifiAwareEventCallback void onConnectSuccess(int clientId); void onConnectFail(int reason); void onIdentityChanged(in byte[] mac); - - void onRangingSuccess(int rangingId, in RttManager.ParcelableRttResults results); - void onRangingFailure(int rangingId, int reason, in String description); - void onRangingAborted(int rangingId); } diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl new file mode 100644 index 000000000000..0e7289cd9c46 --- /dev/null +++ b/wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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.wifi.aware; + +/** + * Callback for IWifiAwareManager.getMacAddressFromPeerHandle + * + * @hide + */ +oneway interface IWifiAwareMacAddressProvider +{ + void macAddress(in Map peerIdToMacMap); +} diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl index 0f4910f0c29f..bad5ce226efc 100644 --- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl +++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl @@ -21,10 +21,10 @@ import android.app.PendingIntent; import android.net.wifi.aware.ConfigRequest; import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback; import android.net.wifi.aware.IWifiAwareEventCallback; +import android.net.wifi.aware.IWifiAwareMacAddressProvider; import android.net.wifi.aware.PublishConfig; import android.net.wifi.aware.SubscribeConfig; import android.net.wifi.aware.Characteristics; -import android.net.wifi.RttManager; /** * Interface that WifiAwareService implements @@ -53,5 +53,7 @@ interface IWifiAwareManager void sendMessage(int clientId, int discoverySessionId, int peerId, in byte[] message, int messageId, int retryCount); void terminateSession(int clientId, int discoverySessionId); - int startRanging(int clientId, int discoverySessionId, in RttManager.ParcelableRttParams parms); + + // internal APIs: intended to be used between System Services (restricted permissions) + void requestMacAddresses(int uid, in List peerIds, in IWifiAwareMacAddressProvider callback); } diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java index d018620719e2..e60f52f88f9e 100644 --- a/wifi/java/android/net/wifi/aware/PublishConfig.java +++ b/wifi/java/android/net/wifi/aware/PublishConfig.java @@ -29,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * Defines the configuration of a Aware publish session. Built using @@ -81,14 +82,19 @@ public final class PublishConfig implements Parcelable { public final boolean mEnableTerminateNotification; /** @hide */ + public final boolean mEnableRanging; + + /** @hide */ public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, - int publishType, int ttlSec, boolean enableTerminateNotification) { + int publishType, int ttlSec, boolean enableTerminateNotification, + boolean enableRanging) { mServiceName = serviceName; mServiceSpecificInfo = serviceSpecificInfo; mMatchFilter = matchFilter; mPublishType = publishType; mTtlSec = ttlSec; mEnableTerminateNotification = enableTerminateNotification; + mEnableRanging = enableRanging; } @Override @@ -103,7 +109,8 @@ public final class PublishConfig implements Parcelable { + (new TlvBufferUtils.TlvIterable(0, 1, mMatchFilter)).toString() + ", mMatchFilter.length=" + (mMatchFilter == null ? 0 : mMatchFilter.length) + ", mPublishType=" + mPublishType + ", mTtlSec=" + mTtlSec - + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]"; + + ", mEnableTerminateNotification=" + mEnableTerminateNotification + + ", mEnableRanging=" + mEnableRanging + "]"; } @Override @@ -119,6 +126,7 @@ public final class PublishConfig implements Parcelable { dest.writeInt(mPublishType); dest.writeInt(mTtlSec); dest.writeInt(mEnableTerminateNotification ? 1 : 0); + dest.writeInt(mEnableRanging ? 1 : 0); } public static final Creator<PublishConfig> CREATOR = new Creator<PublishConfig>() { @@ -135,9 +143,10 @@ public final class PublishConfig implements Parcelable { int publishType = in.readInt(); int ttlSec = in.readInt(); boolean enableTerminateNotification = in.readInt() != 0; + boolean enableRanging = in.readInt() != 0; return new PublishConfig(serviceName, ssi, matchFilter, publishType, - ttlSec, enableTerminateNotification); + ttlSec, enableTerminateNotification, enableRanging); } }; @@ -157,21 +166,14 @@ public final class PublishConfig implements Parcelable { lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter) && mPublishType == lhs.mPublishType && mTtlSec == lhs.mTtlSec - && mEnableTerminateNotification == lhs.mEnableTerminateNotification; + && mEnableTerminateNotification == lhs.mEnableTerminateNotification + && mEnableRanging == lhs.mEnableRanging; } @Override public int hashCode() { - int result = 17; - - result = 31 * result + Arrays.hashCode(mServiceName); - result = 31 * result + Arrays.hashCode(mServiceSpecificInfo); - result = 31 * result + Arrays.hashCode(mMatchFilter); - result = 31 * result + mPublishType; - result = 31 * result + mTtlSec; - result = 31 * result + (mEnableTerminateNotification ? 1 : 0); - - return result; + return Objects.hash(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType, mTtlSec, + mEnableTerminateNotification, mEnableRanging); } /** @@ -226,6 +228,7 @@ public final class PublishConfig implements Parcelable { private int mPublishType = PUBLISH_TYPE_UNSOLICITED; private int mTtlSec = 0; private boolean mEnableTerminateNotification = true; + private boolean mEnableRanging = false; /** * Specify the service name of the publish session. The actual on-air @@ -352,12 +355,35 @@ public final class PublishConfig implements Parcelable { } /** + * Configure whether the publish discovery session supports ranging and allows peers to + * measure distance to it. This API is used in conjunction with + * {@link SubscribeConfig.Builder#setMinDistanceMm(int)} and + * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)} to specify a minimum and/or + * maximum distance at which discovery will be triggered. + * <p> + * Optional. Disabled by default - i.e. any peer which attempts to measure distance to this + * device will be refused. If the peer has ranging enabled (using the + * {@link SubscribeConfig} APIs listed above, it will never discover this device. + * + * @param enable If true, ranging is supported on request of the peer. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + * + * @hide + */ + public Builder setRangingEnabled(boolean enable) { + mEnableRanging = enable; + return this; + } + + /** * Build {@link PublishConfig} given the current requests made on the * builder. */ public PublishConfig build() { return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType, - mTtlSec, mEnableTerminateNotification); + mTtlSec, mEnableTerminateNotification, mEnableRanging); } } } diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 4bf2fb6aa6fe..f6552a767f4f 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -29,6 +29,7 @@ import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * Defines the configuration of a Aware subscribe session. Built using @@ -79,15 +80,32 @@ public final class SubscribeConfig implements Parcelable { public final boolean mEnableTerminateNotification; /** @hide */ + public final boolean mMinDistanceMmSet; + + /** @hide */ + public final int mMinDistanceMm; + + /** @hide */ + public final boolean mMaxDistanceMmSet; + + /** @hide */ + public final int mMaxDistanceMm; + + /** @hide */ public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, - int subscribeType, int ttlSec, - boolean enableTerminateNotification) { + int subscribeType, int ttlSec, boolean enableTerminateNotification, + boolean minDistanceMmSet, int minDistanceMm, boolean maxDistanceMmSet, + int maxDistanceMm) { mServiceName = serviceName; mServiceSpecificInfo = serviceSpecificInfo; mMatchFilter = matchFilter; mSubscribeType = subscribeType; mTtlSec = ttlSec; mEnableTerminateNotification = enableTerminateNotification; + mMinDistanceMm = minDistanceMm; + mMinDistanceMmSet = minDistanceMmSet; + mMaxDistanceMm = maxDistanceMm; + mMaxDistanceMmSet = maxDistanceMmSet; } @Override @@ -102,7 +120,11 @@ public final class SubscribeConfig implements Parcelable { + (new TlvBufferUtils.TlvIterable(0, 1, mMatchFilter)).toString() + ", mMatchFilter.length=" + (mMatchFilter == null ? 0 : mMatchFilter.length) + ", mSubscribeType=" + mSubscribeType + ", mTtlSec=" + mTtlSec - + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]"; + + ", mEnableTerminateNotification=" + mEnableTerminateNotification + + ", mMinDistanceMm=" + mMinDistanceMm + + ", mMinDistanceMmSet=" + mMinDistanceMmSet + + ", mMaxDistanceMm=" + mMaxDistanceMm + + ", mMaxDistanceMmSet=" + mMaxDistanceMmSet + "]"; } @Override @@ -118,6 +140,10 @@ public final class SubscribeConfig implements Parcelable { dest.writeInt(mSubscribeType); dest.writeInt(mTtlSec); dest.writeInt(mEnableTerminateNotification ? 1 : 0); + dest.writeInt(mMinDistanceMm); + dest.writeInt(mMinDistanceMmSet ? 1 : 0); + dest.writeInt(mMaxDistanceMm); + dest.writeInt(mMaxDistanceMmSet ? 1 : 0); } public static final Creator<SubscribeConfig> CREATOR = new Creator<SubscribeConfig>() { @@ -134,9 +160,14 @@ public final class SubscribeConfig implements Parcelable { int subscribeType = in.readInt(); int ttlSec = in.readInt(); boolean enableTerminateNotification = in.readInt() != 0; - - return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, - ttlSec, enableTerminateNotification); + int minDistanceMm = in.readInt(); + boolean minDistanceMmSet = in.readInt() != 0; + int maxDistanceMm = in.readInt(); + boolean maxDistanceMmSet = in.readInt() != 0; + + return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType, ttlSec, + enableTerminateNotification, minDistanceMmSet, minDistanceMm, maxDistanceMmSet, + maxDistanceMm); } }; @@ -152,23 +183,37 @@ public final class SubscribeConfig implements Parcelable { SubscribeConfig lhs = (SubscribeConfig) o; - return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo, - lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter) - && mSubscribeType == lhs.mSubscribeType - && mTtlSec == lhs.mTtlSec - && mEnableTerminateNotification == lhs.mEnableTerminateNotification; + if (!(Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals( + mServiceSpecificInfo, lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, + lhs.mMatchFilter) && mSubscribeType == lhs.mSubscribeType && mTtlSec == lhs.mTtlSec + && mEnableTerminateNotification == lhs.mEnableTerminateNotification + && mMinDistanceMmSet == lhs.mMinDistanceMmSet + && mMaxDistanceMmSet == lhs.mMaxDistanceMmSet)) { + return false; + } + + if (mMinDistanceMmSet && mMinDistanceMm != lhs.mMinDistanceMm) { + return false; + } + + if (mMaxDistanceMmSet && mMaxDistanceMm != lhs.mMaxDistanceMm) { + return false; + } + + return true; } @Override public int hashCode() { - int result = 17; + int result = Objects.hash(mServiceName, mServiceSpecificInfo, mMatchFilter, mSubscribeType, + mTtlSec, mEnableTerminateNotification, mMinDistanceMmSet, mMaxDistanceMmSet); - result = 31 * result + Arrays.hashCode(mServiceName); - result = 31 * result + Arrays.hashCode(mServiceSpecificInfo); - result = 31 * result + Arrays.hashCode(mMatchFilter); - result = 31 * result + mSubscribeType; - result = 31 * result + mTtlSec; - result = 31 * result + (mEnableTerminateNotification ? 1 : 0); + if (mMinDistanceMmSet) { + result = Objects.hash(result, mMinDistanceMm); + } + if (mMaxDistanceMmSet) { + result = Objects.hash(result, mMaxDistanceMm); + } return result; } @@ -213,6 +258,17 @@ public final class SubscribeConfig implements Parcelable { "Match filter longer than supported by device characteristics"); } } + + if (mMinDistanceMmSet && mMinDistanceMm < 0) { + throw new IllegalArgumentException("Minimum distance must be non-negative"); + } + if (mMaxDistanceMmSet && mMaxDistanceMm < 0) { + throw new IllegalArgumentException("Maximum distance must be non-negative"); + } + if (mMinDistanceMmSet && mMaxDistanceMmSet && mMaxDistanceMm <= mMinDistanceMm) { + throw new IllegalArgumentException( + "Maximum distance must be greater than minimum distance"); + } } /** @@ -225,6 +281,10 @@ public final class SubscribeConfig implements Parcelable { private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE; private int mTtlSec = 0; private boolean mEnableTerminateNotification = true; + private boolean mMinDistanceMmSet = false; + private int mMinDistanceMm; + private boolean mMaxDistanceMmSet = false; + private int mMaxDistanceMm; /** * Specify the service name of the subscribe session. The actual on-air @@ -350,13 +410,69 @@ public final class SubscribeConfig implements Parcelable { } /** + * Configure the minimum distance to a discovered publisher at which to trigger a discovery + * notification. I.e. discovery will only be triggered if we've found a matching publisher + * (based on the other criteria in this configuration) <b>and</b> the distance to the + * publisher is > the value specified in this API. + * <p> + * Can be used in conjunction with {@link #setMaxDistanceMm(int)} to specify a geo-fence, + * i.e. discovery with min < distance < max. + * <p> + * If this API is called, the subscriber requires ranging. In such a case, the publisher + * peer must enable ranging using + * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will + * never be triggered. + * + * @param minDistanceMm Minimum distance, in mm, to the publisher above which to trigger + * discovery. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + * + * @hide + */ + public Builder setMinDistanceMm(int minDistanceMm) { + mMinDistanceMm = minDistanceMm; + mMinDistanceMmSet = true; + return this; + } + + /** + * Configure the maximum distance to a discovered publisher at which to trigger a discovery + * notification. I.e. discovery will only be triggered if we've found a matching publisher + * (based on the other criteria in this configuration) <b>and</b> the distance to the + * publisher is < the value specified in this API. + * <p> + * Can be used in conjunction with {@link #setMinDistanceMm(int)} to specify a geo-fence, + * i.e. discovery with min < distance < max. + * <p> + * If this API is called, the subscriber requires ranging. In such a case, the publisher + * peer must enable ranging using + * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will + * never be triggered. + * + * @param maxDistanceMm Maximum distance, in mm, to the publisher below which to trigger + * discovery. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + * + * @hide + */ + public Builder setMaxDistanceMm(int maxDistanceMm) { + mMaxDistanceMm = maxDistanceMm; + mMaxDistanceMmSet = true; + return this; + } + + /** * Build {@link SubscribeConfig} given the current requests made on the * builder. */ public SubscribeConfig build() { return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, - mSubscribeType, mTtlSec, - mEnableTerminateNotification); + mSubscribeType, mTtlSec, mEnableTerminateNotification, + mMinDistanceMmSet, mMinDistanceMm, mMaxDistanceMmSet, mMaxDistanceMm); } } } diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index df0d9d23fe14..166da48ed90a 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -20,13 +20,12 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; -import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemService; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.wifi.RttManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -35,9 +34,6 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.GuardedBy; import libcore.util.HexEncoding; @@ -45,7 +41,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.BufferOverflowException; -import java.util.Arrays; import java.util.List; /** @@ -172,9 +167,6 @@ public class WifiAwareManager { private final Object mLock = new Object(); // lock access to the following vars - @GuardedBy("mLock") - private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>(); - /** @hide */ public WifiAwareManager(Context context, IWifiAwareManager service) { mContext = context; @@ -401,27 +393,6 @@ public class WifiAwareManager { } /** @hide */ - public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params, - RttManager.RttListener listener) { - if (VDBG) { - Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", " - + "params=" + Arrays.toString(params) + ", listener=" + listener); - } - - int rangingKey = 0; - try { - rangingKey = mService.startRanging(clientId, sessionId, - new RttManager.ParcelableRttParams(params)); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - synchronized (mLock) { - mRangingListeners.put(rangingKey, listener); - } - } - - /** @hide */ public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId, PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { @@ -500,29 +471,12 @@ public class WifiAwareManager { private static final int CALLBACK_CONNECT_SUCCESS = 0; private static final int CALLBACK_CONNECT_FAIL = 1; private static final int CALLBACK_IDENTITY_CHANGED = 2; - private static final int CALLBACK_RANGING_SUCCESS = 3; - private static final int CALLBACK_RANGING_FAILURE = 4; - private static final int CALLBACK_RANGING_ABORTED = 5; private final Handler mHandler; private final WeakReference<WifiAwareManager> mAwareManager; private final Binder mBinder; private final Looper mLooper; - RttManager.RttListener getAndRemoveRangingListener(int rangingId) { - WifiAwareManager mgr = mAwareManager.get(); - if (mgr == null) { - Log.w(TAG, "getAndRemoveRangingListener: called post GC"); - return null; - } - - synchronized (mgr.mLock) { - RttManager.RttListener listener = mgr.mRangingListeners.get(rangingId); - mgr.mRangingListeners.delete(rangingId); - return listener; - } - } - /** * Constructs a {@link AttachCallback} using the specified looper. * All callbacks will delivered on the thread of the specified looper. @@ -567,37 +521,6 @@ public class WifiAwareManager { identityChangedListener.onIdentityChanged((byte[]) msg.obj); } break; - case CALLBACK_RANGING_SUCCESS: { - RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); - if (listener == null) { - Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 - + ": no listener registered (anymore)"); - } else { - listener.onSuccess( - ((RttManager.ParcelableRttResults) msg.obj).mResults); - } - break; - } - case CALLBACK_RANGING_FAILURE: { - RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); - if (listener == null) { - Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 - + ": no listener registered (anymore)"); - } else { - listener.onFailure(msg.arg2, (String) msg.obj); - } - break; - } - case CALLBACK_RANGING_ABORTED: { - RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1); - if (listener == null) { - Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1 - + ": no listener registered (anymore)"); - } else { - listener.onAborted(); - } - break; - } } } }; @@ -629,43 +552,6 @@ public class WifiAwareManager { msg.obj = mac; mHandler.sendMessage(msg); } - - @Override - public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) { - if (VDBG) { - Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results); - } - - Message msg = mHandler.obtainMessage(CALLBACK_RANGING_SUCCESS); - msg.arg1 = rangingId; - msg.obj = results; - mHandler.sendMessage(msg); - } - - @Override - public void onRangingFailure(int rangingId, int reason, String description) { - if (VDBG) { - Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", reason=" + reason - + ", description=" + description); - } - - Message msg = mHandler.obtainMessage(CALLBACK_RANGING_FAILURE); - msg.arg1 = rangingId; - msg.arg2 = reason; - msg.obj = description; - mHandler.sendMessage(msg); - - } - - @Override - public void onRangingAborted(int rangingId) { - if (VDBG) Log.v(TAG, "onRangingAborted: rangingId=" + rangingId); - - Message msg = mHandler.obtainMessage(CALLBACK_RANGING_ABORTED); - msg.arg1 = rangingId; - mHandler.sendMessage(msg); - - } } private static class WifiAwareDiscoverySessionCallbackProxy extends @@ -678,6 +564,7 @@ public class WifiAwareManager { private static final int CALLBACK_MESSAGE_SEND_SUCCESS = 5; private static final int CALLBACK_MESSAGE_SEND_FAIL = 6; private static final int CALLBACK_MESSAGE_RECEIVED = 7; + private static final int CALLBACK_MATCH_WITH_DISTANCE = 8; private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; @@ -732,7 +619,9 @@ public class WifiAwareManager { case CALLBACK_SESSION_TERMINATED: onProxySessionTerminated(msg.arg1); break; - case CALLBACK_MATCH: { + case CALLBACK_MATCH: + case CALLBACK_MATCH_WITH_DISTANCE: + { List<byte[]> matchFilter = null; byte[] arg = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2); try { @@ -743,9 +632,16 @@ public class WifiAwareManager { + new String(HexEncoding.encode(arg)) + "' - cannot be parsed: e=" + e); } - mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1), - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), - matchFilter); + if (msg.what == CALLBACK_MATCH) { + mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1), + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + matchFilter); + } else { + mOriginalCallback.onServiceDiscoveredWithinRange( + new PeerHandle(msg.arg1), + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + matchFilter, msg.arg2); + } break; } case CALLBACK_MESSAGE_SEND_SUCCESS: @@ -798,21 +694,38 @@ public class WifiAwareManager { mHandler.sendMessage(msg); } - @Override - public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter) { - if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); - + private void onMatchCommon(int messageType, int peerId, byte[] serviceSpecificInfo, + byte[] matchFilter, int distanceMm) { Bundle data = new Bundle(); data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); - Message msg = mHandler.obtainMessage(CALLBACK_MATCH); + Message msg = mHandler.obtainMessage(messageType); msg.arg1 = peerId; + msg.arg2 = distanceMm; msg.setData(data); mHandler.sendMessage(msg); } @Override + public void onMatch(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter) { + if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); + + onMatchCommon(CALLBACK_MATCH, peerId, serviceSpecificInfo, matchFilter, 0); + } + + @Override + public void onMatchWithDistance(int peerId, byte[] serviceSpecificInfo, byte[] matchFilter, + int distanceMm) { + if (VDBG) { + Log.v(TAG, "onMatchWithDistance: peerId=" + peerId + ", distanceMm=" + distanceMm); + } + + onMatchCommon(CALLBACK_MATCH_WITH_DISTANCE, peerId, serviceSpecificInfo, matchFilter, + distanceMm); + } + + @Override public void onMessageSendSuccess(int messageId) { if (VDBG) Log.v(TAG, "onMessageSendSuccess"); diff --git a/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl new file mode 100644 index 000000000000..c2cb16ab847c --- /dev/null +++ b/wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 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.wifi.hotspot2; + +/** + * Interface for Provisioning callback. + * + * @hide + */ +oneway interface IProvisioningCallback +{ + /** + * Service to manager callback providing failure notification + */ + void onProvisioningFailure(int status); + + /** + * Service to manager callback providing Provisioning status + */ + void onProvisioningStatus(int status); +} + diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java new file mode 100644 index 000000000000..8b86cdde4a9e --- /dev/null +++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 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.wifi.hotspot2; + +import android.os.Handler; + +/** + * Base class for provisioning callbacks. Should be extended by applications and set when calling + * {@link WifiManager#startSubscriptionProvisiong(OsuProvider, ProvisioningCallback, Handler)}. + * + * @hide + */ +public abstract class ProvisioningCallback { + + /** + * The reason code for Provisioning Failure due to connection failure to OSU AP. + * @hide + */ + public static final int OSU_FAILURE_AP_CONNECTION = 1; + + /** + * The status code for Provisioning flow to indicate connecting to OSU AP + * @hide + */ + public static final int OSU_STATUS_AP_CONNECTING = 1; + + /** + * The status code for Provisioning flow to indicate connected to OSU AP + * @hide + */ + public static final int OSU_STATUS_AP_CONNECTED = 2; + + /** + * Provisioning status for OSU failure + * @param status indicates error condition + */ + public abstract void onProvisioningFailure(int status); + + /** + * Provisioning status when OSU is in progress + * @param status indicates status of OSU flow + */ + public abstract void onProvisioningStatus(int status); +} + diff --git a/wifi/java/android/net/wifi/rtt/IRttCallback.aidl b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl new file mode 100644 index 000000000000..578dd1e94997 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/IRttCallback.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.net.wifi.rtt.RangingResult; + +/** + * Interface for RTT result callback. + * + * @hide + */ +oneway interface IRttCallback +{ + /** + * Service to manager callback indicating failure. + */ + void onRangingFailure(int status); + + /** + * Service to manager callback indicating success and providing results. + */ + void onRangingResults(in List<RangingResult> results); +} diff --git a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl new file mode 100644 index 000000000000..3e37af06ab27 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.os.WorkSource; + +import android.net.wifi.rtt.IRttCallback; +import android.net.wifi.rtt.RangingRequest; + +/** + * @hide + */ +interface IWifiRttManager +{ + boolean isAvailable(); + void startRanging(in IBinder binder, in String callingPackage, in WorkSource workSource, + in RangingRequest request, in IRttCallback callback); + void cancelRanging(in WorkSource workSource); +} diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.aidl b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl new file mode 100644 index 000000000000..8053c9416aeb --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +parcelable RangingRequest; diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java new file mode 100644 index 000000000000..b4e3097a56a7 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.annotation.NonNull; +import android.net.MacAddress; +import android.net.wifi.ScanResult; +import android.net.wifi.aware.AttachCallback; +import android.net.wifi.aware.DiscoverySessionCallback; +import android.net.wifi.aware.IdentityChangedListener; +import android.net.wifi.aware.PeerHandle; +import android.net.wifi.aware.WifiAwareManager; +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; + +/** + * Defines the ranging request to other devices. The ranging request is built using + * {@link RangingRequest.Builder}. + * A ranging request is executed using + * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. + * <p> + * The ranging request is a batch request - specifying a set of devices (specified using + * {@link RangingRequest.Builder#addAccessPoint(ScanResult)} and + * {@link RangingRequest.Builder#addAccessPoints(List)}). + * + * @hide RTT_API + */ +public final class RangingRequest implements Parcelable { + private static final int MAX_PEERS = 10; + + /** + * Returns the maximum number of peers to range which can be specified in a single {@code + * RangingRequest}. The limit applies no matter how the peers are added to the request, e.g. + * through {@link RangingRequest.Builder#addAccessPoint(ScanResult)} or + * {@link RangingRequest.Builder#addAccessPoints(List)}. + * + * @return Maximum number of peers. + */ + public static int getMaxPeers() { + return MAX_PEERS; + } + + /** @hide */ + public final List<ResponderConfig> mRttPeers; + + /** @hide */ + private RangingRequest(List<ResponderConfig> rttPeers) { + mRttPeers = rttPeers; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeList(mRttPeers); + } + + public static final Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() { + @Override + public RangingRequest[] newArray(int size) { + return new RangingRequest[size]; + } + + @Override + public RangingRequest createFromParcel(Parcel in) { + return new RangingRequest(in.readArrayList(null)); + } + }; + + /** @hide */ + @Override + public String toString() { + StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", "]"); + for (ResponderConfig rc : mRttPeers) { + sj.add(rc.toString()); + } + return sj.toString(); + } + + /** @hide */ + public void enforceValidity(boolean awareSupported) { + if (mRttPeers.size() > MAX_PEERS) { + throw new IllegalArgumentException( + "Ranging to too many peers requested. Use getMaxPeers() API to get limit."); + } + + for (ResponderConfig peer: mRttPeers) { + if (!peer.isValid(awareSupported)) { + throw new IllegalArgumentException("Invalid Responder specification"); + } + } + } + + /** + * Builder class used to construct {@link RangingRequest} objects. + */ + public static final class Builder { + private List<ResponderConfig> mRttPeers = new ArrayList<>(); + + /** + * Add the device specified by the {@link ScanResult} to the list of devices with + * which to measure range. The total number of peers added to a request cannot exceed the + * limit specified by {@link #getMaxPeers()}. + * + * @param apInfo Information of an Access Point (AP) obtained in a Scan Result. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder addAccessPoint(@NonNull ScanResult apInfo) { + if (apInfo == null) { + throw new IllegalArgumentException("Null ScanResult!"); + } + return addResponder(ResponderConfig.fromScanResult(apInfo)); + } + + /** + * Add the devices specified by the {@link ScanResult}s to the list of devices with + * which to measure range. The total number of peers added to a request cannot exceed the + * limit specified by {@link #getMaxPeers()}. + * + * @param apInfos Information of an Access Points (APs) obtained in a Scan Result. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder addAccessPoints(@NonNull List<ScanResult> apInfos) { + if (apInfos == null) { + throw new IllegalArgumentException("Null list of ScanResults!"); + } + for (ScanResult scanResult : apInfos) { + addAccessPoint(scanResult); + } + return this; + } + + /** + * Add the device specified by the {@code peerMacAddress} to the list of devices with + * which to measure range. + * + * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi + * Aware device may obtain its MAC address using the {@link IdentityChangedListener} + * provided to + * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}. + * + * * Note: in order to use this API the device must support Wi-Fi Aware + * {@link android.net.wifi.aware}. + * + * @param peerMacAddress The MAC address of the Wi-Fi Aware peer. + * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder addWifiAwarePeer(@NonNull MacAddress peerMacAddress) { + if (peerMacAddress == null) { + throw new IllegalArgumentException("Null peer MAC address"); + } + return addResponder( + ResponderConfig.fromWifiAwarePeerMacAddressWithDefaults(peerMacAddress)); + } + + /** + * Add a device specified by a {@link PeerHandle} to the list of devices with which to + * measure range. + * + * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g. + * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}. + * + * Note: in order to use this API the device must support Wi-Fi Aware + * {@link android.net.wifi.aware}. + * + * @param peerHandle The peer handler of the peer Wi-Fi Aware device. + * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder addWifiAwarePeer(@NonNull PeerHandle peerHandle) { + if (peerHandle == null) { + throw new IllegalArgumentException("Null peer handler (identifier)"); + } + + return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle)); + } + + /* + * Add the Responder device specified by the {@link ResponderConfig} to the list of devices + * with which to measure range. The total number of peers added to the request cannot exceed + * the limit specified by {@link #getMaxPeers()}. + * + * @param responder Information on the RTT Responder. + * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. + * + * @hide (SystemApi) + */ + public Builder addResponder(@NonNull ResponderConfig responder) { + if (responder == null) { + throw new IllegalArgumentException("Null Responder!"); + } + + mRttPeers.add(responder); + return this; + } + + /** + * Build {@link RangingRequest} given the current configurations made on the + * builder. + */ + public RangingRequest build() { + return new RangingRequest(mRttPeers); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof RangingRequest)) { + return false; + } + + RangingRequest lhs = (RangingRequest) o; + + return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers); + } + + @Override + public int hashCode() { + return mRttPeers.hashCode(); + } +} diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.aidl b/wifi/java/android/net/wifi/rtt/RangingResult.aidl new file mode 100644 index 000000000000..ae295a610afa --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingResult.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +parcelable RangingResult; diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java new file mode 100644 index 000000000000..a380fae7141a --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingResult.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.net.MacAddress; +import android.net.wifi.aware.PeerHandle; +import android.os.Handler; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Objects; + +/** + * Ranging result for a request started by + * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. Results are + * returned in {@link RangingResultCallback#onRangingResults(List)}. + * <p> + * A ranging result is the distance measurement result for a single device specified in the + * {@link RangingRequest}. + * + * @hide RTT_API + */ +public final class RangingResult implements Parcelable { + private static final String TAG = "RangingResult"; + + /** @hide */ + @IntDef({STATUS_SUCCESS, STATUS_FAIL}) + @Retention(RetentionPolicy.SOURCE) + public @interface RangeResultStatus { + } + + /** + * Individual range request status, {@link #getStatus()}. Indicates ranging operation was + * successful and distance value is valid. + */ + public static final int STATUS_SUCCESS = 0; + + /** + * Individual range request status, {@link #getStatus()}. Indicates ranging operation failed + * and the distance value is invalid. + */ + public static final int STATUS_FAIL = 1; + + private final int mStatus; + private final MacAddress mMac; + private final PeerHandle mPeerHandle; + private final int mDistanceMm; + private final int mDistanceStdDevMm; + private final int mRssi; + private final long mTimestamp; + + /** @hide */ + public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm, + int distanceStdDevMm, int rssi, long timestamp) { + mStatus = status; + mMac = mac; + mPeerHandle = null; + mDistanceMm = distanceMm; + mDistanceStdDevMm = distanceStdDevMm; + mRssi = rssi; + mTimestamp = timestamp; + } + + /** @hide */ + public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm, + int distanceStdDevMm, int rssi, long timestamp) { + mStatus = status; + mMac = null; + mPeerHandle = peerHandle; + mDistanceMm = distanceMm; + mDistanceStdDevMm = distanceStdDevMm; + mRssi = rssi; + mTimestamp = timestamp; + } + + /** + * @return The status of ranging measurement: {@link #STATUS_SUCCESS} in case of success, and + * {@link #STATUS_FAIL} in case of failure. + */ + @RangeResultStatus + public int getStatus() { + return mStatus; + } + + /** + * @return The MAC address of the device whose range measurement was requested. Will correspond + * to the MAC address of the device in the {@link RangingRequest}. + * <p> + * Will return a {@code null} for results corresponding to requests issued using a {@code + * PeerHandle}, i.e. using the {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)} API. + */ + public MacAddress getMacAddress() { + return mMac; + } + + /** + * @return The PeerHandle of the device whose reange measurement was requested. Will correspond + * to the PeerHandle of the devices requested using + * {@link RangingRequest.Builder#addWifiAwarePeer(PeerHandle)}. + * <p> + * Will return a {@code null} for results corresponding to requests issued using a MAC address. + */ + public PeerHandle getPeerHandle() { + return mPeerHandle; + } + + /** + * @return The distance (in mm) to the device specified by {@link #getMacAddress()} or + * {@link #getPeerHandle()}. + * <p> + * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an + * exception. + */ + public int getDistanceMm() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getDistanceMm(): invoked on an invalid result: getStatus()=" + mStatus); + } + return mDistanceMm; + } + + /** + * @return The standard deviation of the measured distance (in mm) to the device specified by + * {@link #getMacAddress()} or {@link #getPeerHandle()}. The standard deviation is calculated + * over the measurements executed in a single RTT burst. + * <p> + * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an + * exception. + */ + public int getDistanceStdDevMm() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getDistanceStdDevMm(): invoked on an invalid result: getStatus()=" + mStatus); + } + return mDistanceStdDevMm; + } + + /** + * @return The average RSSI (in units of -0.5dB) observed during the RTT measurement. + * <p> + * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an + * exception. + */ + public int getRssi() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getRssi(): invoked on an invalid result: getStatus()=" + mStatus); + } + return mRssi; + } + + /** + * @return The timestamp, in us since boot, at which the ranging operation was performed. + * <p> + * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an + * exception. + */ + public long getRangingTimestampUs() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getRangingTimestamp(): invoked on an invalid result: getStatus()=" + mStatus); + } + return mTimestamp; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mStatus); + if (mMac == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + mMac.writeToParcel(dest, flags); + } + if (mPeerHandle == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + dest.writeInt(mPeerHandle.peerId); + } + dest.writeInt(mDistanceMm); + dest.writeInt(mDistanceStdDevMm); + dest.writeInt(mRssi); + dest.writeLong(mTimestamp); + } + + /** @hide */ + public static final Creator<RangingResult> CREATOR = new Creator<RangingResult>() { + @Override + public RangingResult[] newArray(int size) { + return new RangingResult[size]; + } + + @Override + public RangingResult createFromParcel(Parcel in) { + int status = in.readInt(); + boolean macAddressPresent = in.readBoolean(); + MacAddress mac = null; + if (macAddressPresent) { + mac = MacAddress.CREATOR.createFromParcel(in); + } + boolean peerHandlePresent = in.readBoolean(); + PeerHandle peerHandle = null; + if (peerHandlePresent) { + peerHandle = new PeerHandle(in.readInt()); + } + int distanceMm = in.readInt(); + int distanceStdDevMm = in.readInt(); + int rssi = in.readInt(); + long timestamp = in.readLong(); + if (peerHandlePresent) { + return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi, + timestamp); + } else { + return new RangingResult(status, mac, distanceMm, distanceStdDevMm, rssi, + timestamp); + } + } + }; + + /** @hide */ + @Override + public String toString() { + return new StringBuilder("RangingResult: [status=").append(mStatus).append(", mac=").append( + mMac).append(", peerHandle=").append( + mPeerHandle == null ? "<null>" : mPeerHandle.peerId).append(", distanceMm=").append( + mDistanceMm).append(", distanceStdDevMm=").append(mDistanceStdDevMm).append( + ", rssi=").append(mRssi).append(", timestamp=").append(mTimestamp).append( + "]").toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof RangingResult)) { + return false; + } + + RangingResult lhs = (RangingResult) o; + + return mStatus == lhs.mStatus && Objects.equals(mMac, lhs.mMac) && Objects.equals( + mPeerHandle, lhs.mPeerHandle) && mDistanceMm == lhs.mDistanceMm + && mDistanceStdDevMm == lhs.mDistanceStdDevMm && mRssi == lhs.mRssi + && mTimestamp == lhs.mTimestamp; + } + + @Override + public int hashCode() { + return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi, + mTimestamp); + } +} diff --git a/wifi/java/android/net/wifi/rtt/RangingResultCallback.java b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java new file mode 100644 index 000000000000..c8aea3c4aa62 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.annotation.IntDef; +import android.os.Handler; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +/** + * Base class for ranging result callbacks. Should be extended by applications and set when calling + * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)}. If the + * ranging operation fails in whole (not attempted) then {@link #onRangingFailure(int)} will be + * called with a failure code. If the ranging operation is performed for each of the requested + * peers then the {@link #onRangingResults(List)} will be called with the set of results (@link + * {@link RangingResult}, each of which has its own success/failure code + * {@link RangingResult#getStatus()}. + * + * @hide RTT_API + */ +public abstract class RangingResultCallback { + /** @hide */ + @IntDef({STATUS_CODE_FAIL, STATUS_CODE_FAIL_RTT_NOT_AVAILABLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface RangingOperationStatus { + } + + /** + * A failure code for the whole ranging request operation. Indicates a failure. + */ + public static final int STATUS_CODE_FAIL = 1; + + /** + * A failure code for the whole ranging request operation. Indicates that the request failed due + * to RTT not being available - e.g. Wi-Fi was disabled. Use the + * {@link WifiRttManager#isAvailable()} and {@link WifiRttManager#ACTION_WIFI_RTT_STATE_CHANGED} + * to track RTT availability. + */ + public static final int STATUS_CODE_FAIL_RTT_NOT_AVAILABLE = 2; + + /** + * Called when a ranging operation failed in whole - i.e. no ranging operation to any of the + * devices specified in the request was attempted. + * + * @param code A status code indicating the type of failure. + */ + public abstract void onRangingFailure(@RangingOperationStatus int code); + + /** + * Called when a ranging operation was executed. The list of results corresponds to devices + * specified in the ranging request. + * + * @param results List of range measurements, one per requested device. + */ + public abstract void onRangingResults(List<RangingResult> results); +} diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl new file mode 100644 index 000000000000..fd3988aca06c --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +parcelable ResponderConfig; diff --git a/wifi/java/android/net/wifi/rtt/ResponderConfig.java b/wifi/java/android/net/wifi/rtt/ResponderConfig.java new file mode 100644 index 000000000000..8be7782d5664 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2017 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.wifi.rtt; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.net.MacAddress; +import android.net.wifi.ScanResult; +import android.net.wifi.aware.PeerHandle; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Defines the configuration of an IEEE 802.11mc Responder. The Responder may be an Access Point + * (AP), a Wi-Fi Aware device, or a manually configured Responder. + * <p> + * A Responder configuration may be constructed from a {@link ScanResult} or manually (with the + * data obtained out-of-band from a peer). + * + * @hide (@SystemApi) + */ +public class ResponderConfig implements Parcelable { + private static final int AWARE_BAND_2_DISCOVERY_CHANNEL = 2437; + + /** @hide */ + @IntDef({RESPONDER_AP, RESPONDER_STA, RESPONDER_P2P_GO, RESPONDER_P2P_CLIENT, RESPONDER_AWARE}) + @Retention(RetentionPolicy.SOURCE) + public @interface ResponderType { + } + + /** + * Responder is an AP. + */ + public static final int RESPONDER_AP = 0; + /** + * Responder is a STA. + */ + public static final int RESPONDER_STA = 1; + /** + * Responder is a Wi-Fi Direct Group Owner (GO). + */ + public static final int RESPONDER_P2P_GO = 2; + /** + * Responder is a Wi-Fi Direct Group Client. + */ + public static final int RESPONDER_P2P_CLIENT = 3; + /** + * Responder is a Wi-Fi Aware device. + */ + public static final int RESPONDER_AWARE = 4; + + + /** @hide */ + @IntDef({ + CHANNEL_WIDTH_20MHZ, CHANNEL_WIDTH_40MHZ, CHANNEL_WIDTH_80MHZ, CHANNEL_WIDTH_160MHZ, + CHANNEL_WIDTH_80MHZ_PLUS_MHZ}) + @Retention(RetentionPolicy.SOURCE) + public @interface ChannelWidth { + } + + /** + * Channel bandwidth is 20 MHZ + */ + public static final int CHANNEL_WIDTH_20MHZ = 0; + /** + * Channel bandwidth is 40 MHZ + */ + public static final int CHANNEL_WIDTH_40MHZ = 1; + /** + * Channel bandwidth is 80 MHZ + */ + public static final int CHANNEL_WIDTH_80MHZ = 2; + /** + * Channel bandwidth is 160 MHZ + */ + public static final int CHANNEL_WIDTH_160MHZ = 3; + /** + * Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ + */ + public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; + + /** @hide */ + @IntDef({PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT}) + @Retention(RetentionPolicy.SOURCE) + public @interface PreambleType { + } + + /** + * Preamble type: Legacy. + */ + public static final int PREAMBLE_LEGACY = 0; + + /** + * Preamble type: HT. + */ + public static final int PREAMBLE_HT = 1; + + /** + * Preamble type: VHT. + */ + public static final int PREAMBLE_VHT = 2; + + + /** + * The MAC address of the Responder. Will be null if a Wi-Fi Aware peer identifier (the + * peerHandle field) ise used to identify the Responder. + * TODO: convert to MacAddress + */ + public MacAddress macAddress; + + /** + * The peer identifier of a Wi-Fi Aware Responder. Will be null if a MAC Address (the macAddress + * field) is used to identify the Responder. + */ + public PeerHandle peerHandle; + + /** + * The device type of the Responder. + */ + public final int responderType; + + /** + * Indicates whether the Responder device supports IEEE 802.11mc. + */ + public final boolean supports80211mc; + + /** + * Responder channel bandwidth, specified using {@link ChannelWidth}. + */ + public final int channelWidth; + + /** + * The primary 20 MHz frequency (in MHz) of the channel of the Responder. + */ + public final int frequency; + + /** + * Not used if the {@link #channelWidth} is 20 MHz. If the Responder uses 40, 80 or 160 MHz, + * this is the center frequency (in MHz), if the Responder uses 80 + 80 MHz, this is the + * center frequency of the first segment (in MHz). + */ + public final int centerFreq0; + + /** + * Only used if the {@link #channelWidth} is 80 + 80 MHz. If the Responder uses 80 + 80 MHz, + * this is the center frequency of the second segment (in MHz). + */ + public final int centerFreq1; + + /** + * The preamble used by the Responder, specified using {@link PreambleType}. + */ + public final int preamble; + + /** + * Constructs Responder configuration. + * + * @param macAddress The MAC address of the Responder. + * @param responderType The type of the responder device, specified using + * {@link ResponderType}. + * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. + * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. + * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. + * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses + * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the + * Responder uses 80 + 80 MHz, this is the center frequency of the first + * segment (in MHz). + * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the + * Responder + * uses 80 + 80 MHz, this is the center frequency of the second segment + * (in + * MHz). + * @param preamble The preamble used by the Responder, specified using + * {@link PreambleType}. + */ + public ResponderConfig(@NonNull MacAddress macAddress, @ResponderType int responderType, + boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, + int centerFreq1, @PreambleType int preamble) { + if (macAddress == null) { + throw new IllegalArgumentException( + "Invalid ResponderConfig - must specify a MAC address"); + } + this.macAddress = macAddress; + this.peerHandle = null; + this.responderType = responderType; + this.supports80211mc = supports80211mc; + this.channelWidth = channelWidth; + this.frequency = frequency; + this.centerFreq0 = centerFreq0; + this.centerFreq1 = centerFreq1; + this.preamble = preamble; + } + + /** + * Constructs Responder configuration. + * + * @param peerHandle The Wi-Fi Aware peer identifier of the Responder. + * @param responderType The type of the responder device, specified using + * {@link ResponderType}. + * @param supports80211mc Indicates whether the responder supports IEEE 802.11mc. + * @param channelWidth Responder channel bandwidth, specified using {@link ChannelWidth}. + * @param frequency The primary 20 MHz frequency (in MHz) of the channel of the Responder. + * @param centerFreq0 Not used if the {@code channelWidth} is 20 MHz. If the Responder uses + * 40, 80 or 160 MHz, this is the center frequency (in MHz), if the + * Responder uses 80 + 80 MHz, this is the center frequency of the first + * segment (in MHz). + * @param centerFreq1 Only used if the {@code channelWidth} is 80 + 80 MHz. If the + * Responder + * uses 80 + 80 MHz, this is the center frequency of the second segment + * (in + * MHz). + * @param preamble The preamble used by the Responder, specified using + * {@link PreambleType}. + */ + public ResponderConfig(@NonNull PeerHandle peerHandle, @ResponderType int responderType, + boolean supports80211mc, @ChannelWidth int channelWidth, int frequency, int centerFreq0, + int centerFreq1, @PreambleType int preamble) { + this.macAddress = null; + this.peerHandle = peerHandle; + this.responderType = responderType; + this.supports80211mc = supports80211mc; + this.channelWidth = channelWidth; + this.frequency = frequency; + this.centerFreq0 = centerFreq0; + this.centerFreq1 = centerFreq1; + this.preamble = preamble; + } + + /** + * Creates a Responder configuration from a {@link ScanResult} corresponding to an Access + * Point (AP), which can be obtained from {@link android.net.wifi.WifiManager#getScanResults()}. + */ + public static ResponderConfig fromScanResult(ScanResult scanResult) { + MacAddress macAddress = MacAddress.fromString(scanResult.BSSID); + int responderType = RESPONDER_AP; + boolean supports80211mc = scanResult.is80211mcResponder(); + int channelWidth = translcateScanResultChannelWidth(scanResult.channelWidth); + int frequency = scanResult.frequency; + int centerFreq0 = scanResult.centerFreq0; + int centerFreq1 = scanResult.centerFreq1; + + // TODO: b/68936111 - extract preamble info from IE + int preamble; + if (channelWidth == CHANNEL_WIDTH_80MHZ || channelWidth == CHANNEL_WIDTH_160MHZ) { + preamble = PREAMBLE_VHT; + } else { + preamble = PREAMBLE_HT; + } + + return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, + frequency, centerFreq0, centerFreq1, preamble); + } + + /** + * Creates a Responder configuration from a MAC address corresponding to a Wi-Fi Aware + * Responder. The Responder parameters are set to defaults. + */ + public static ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(MacAddress macAddress) { + /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder + * is expected to be brought up and available to negotiate a maximum accuracy channel + * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware + * Unsolicited Publisher with Ranging enabled. + */ + return new ResponderConfig(macAddress, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, + AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); + } + + /** + * Creates a Responder configuration from a {@link PeerHandle} corresponding to a Wi-Fi Aware + * Responder. The Responder parameters are set to defaults. + */ + public static ResponderConfig fromWifiAwarePeerHandleWithDefaults(PeerHandle peerHandle) { + /* Note: the parameters are those of the Aware discovery channel (channel 6). A Responder + * is expected to be brought up and available to negotiate a maximum accuracy channel + * (i.e. Band 5 @ 80MHz). A Responder is brought up on the peer by starting an Aware + * Unsolicited Publisher with Ranging enabled. + */ + return new ResponderConfig(peerHandle, RESPONDER_AWARE, true, CHANNEL_WIDTH_20MHZ, + AWARE_BAND_2_DISCOVERY_CHANNEL, 0, 0, PREAMBLE_HT); + } + + /** + * Check whether the Responder configuration is valid. + * + * @return true if valid, false otherwise. + * @hide + */ + public boolean isValid(boolean awareSupported) { + if (macAddress == null && peerHandle == null || macAddress != null && peerHandle != null) { + return false; + } + if (!awareSupported && responderType == RESPONDER_AWARE) { + return false; + } + + return true; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (macAddress == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + macAddress.writeToParcel(dest, flags); + } + if (peerHandle == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + dest.writeInt(peerHandle.peerId); + } + dest.writeInt(responderType); + dest.writeInt(supports80211mc ? 1 : 0); + dest.writeInt(channelWidth); + dest.writeInt(frequency); + dest.writeInt(centerFreq0); + dest.writeInt(centerFreq1); + dest.writeInt(preamble); + } + + public static final Creator<ResponderConfig> CREATOR = new Creator<ResponderConfig>() { + @Override + public ResponderConfig[] newArray(int size) { + return new ResponderConfig[size]; + } + + @Override + public ResponderConfig createFromParcel(Parcel in) { + boolean macAddressPresent = in.readBoolean(); + MacAddress macAddress = null; + if (macAddressPresent) { + macAddress = MacAddress.CREATOR.createFromParcel(in); + } + boolean peerHandlePresent = in.readBoolean(); + PeerHandle peerHandle = null; + if (peerHandlePresent) { + peerHandle = new PeerHandle(in.readInt()); + } + int responderType = in.readInt(); + boolean supports80211mc = in.readInt() == 1; + int channelWidth = in.readInt(); + int frequency = in.readInt(); + int centerFreq0 = in.readInt(); + int centerFreq1 = in.readInt(); + int preamble = in.readInt(); + + if (peerHandle == null) { + return new ResponderConfig(macAddress, responderType, supports80211mc, channelWidth, + frequency, centerFreq0, centerFreq1, preamble); + } else { + return new ResponderConfig(peerHandle, responderType, supports80211mc, channelWidth, + frequency, centerFreq0, centerFreq1, preamble); + } + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof ResponderConfig)) { + return false; + } + + ResponderConfig lhs = (ResponderConfig) o; + + return Objects.equals(macAddress, lhs.macAddress) && Objects.equals(peerHandle, + lhs.peerHandle) && responderType == lhs.responderType + && supports80211mc == lhs.supports80211mc && channelWidth == lhs.channelWidth + && frequency == lhs.frequency && centerFreq0 == lhs.centerFreq0 + && centerFreq1 == lhs.centerFreq1 && preamble == lhs.preamble; + } + + @Override + public int hashCode() { + return Objects.hash(macAddress, peerHandle, responderType, supports80211mc, channelWidth, + frequency, centerFreq0, centerFreq1, preamble); + } + + /** @hide */ + @Override + public String toString() { + return new StringBuffer("ResponderConfig: macAddress=").append(macAddress).append( + ", peerHandle=").append(peerHandle == null ? "<null>" : peerHandle.peerId).append( + ", responderType=").append(responderType).append(", supports80211mc=").append( + supports80211mc).append(", channelWidth=").append(channelWidth).append( + ", frequency=").append(frequency).append(", centerFreq0=").append( + centerFreq0).append(", centerFreq1=").append(centerFreq1).append( + ", preamble=").append(preamble).toString(); + } + + /** @hide */ + static int translcateScanResultChannelWidth(int scanResultChannelWidth) { + switch (scanResultChannelWidth) { + case ScanResult.CHANNEL_WIDTH_20MHZ: + return CHANNEL_WIDTH_20MHZ; + case ScanResult.CHANNEL_WIDTH_40MHZ: + return CHANNEL_WIDTH_40MHZ; + case ScanResult.CHANNEL_WIDTH_80MHZ: + return CHANNEL_WIDTH_80MHZ; + case ScanResult.CHANNEL_WIDTH_160MHZ: + return CHANNEL_WIDTH_160MHZ; + case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ: + return CHANNEL_WIDTH_80MHZ_PLUS_MHZ; + default: + throw new IllegalArgumentException( + "translcateScanResultChannelWidth: bad " + scanResultChannelWidth); + } + } +} diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java new file mode 100644 index 000000000000..b4c690f4840d --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java @@ -0,0 +1,182 @@ +package android.net.wifi.rtt; + +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_WIFI_STATE; +import static android.Manifest.permission.CHANGE_WIFI_STATE; +import static android.Manifest.permission.LOCATION_HARDWARE; + +import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.Binder; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.WorkSource; +import android.util.Log; + +import java.util.List; + +/** + * This class provides the primary API for measuring distance (range) to other devices using the + * IEEE 802.11mc Wi-Fi Round Trip Time (RTT) technology. + * <p> + * The devices which can be ranged include: + * <li>Access Points (APs) + * <li>Wi-Fi Aware peers + * <p> + * Ranging requests are triggered using + * {@link #startRanging(RangingRequest, RangingResultCallback, Handler)}. Results (in case of + * successful operation) are returned in the {@link RangingResultCallback#onRangingResults(List)} + * callback. + * <p> + * Wi-Fi RTT may not be usable at some points, e.g. when Wi-Fi is disabled. To validate that + * the functionality is available use the {@link #isAvailable()} function. To track + * changes in RTT usability register for the {@link #ACTION_WIFI_RTT_STATE_CHANGED} + * broadcast. Note that this broadcast is not sticky - you should register for it and then + * check the above API to avoid a race condition. + * + * @hide RTT_API + */ +@SystemService(Context.WIFI_RTT_RANGING_SERVICE) +public class WifiRttManager { + private static final String TAG = "WifiRttManager"; + private static final boolean VDBG = false; + + private final Context mContext; + private final IWifiRttManager mService; + + /** + * Broadcast intent action to indicate that the state of Wi-Fi RTT availability has changed. + * Use the {@link #isAvailable()} to query the current status. + * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering + * the broadcast to check the current state of Wi-Fi RTT. + * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered + * components will be launched. + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_WIFI_RTT_STATE_CHANGED = + "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED"; + + /** @hide */ + public WifiRttManager(Context context, IWifiRttManager service) { + mContext = context; + mService = service; + } + + /** + * Returns the current status of RTT API: whether or not RTT is available. To track + * changes in the state of RTT API register for the + * {@link #ACTION_WIFI_RTT_STATE_CHANGED} broadcast. + * + * @return A boolean indicating whether the app can use the RTT API at this time (true) or + * not (false). + */ + public boolean isAvailable() { + try { + return mService.isAvailable(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Initiate a request to range to a set of devices specified in the {@link RangingRequest}. + * Results will be returned in the {@link RangingResultCallback} set of callbacks. + * + * @param request A request specifying a set of devices whose distance measurements are + * requested. + * @param callback A callback for the result of the ranging request. + * @param handler The Handler on whose thread to execute the callbacks of the {@code + * callback} object. If a null is provided then the application's main thread + * will be used. + */ + @RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE}) + public void startRanging(RangingRequest request, RangingResultCallback callback, + @Nullable Handler handler) { + startRanging(null, request, callback, handler); + } + + /** + * Initiate a request to range to a set of devices specified in the {@link RangingRequest}. + * Results will be returned in the {@link RangingResultCallback} set of callbacks. + * + * @param workSource A mechanism to specify an alternative work-source for the request. + * @param request A request specifying a set of devices whose distance measurements are + * requested. + * @param callback A callback for the result of the ranging request. + * @param handler The Handler on whose thread to execute the callbacks of the {@code + * callback} object. If a null is provided then the application's main thread + * will be used. + * + * @hide (@SystemApi) + */ + @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_COARSE_LOCATION, CHANGE_WIFI_STATE, + ACCESS_WIFI_STATE}) + public void startRanging(@Nullable WorkSource workSource, RangingRequest request, + RangingResultCallback callback, @Nullable Handler handler) { + if (VDBG) { + Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request + + ", callback=" + callback + ", handler=" + handler); + } + + Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); + Binder binder = new Binder(); + try { + mService.startRanging(binder, mContext.getOpPackageName(), workSource, request, + new RttCallbackProxy(looper, callback)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Cancel all ranging requests for the specified work sources. The requests have been requested + * using {@link #startRanging(WorkSource, RangingRequest, RangingResultCallback, Handler)}. + * + * @param workSource The work-sources of the requesters. + * + * @hide (@SystemApi) + */ + @RequiresPermission(allOf = {LOCATION_HARDWARE}) + public void cancelRanging(WorkSource workSource) { + if (VDBG) { + Log.v(TAG, "cancelRanging: workSource=" + workSource); + } + + try { + mService.cancelRanging(workSource); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static class RttCallbackProxy extends IRttCallback.Stub { + private final Handler mHandler; + private final RangingResultCallback mCallback; + + RttCallbackProxy(Looper looper, RangingResultCallback callback) { + mHandler = new Handler(looper); + mCallback = callback; + } + + @Override + public void onRangingFailure(int status) throws RemoteException { + if (VDBG) Log.v(TAG, "RttCallbackProxy: onRangingFailure: status=" + status); + mHandler.post(() -> { + mCallback.onRangingFailure(status); + }); + } + + @Override + public void onRangingResults(List<RangingResult> results) throws RemoteException { + if (VDBG) Log.v(TAG, "RttCallbackProxy: onRanginResults: results=" + results); + mHandler.post(() -> { + mCallback.onRangingResults(results); + }); + } + } +} diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html new file mode 100644 index 000000000000..a0d407a927a2 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/package.html @@ -0,0 +1,39 @@ +<HTML> +<BODY> +<p>Provides classes which allow applications to use Wi-Fi RTT (IEEE 802.11mc) to measure distance + to supporting Access Points and peer devices.</p> +<p>The primary entry point to Wi-Fi RTT capabilities is the + {@link android.net.wifi.rtt.WifiRttManager} class, which is acquired by calling + {@link android.content.Context#getSystemService(String) + Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE)}</p> + +<p>Some APIs may require the following user permissions:</p> +<ul> + <li>{@link android.Manifest.permission#ACCESS_WIFI_STATE}</li> + <li>{@link android.Manifest.permission#CHANGE_WIFI_STATE}</li> + <li>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</li> +</ul> + +<p class="note"><strong>Note:</strong> Not all Android-powered devices support Wi-Fi RTT + functionality. + If your application only works with Wi-Fi RTT (i.e. it should only be installed on devices which + support Wi-Fi RTT), declare so with a <a + href="{@docRoot}guide/topics/manifest/uses-feature-element.html"> + {@code <uses-feature>}</a> + element in the manifest file:</p> +<pre> +<manifest ...> + <uses-feature android:name="android.hardware.wifi.rtt" /> + ... +</manifest> +</pre> +<p>Alternatively, if your application does not require Wi-Fi RTT but can take advantage of it if + available, you can perform + the check at run-time in your code using {@link + android.content.pm.PackageManager#hasSystemFeature(String)} with {@link + android.content.pm.PackageManager#FEATURE_WIFI_RTT}:</p> +<pre> + getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT) +</pre> +</BODY> +</HTML> |