diff options
Diffstat (limited to 'wifi/java')
36 files changed, 3138 insertions, 1497 deletions
diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl new file mode 100644 index 000000000000..b8d2971e74bb --- /dev/null +++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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; + +/** + * Interface for Soft AP callback. + * + * @hide + */ +oneway interface ISoftApCallback +{ + /** + * Service to manager callback providing current soft AP state. The possible + * parameter values listed are defined in WifiManager.java + * + * @param state new AP state. One of WIFI_AP_STATE_DISABLED, + * WIFI_AP_STATE_DISABLING, WIFI_AP_STATE_ENABLED, + * WIFI_AP_STATE_ENABLING, WIFI_AP_STATE_FAILED + * @param failureReason reason when in failed state. One of + * SAP_START_FAILURE_GENERAL, SAP_START_FAILURE_NO_CHANNEL + */ + void onStateChanged(int state, int failureReason); + + /** + * Service to manager callback providing number of connected clients. + * + * @param numClients number of connected clients + */ + void onNumClientsChanged(int numClients); +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index a3a1054f869e..309bc80b8864 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -21,17 +21,17 @@ 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; -import android.net.wifi.ScanSettings; -import android.net.wifi.ScanResult; +import android.net.DhcpInfo; +import android.net.Network; +import android.net.wifi.ISoftApCallback; import android.net.wifi.PasspointManagementObjectDefinition; -import android.net.wifi.WifiConnectionStatistics; +import android.net.wifi.ScanResult; +import android.net.wifi.ScanSettings; import android.net.wifi.WifiActivityEnergyInfo; -import android.net.Network; - -import android.net.DhcpInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; import android.os.Messenger; import android.os.ResultReceiver; @@ -62,13 +62,15 @@ interface IWifiManager WifiConfiguration getMatchingWifiConfig(in ScanResult scanResult); + List<WifiConfiguration> getAllMatchingWifiConfigs(in ScanResult scanResult); + List<OsuProvider> getMatchingOsuProviders(in ScanResult scanResult); - int addOrUpdateNetwork(in WifiConfiguration config); + int addOrUpdateNetwork(in WifiConfiguration config, String packageName); - boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config); + boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config, String packageName); - boolean removePasspointConfiguration(in String fqdn); + boolean removePasspointConfiguration(in String fqdn, String packageName); List<PasspointConfiguration> getPasspointConfigurations(); @@ -78,21 +80,21 @@ interface IWifiManager void deauthenticateNetwork(long holdoff, boolean ess); - boolean removeNetwork(int netId); + boolean removeNetwork(int netId, String packageName); - boolean enableNetwork(int netId, boolean disableOthers); + boolean enableNetwork(int netId, boolean disableOthers, String packageName); - boolean disableNetwork(int netId); + boolean disableNetwork(int netId, String packageName); - void startScan(in ScanSettings requested, in WorkSource ws, in String packageName); + void startScan(in ScanSettings requested, in WorkSource ws, String packageName); List<ScanResult> getScanResults(String callingPackage); - void disconnect(); + void disconnect(String packageName); - void reconnect(); + void reconnect(String packageName); - void reassociate(); + void reassociate(String packageName); WifiInfo getConnectionInfo(String callingPackage); @@ -100,14 +102,12 @@ interface IWifiManager int getWifiEnabledState(); - void setCountryCode(String country, boolean persist); + void setCountryCode(String country); String getCountryCode(); boolean isDualBandSupported(); - boolean saveConfiguration(); - DhcpInfo getDhcpInfo(); boolean isScanAlwaysAvailable(); @@ -126,15 +126,13 @@ interface IWifiManager void releaseMulticastLock(); - void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable); - void updateInterfaceIpState(String ifaceName, int mode); boolean startSoftAp(in WifiConfiguration wifiConfig); boolean stopSoftAp(); - int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, in String packageName); + int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName); void stopLocalOnlyHotspot(); @@ -146,9 +144,9 @@ interface IWifiManager WifiConfiguration getWifiApConfiguration(); - void setWifiApConfiguration(in WifiConfiguration wifiConfig); + void setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName); - Messenger getWifiServiceMessenger(); + Messenger getWifiServiceMessenger(String packageName); void enableTdls(String remoteIPAddress, boolean enable); @@ -160,22 +158,11 @@ interface IWifiManager int getVerboseLoggingLevel(); - void enableAggressiveHandover(int enabled); - int getAggressiveHandover(); - - void setAllowScansWithTraffic(int enabled); - int getAllowScansWithTraffic(); - - boolean setEnableAutoJoinWhenAssociated(boolean enabled); - boolean getEnableAutoJoinWhenAssociated(); - void enableWifiConnectivityManager(boolean enabled); - WifiConnectionStatistics getConnectionStatistics(); - - void disableEphemeralNetwork(String SSID); + void disableEphemeralNetwork(String SSID, String packageName); - void factoryReset(); + void factoryReset(String packageName); Network getCurrentNetwork(); @@ -184,5 +171,11 @@ interface IWifiManager void restoreBackupData(in byte[] data); void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData); + + void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback); + + void registerSoftApCallback(in IBinder binder, in ISoftApCallback callback, int callbackIdentifier); + + void unregisterSoftApCallback(int callbackIdentifier); } diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 12a8ddf9fcdc..bdbc149a0a42 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -7,24 +7,24 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; -import android.os.Binder; -import android.os.Bundle; +import android.content.pm.PackageManager; +import android.net.wifi.rtt.RangingRequest; +import android.net.wifi.rtt.RangingResult; +import android.net.wifi.rtt.RangingResultCallback; +import android.net.wifi.rtt.WifiRttManager; import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; import android.os.Parcel; import android.os.Parcelable; -import android.os.RemoteException; import android.util.Log; -import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.util.List; + /** @hide */ @SystemApi +@Deprecated @SystemService(Context.WIFI_RTT_SERVICE) public class RttManager { @@ -175,12 +175,14 @@ public class RttManager { @Deprecated @SuppressLint("Doclava125") public Capabilities getCapabilities() { - return new Capabilities(); + throw new UnsupportedOperationException( + "getCapabilities is not supported in the adaptation layer"); } /** * This class describe the RTT capability of the Hardware */ + @Deprecated public static class RttCapabilities implements Parcelable { /** @deprecated It is not supported*/ @Deprecated @@ -314,21 +316,16 @@ public class RttManager { }; } + /** + * This method is deprecated. Please use the {@link WifiRttManager} API. + */ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) public RttCapabilities getRttCapabilities() { - synchronized (mCapabilitiesLock) { - if (mRttCapabilities == null) { - try { - mRttCapabilities = mService.getRttCapabilities(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - return mRttCapabilities; - } + return mRttCapabilities; } /** specifies parameters for RTT request */ + @Deprecated public static class RttParams { /** * type of destination device being ranged @@ -511,6 +508,7 @@ public class RttManager { } /** pseudo-private class used to parcel arguments */ + @Deprecated public static class ParcelableRttParams implements Parcelable { @NonNull @@ -598,12 +596,14 @@ public class RttManager { }; } + @Deprecated public static class WifiInformationElement { /** Information Element ID 0xFF means element is invalid. */ public byte id; public byte[] data; } /** specifies RTT results */ + @Deprecated public static class RttResult { /** mac address of the device being ranged. */ public String bssid; @@ -755,6 +755,7 @@ public class RttManager { /** pseudo-private class used to parcel results. */ + @Deprecated public static class ParcelableRttResults implements Parcelable { public RttResult mResults[]; @@ -920,7 +921,7 @@ public class RttManager { }; } - + @Deprecated public static interface RttListener { public void onSuccess(RttResult[] results); public void onFailure(int reason, String description); @@ -928,141 +929,88 @@ public class RttManager { } /** - * A parcelable that contains rtt client information. + * Request to start an RTT ranging + * <p> + * This method is deprecated. Please use the + * {@link WifiRttManager#startRanging(RangingRequest, RangingResultCallback, Handler)} API. * - * @hide + * @param params -- RTT request Parameters + * @param listener -- Call back to inform RTT result + * @exception throw IllegalArgumentException when params are illegal + * throw IllegalStateException when RttCapabilities do not exist */ - public static class RttClient implements Parcelable { - // Package name of RttClient. - private final String mPackageName; - - public RttClient(String packageName) { - mPackageName = packageName; - } + @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) + public void startRanging(RttParams[] params, RttListener listener) { + Log.i(TAG, "Send RTT request to RTT Service"); - protected RttClient(Parcel in) { - mPackageName = in.readString(); + if (!mNewService.isAvailable()) { + listener.onFailure(REASON_NOT_AVAILABLE, ""); + return; } - public static final Creator<RttManager.RttClient> CREATOR = - new Creator<RttManager.RttClient>() { - @Override - public RttManager.RttClient createFromParcel(Parcel in) { - return new RttManager.RttClient(in); - } - - @Override - public RttManager.RttClient[] newArray(int size) { - return new RttManager.RttClient[size]; + RangingRequest.Builder builder = new RangingRequest.Builder(); + for (RttParams rttParams : params) { + if (rttParams.deviceType != RTT_PEER_TYPE_AP) { + listener.onFailure(REASON_INVALID_REQUEST, "Only AP peers are supported"); + return; } - }; - - @Override - public int describeContents() { - return 0; - } - @Override - public void writeToParcel(Parcel parcel, int i) { - parcel.writeString(mPackageName); - } - - public String getPackageName() { - return mPackageName; - } - } - - private boolean rttParamSanity(RttParams params, int index) { - if (mRttCapabilities == null) { - if(getRttCapabilities() == null) { - Log.e(TAG, "Can not get RTT capabilities"); - throw new IllegalStateException("RTT chip is not working"); + ScanResult reconstructed = new ScanResult(); + reconstructed.BSSID = rttParams.bssid; + if (rttParams.requestType == RTT_TYPE_TWO_SIDED) { + reconstructed.setFlag(ScanResult.FLAG_80211mc_RESPONDER); } + reconstructed.channelWidth = rttParams.channelWidth; + reconstructed.frequency = rttParams.frequency; + reconstructed.centerFreq0 = rttParams.centerFreq0; + reconstructed.centerFreq1 = rttParams.centerFreq1; + builder.addResponder( + android.net.wifi.rtt.ResponderConfig.fromScanResult(reconstructed)); } + try { + mNewService.startRanging(builder.build(), new RangingResultCallback() { + @Override + public void onRangingFailure(int code) { + int localCode = REASON_UNSPECIFIED; + if (code == STATUS_CODE_FAIL_RTT_NOT_AVAILABLE) { + localCode = REASON_NOT_AVAILABLE; + } + listener.onFailure(localCode, ""); + } - if (params.deviceType != RTT_PEER_TYPE_AP) { - return false; - } else if (params.requestType != RTT_TYPE_ONE_SIDED && params.requestType != - RTT_TYPE_TWO_SIDED) { - Log.e(TAG, "Request " + index + ": Illegal Request Type: " + params.requestType); - return false; - } else if (params.requestType == RTT_TYPE_ONE_SIDED && - !mRttCapabilities.oneSidedRttSupported) { - Log.e(TAG, "Request " + index + ": One side RTT is not supported"); - return false; - } else if (params.requestType == RTT_TYPE_TWO_SIDED && - !mRttCapabilities.twoSided11McRttSupported) { - Log.e(TAG, "Request " + index + ": two side RTT is not supported"); - return false; - } else if(params.bssid == null || params.bssid.isEmpty()) { - Log.e(TAG,"No BSSID in params"); - return false; - } else if ( params.numberBurst != 0 ) { - Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst); - return false; - } else if (params.numSamplesPerBurst <= 0 || params.numSamplesPerBurst > 31) { - Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " + - params.numSamplesPerBurst); - return false; - } else if (params.numRetriesPerMeasurementFrame < 0 || - params.numRetriesPerMeasurementFrame > 3) { - Log.e(TAG, "Request " + index + ": Illegal measurement frame retry number:" + - params.numRetriesPerMeasurementFrame); - return false; - } else if(params.numRetriesPerFTMR < 0 || - params.numRetriesPerFTMR > 3) { - Log.e(TAG, "Request " + index + ": Illegal FTMR frame retry number:" + - params.numRetriesPerFTMR); - return false; - } else if (params.LCIRequest && !mRttCapabilities.lciSupported) { - Log.e(TAG, "Request " + index + ": LCI is not supported"); - return false; - } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) { - Log.e(TAG, "Request " + index + ": LCR is not supported"); - return false; - } else if (params.burstTimeout < 1 || - (params.burstTimeout > 11 && params.burstTimeout != 15)){ - Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout); - return false; - } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) { - Log.e(TAG, "Request " + index + ": Do not support this preamble: " + params.preamble); - return false; - } else if ((params.bandwidth & mRttCapabilities.bwSupported) == 0) { - Log.e(TAG, "Request " + index + ": Do not support this bandwidth: " + params.bandwidth); - return false; + @Override + public void onRangingResults(List<RangingResult> results) { + RttResult[] legacyResults = new RttResult[results.size()]; + int i = 0; + for (RangingResult result : results) { + legacyResults[i] = new RttResult(); + legacyResults[i].status = result.getStatus(); + legacyResults[i].bssid = result.getMacAddress().toString(); + legacyResults[i].distance = result.getDistanceMm() / 10; + legacyResults[i].distanceStandardDeviation = + result.getDistanceStdDevMm() / 10; + legacyResults[i].rssi = result.getRssi(); + legacyResults[i].ts = result.getRangingTimestampUs(); + } + listener.onSuccess(legacyResults); + } + }, null); + } catch (IllegalArgumentException e) { + Log.e(TAG, "startRanging: invalid arguments - " + e); + listener.onFailure(REASON_INVALID_REQUEST, e.getMessage()); + } catch (SecurityException e) { + Log.e(TAG, "startRanging: security exception - " + e); + listener.onFailure(REASON_PERMISSION_DENIED, e.getMessage()); } - - return true; } /** - * Request to start an RTT ranging - * - * @param params -- RTT request Parameters - * @param listener -- Call back to inform RTT result - * @exception throw IllegalArgumentException when params are illegal - * throw IllegalStateException when RttCapabilities do not exist + * This method is deprecated and performs no function. Please use the {@link WifiRttManager} + * API. */ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) - public void startRanging(RttParams[] params, RttListener listener) { - int index = 0; - for(RttParams rttParam : params) { - if (!rttParamSanity(rttParam, index)) { - throw new IllegalArgumentException("RTT Request Parameter Illegal"); - } - index++; - } - validateChannel(); - ParcelableRttParams parcelableParams = new ParcelableRttParams(params); - Log.i(TAG, "Send RTT request to RTT Service"); - mAsyncChannel.sendMessage(CMD_OP_START_RANGING, - 0, putListener(listener), parcelableParams); - } - - @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopRanging(RttListener listener) { - validateChannel(); - mAsyncChannel.sendMessage(CMD_OP_STOP_RANGING, 0, removeListener(listener)); + Log.e(TAG, "stopRanging: unsupported operation - nop"); } /** @@ -1074,6 +1022,7 @@ public class RttManager { * The client can freely destroy or reuse the callback after {@link RttManager#disableResponder} * is called. */ + @Deprecated public abstract static class ResponderCallback { /** Callback when responder is enabled. */ public abstract void onResponderEnabled(ResponderConfig config); @@ -1089,18 +1038,18 @@ public class RttManager { * Note calling this method with the same callback when the responder is already enabled won't * change the responder state, a cached {@link ResponderConfig} from the last enabling will be * returned through the callback. + * <p> + * This method is deprecated and will throw an {@link UnsupportedOperationException} + * exception. Please use the {@link WifiRttManager} API to perform a Wi-Fi Aware peer-to-peer + * ranging. * * @param callback Callback for responder enabling/disabling result. * @throws IllegalArgumentException If {@code callback} is null. */ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void enableResponder(ResponderCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - validateChannel(); - int key = putListenerIfAbsent(callback); - mAsyncChannel.sendMessage(CMD_OP_ENABLE_RESPONDER, 0, key); + throw new UnsupportedOperationException( + "enableResponder is not supported in the adaptation layer"); } /** @@ -1109,22 +1058,18 @@ public class RttManager { * <p> * Calling this method when responder isn't enabled won't have any effect. The callback can be * reused for enabling responder after this method is called. + * <p> + * This method is deprecated and will throw an {@link UnsupportedOperationException} + * exception. Please use the {@link WifiRttManager} API to perform a Wi-Fi Aware peer-to-peer + * ranging. * * @param callback The same callback used for enabling responder. * @throws IllegalArgumentException If {@code callback} is null. */ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void disableResponder(ResponderCallback callback) { - if (callback == null) { - throw new IllegalArgumentException("callback cannot be null"); - } - validateChannel(); - int key = removeListener(callback); - if (key == INVALID_KEY) { - Log.e(TAG, "responder not enabled yet"); - return; - } - mAsyncChannel.sendMessage(CMD_OP_DISABLE_RESPONDER, 0, key); + throw new UnsupportedOperationException( + "disableResponder is not supported in the adaptation layer"); } /** @@ -1133,6 +1078,7 @@ public class RttManager { * * @see ScanResult */ + @Deprecated public static class ResponderConfig implements Parcelable { // TODO: make all fields final once we can get mac address from responder HAL APIs. @@ -1238,195 +1184,33 @@ public class RttManager { /** @hide */ public static final int CMD_OP_REG_BINDER = BASE + 9; - private static final int INVALID_KEY = 0; - - private final Context mContext; - private final IRttManager mService; - private final SparseArray mListenerMap = new SparseArray(); - private final Object mListenerMapLock = new Object(); - private final Object mCapabilitiesLock = new Object(); - + private final WifiRttManager mNewService; private RttCapabilities mRttCapabilities; - private int mListenerKey = 1; - private AsyncChannel mAsyncChannel; /** * Create a new WifiScanner instance. * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}. - * @param context the application context - * @param service the Binder interface - * @param looper Looper for running the callbacks. + * @param service the new WifiRttManager service * * @hide */ - public RttManager(Context context, IRttManager service, Looper looper) { - mContext = context; - mService = service; - Messenger messenger = null; - int[] key = new int[1]; - try { - Log.d(TAG, "Get the messenger from " + mService); - messenger = mService.getMessenger(new Binder(), key); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - if (messenger == null) { - throw new IllegalStateException("getMessenger() returned null! This is invalid."); - } - - mAsyncChannel = new AsyncChannel(); - - Handler handler = new ServiceHandler(looper); - mAsyncChannel.connectSync(mContext, handler, messenger); - // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message - // synchronously, which causes RttService to receive the wrong replyTo value. - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION, - new RttClient(context.getPackageName())); - mAsyncChannel.sendMessage(CMD_OP_REG_BINDER, key[0]); + public RttManager(Context context, WifiRttManager service) { + mNewService = service; + + boolean rttSupported = context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WIFI_RTT); + + mRttCapabilities = new RttCapabilities(); + mRttCapabilities.oneSidedRttSupported = rttSupported; + mRttCapabilities.twoSided11McRttSupported = rttSupported; + mRttCapabilities.lciSupported = false; + mRttCapabilities.lcrSupported = false; + mRttCapabilities.preambleSupported = PREAMBLE_HT | PREAMBLE_VHT; + mRttCapabilities.bwSupported = RTT_BW_40_SUPPORT | RTT_BW_80_SUPPORT; + mRttCapabilities.responderSupported = false; + mRttCapabilities.secureRttSupported = false; } - - private void validateChannel() { - if (mAsyncChannel == null) throw new IllegalStateException( - "No permission to access and change wifi or a bad initialization"); - } - - private int putListener(Object listener) { - if (listener == null) return INVALID_KEY; - int key; - synchronized (mListenerMapLock) { - do { - key = mListenerKey++; - } while (key == INVALID_KEY); - mListenerMap.put(key, listener); - } - return key; - } - - // Insert a listener if it doesn't exist in mListenerMap. Returns the key of the listener. - private int putListenerIfAbsent(Object listener) { - if (listener == null) return INVALID_KEY; - synchronized (mListenerMapLock) { - int key = getListenerKey(listener); - if (key != INVALID_KEY) { - return key; - } - do { - key = mListenerKey++; - } while (key == INVALID_KEY); - mListenerMap.put(key, listener); - return key; - } - - } - - private Object getListener(int key) { - if (key == INVALID_KEY) return null; - synchronized (mListenerMapLock) { - Object listener = mListenerMap.get(key); - return listener; - } - } - - private int getListenerKey(Object listener) { - if (listener == null) return INVALID_KEY; - synchronized (mListenerMapLock) { - int index = mListenerMap.indexOfValue(listener); - if (index == -1) { - return INVALID_KEY; - } else { - return mListenerMap.keyAt(index); - } - } - } - - private Object removeListener(int key) { - if (key == INVALID_KEY) return null; - synchronized (mListenerMapLock) { - Object listener = mListenerMap.get(key); - mListenerMap.remove(key); - return listener; - } - } - - private int removeListener(Object listener) { - int key = getListenerKey(listener); - if (key == INVALID_KEY) return key; - synchronized (mListenerMapLock) { - mListenerMap.remove(key); - return key; - } - } - - private class ServiceHandler extends Handler { - ServiceHandler(Looper looper) { - super(looper); - } - @Override - public void handleMessage(Message msg) { - Log.i(TAG, "RTT manager get message: " + msg.what); - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: - return; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - Log.e(TAG, "Channel connection lost"); - // This will cause all further async API calls on the WifiManager - // to fail and throw an exception - mAsyncChannel = null; - getLooper().quit(); - return; - } - - Object listener = getListener(msg.arg2); - if (listener == null) { - Log.e(TAG, "invalid listener key = " + msg.arg2 ); - return; - } else { - Log.i(TAG, "listener key = " + msg.arg2); - } - - switch (msg.what) { - /* ActionListeners grouped together */ - case CMD_OP_SUCCEEDED : - reportSuccess(listener, msg); - removeListener(msg.arg2); - break; - case CMD_OP_FAILED : - reportFailure(listener, msg); - removeListener(msg.arg2); - break; - case CMD_OP_ABORTED : - ((RttListener) listener).onAborted(); - removeListener(msg.arg2); - break; - case CMD_OP_ENALBE_RESPONDER_SUCCEEDED: - ResponderConfig config = (ResponderConfig) msg.obj; - ((ResponderCallback) (listener)).onResponderEnabled(config); - break; - case CMD_OP_ENALBE_RESPONDER_FAILED: - ((ResponderCallback) (listener)).onResponderEnableFailure(msg.arg1); - removeListener(msg.arg2); - break; - default: - if (DBG) Log.d(TAG, "Ignoring message " + msg.what); - return; - } - } - - void reportSuccess(Object listener, Message msg) { - RttListener rttListener = (RttListener) listener; - ParcelableRttResults parcelableResults = (ParcelableRttResults) msg.obj; - ((RttListener) listener).onSuccess(parcelableResults.mResults); - } - - void reportFailure(Object listener, Message msg) { - RttListener rttListener = (RttListener) listener; - Bundle bundle = (Bundle) msg.obj; - ((RttListener) listener).onFailure(msg.arg1, bundle.getString(DESCRIPTION_KEY)); - } - } - } diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index b6ad92614bfe..8024bf08b1d4 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -21,7 +21,9 @@ import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * Describes information about a detected access point. In addition @@ -227,37 +229,48 @@ public class ScanResult implements Parcelable { public long seen; /** - * @hide - * Update RSSI of the scan result - * @param previousRssi - * @param previousSeen - * @param maxAge + * On devices with multiple hardware radio chains, this class provides metadata about + * each radio chain that was used to receive this scan result (probe response or beacon). + * {@hide} */ - public void averageRssi(int previousRssi, long previousSeen, int maxAge) { + public static class RadioChainInfo { + /** Vendor defined id for a radio chain. */ + public int id; + /** Detected signal level in dBm (also known as the RSSI) on this radio chain. */ + public int level; - if (seen == 0) { - seen = System.currentTimeMillis(); + @Override + public String toString() { + return "RadioChainInfo: id=" + id + ", level=" + level; } - long age = seen - previousSeen; - if (previousSeen > 0 && age > 0 && age < maxAge/2) { - // Average the RSSI with previously seen instances of this scan result - double alpha = 0.5 - (double) age / (double) maxAge; - level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha); + @Override + public boolean equals(Object otherObj) { + if (this == otherObj) { + return true; + } + if (!(otherObj instanceof RadioChainInfo)) { + return false; + } + RadioChainInfo other = (RadioChainInfo) otherObj; + return id == other.id && level == other.level; } - } - /** - * num IP configuration failures - * @hide - */ - public int numIpConfigFailures; + @Override + public int hashCode() { + return Objects.hash(id, level); + } + }; /** - * @hide - * Last time we blacklisted the ScanResult + * Information about the list of the radio chains used to receive this scan result + * (probe response or beacon). + * + * For Example: On devices with 2 hardware radio chains, this list could hold 1 or 2 + * entries based on whether this scan result was received using one or both the chains. + * {@hide} */ - public long blackListTimestamp; + public RadioChainInfo[] radioChainInfos; /** * Status indicating the scan result does not correspond to a user's saved configuration @@ -268,12 +281,6 @@ public class ScanResult implements Parcelable { public boolean untrusted; /** - * Number of time we connected to it - * @hide - */ - public int numConnection; - - /** * Number of time autojoin used it * @hide */ @@ -386,12 +393,6 @@ public class ScanResult implements Parcelable { */ public List<String> anqpLines; - /** - * @hide - * storing the raw bytes of full result IEs - **/ - public byte[] bytes; - /** information elements from beacon * @hide */ @@ -481,6 +482,7 @@ public class ScanResult implements Parcelable { this.isCarrierAp = false; this.carrierApEapType = UNSPECIFIED; this.carrierName = null; + this.radioChainInfos = null; } /** {@hide} */ @@ -502,6 +504,7 @@ public class ScanResult implements Parcelable { this.isCarrierAp = false; this.carrierApEapType = UNSPECIFIED; this.carrierName = null; + this.radioChainInfos = null; } /** {@hide} */ @@ -530,6 +533,7 @@ public class ScanResult implements Parcelable { this.isCarrierAp = false; this.carrierApEapType = UNSPECIFIED; this.carrierName = null; + this.radioChainInfos = null; } /** {@hide} */ @@ -563,15 +567,14 @@ public class ScanResult implements Parcelable { distanceSdCm = source.distanceSdCm; seen = source.seen; untrusted = source.untrusted; - numConnection = source.numConnection; numUsage = source.numUsage; - numIpConfigFailures = source.numIpConfigFailures; venueName = source.venueName; operatorFriendlyName = source.operatorFriendlyName; flags = source.flags; isCarrierAp = source.isCarrierAp; carrierApEapType = source.carrierApEapType; carrierName = source.carrierName; + radioChainInfos = source.radioChainInfos; } } @@ -615,6 +618,7 @@ public class ScanResult implements Parcelable { sb.append(", Carrier AP: ").append(isCarrierAp ? "yes" : "no"); sb.append(", Carrier AP EAP Type: ").append(carrierApEapType); sb.append(", Carrier name: ").append(carrierName); + sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos)); return sb.toString(); } @@ -646,9 +650,7 @@ public class ScanResult implements Parcelable { dest.writeInt(centerFreq1); dest.writeLong(seen); dest.writeInt(untrusted ? 1 : 0); - dest.writeInt(numConnection); dest.writeInt(numUsage); - dest.writeInt(numIpConfigFailures); dest.writeString((venueName != null) ? venueName.toString() : ""); dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : ""); dest.writeLong(this.flags); @@ -687,6 +689,16 @@ public class ScanResult implements Parcelable { dest.writeInt(isCarrierAp ? 1 : 0); dest.writeInt(carrierApEapType); dest.writeString(carrierName); + + if (radioChainInfos != null) { + dest.writeInt(radioChainInfos.length); + for (int i = 0; i < radioChainInfos.length; i++) { + dest.writeInt(radioChainInfos[i].id); + dest.writeInt(radioChainInfos[i].level); + } + } else { + dest.writeInt(0); + } } /** Implement the Parcelable interface {@hide} */ @@ -718,9 +730,7 @@ public class ScanResult implements Parcelable { sr.seen = in.readLong(); sr.untrusted = in.readInt() != 0; - sr.numConnection = in.readInt(); sr.numUsage = in.readInt(); - sr.numIpConfigFailures = in.readInt(); sr.venueName = in.readString(); sr.operatorFriendlyName = in.readString(); sr.flags = in.readLong(); @@ -759,6 +769,15 @@ public class ScanResult implements Parcelable { sr.isCarrierAp = in.readInt() != 0; sr.carrierApEapType = in.readInt(); sr.carrierName = in.readString(); + n = in.readInt(); + if (n != 0) { + sr.radioChainInfos = new RadioChainInfo[n]; + for (int i = 0; i < n; i++) { + sr.radioChainInfos[i] = new RadioChainInfo(); + sr.radioChainInfos[i].id = in.readInt(); + sr.radioChainInfos[i].level = in.readInt(); + } + } return sr; } diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java index 29bf02cac8fe..03c9fbeec918 100644 --- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java +++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java @@ -56,6 +56,11 @@ public final class WifiActivityEnergyInfo implements Parcelable { /** * @hide */ + public long mControllerScanTimeMs; + + /** + * @hide + */ public long mControllerIdleTimeMs; /** @@ -69,13 +74,14 @@ public final class WifiActivityEnergyInfo implements Parcelable { public static final int STACK_STATE_STATE_IDLE = 3; public WifiActivityEnergyInfo(long timestamp, int stackState, - long txTime, long[] txTimePerLevel, long rxTime, long idleTime, - long energyUsed) { + long txTime, long[] txTimePerLevel, long rxTime, long scanTime, + long idleTime, long energyUsed) { mTimestamp = timestamp; mStackState = stackState; mControllerTxTimeMs = txTime; mControllerTxTimePerLevelMs = txTimePerLevel; mControllerRxTimeMs = rxTime; + mControllerScanTimeMs = scanTime; mControllerIdleTimeMs = idleTime; mControllerEnergyUsed = energyUsed; } @@ -88,6 +94,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { + " mControllerTxTimeMs=" + mControllerTxTimeMs + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs) + " mControllerRxTimeMs=" + mControllerRxTimeMs + + " mControllerScanTimeMs=" + mControllerScanTimeMs + " mControllerIdleTimeMs=" + mControllerIdleTimeMs + " mControllerEnergyUsed=" + mControllerEnergyUsed + " }"; @@ -101,10 +108,11 @@ public final class WifiActivityEnergyInfo implements Parcelable { long txTime = in.readLong(); long[] txTimePerLevel = in.createLongArray(); long rxTime = in.readLong(); + long scanTime = in.readLong(); long idleTime = in.readLong(); long energyUsed = in.readLong(); return new WifiActivityEnergyInfo(timestamp, stackState, - txTime, txTimePerLevel, rxTime, idleTime, energyUsed); + txTime, txTimePerLevel, rxTime, scanTime, idleTime, energyUsed); } public WifiActivityEnergyInfo[] newArray(int size) { return new WifiActivityEnergyInfo[size]; @@ -117,6 +125,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { out.writeLong(mControllerTxTimeMs); out.writeLongArray(mControllerTxTimePerLevelMs); out.writeLong(mControllerRxTimeMs); + out.writeLong(mControllerScanTimeMs); out.writeLong(mControllerIdleTimeMs); out.writeLong(mControllerEnergyUsed); } @@ -157,6 +166,13 @@ public final class WifiActivityEnergyInfo implements Parcelable { } /** + * @return scan time in ms + */ + public long getControllerScanTimeMillis() { + return mControllerScanTimeMs; + } + + /** * @return idle time in ms */ public long getControllerIdleTimeMillis() { @@ -183,6 +199,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { public boolean isValid() { return ((mControllerTxTimeMs >=0) && (mControllerRxTimeMs >=0) && + (mControllerScanTimeMs >=0) && (mControllerIdleTimeMs >=0)); } -} +}
\ No newline at end of file diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 6438631cb8ed..ddcf327b9dd1 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -16,10 +16,12 @@ package android.net.wifi; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.pm.PackageManager; import android.net.IpConfiguration; import android.net.IpConfiguration.ProxySettings; +import android.net.MacAddress; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; import android.net.Uri; @@ -54,8 +56,10 @@ public class WifiConfiguration implements Parcelable { /** {@hide} */ public static final String pskVarName = "psk"; /** {@hide} */ + @Deprecated public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" }; /** {@hide} */ + @Deprecated public static final String wepTxKeyIdxVarName = "wep_tx_keyidx"; /** {@hide} */ public static final String priorityVarName = "priority"; @@ -82,6 +86,9 @@ public class WifiConfiguration implements Parcelable { /** WPA is not used; plaintext or static WEP could be used. */ public static final int NONE = 0; /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */ + /** @deprecated Due to security and performance limitations, use of WPA-1 networks + * is discouraged. WPA-2 (RSN) should be used instead. */ + @Deprecated public static final int WPA_PSK = 1; /** WPA using EAP authentication. Generally used with an external authentication server. */ public static final int WPA_EAP = 2; @@ -115,8 +122,8 @@ public class WifiConfiguration implements Parcelable { public static final String varName = "key_mgmt"; - public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X", - "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" }; + public static final String[] strings = { "NONE", /* deprecated */ "WPA_PSK", "WPA_EAP", + "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" }; } /** @@ -125,7 +132,10 @@ public class WifiConfiguration implements Parcelable { public static class Protocol { private Protocol() { } - /** WPA/IEEE 802.11i/D3.0 */ + /** WPA/IEEE 802.11i/D3.0 + * @deprecated Due to security and performance limitations, use of WPA-1 networks + * is discouraged. WPA-2 (RSN) should be used instead. */ + @Deprecated public static final int WPA = 0; /** WPA2/IEEE 802.11i */ public static final int RSN = 1; @@ -147,7 +157,10 @@ public class WifiConfiguration implements Parcelable { /** Open System authentication (required for WPA/WPA2) */ public static final int OPEN = 0; - /** Shared Key authentication (requires static WEP keys) */ + /** Shared Key authentication (requires static WEP keys) + * @deprecated Due to security and performance limitations, use of WEP networks + * is discouraged. */ + @Deprecated public static final int SHARED = 1; /** LEAP/Network EAP (only used with LEAP) */ public static final int LEAP = 2; @@ -165,7 +178,10 @@ public class WifiConfiguration implements Parcelable { /** Use only Group keys (deprecated) */ public static final int NONE = 0; - /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ + /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] + * @deprecated Due to security and performance limitations, use of WPA-1 networks + * is discouraged. WPA-2 (RSN) should be used instead. */ + @Deprecated public static final int TKIP = 1; /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */ public static final int CCMP = 2; @@ -187,9 +203,15 @@ public class WifiConfiguration implements Parcelable { public static class GroupCipher { private GroupCipher() { } - /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */ + /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) + * @deprecated Due to security and performance limitations, use of WEP networks + * is discouraged. */ + @Deprecated public static final int WEP40 = 0; - /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */ + /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key + * @deprecated Due to security and performance limitations, use of WEP networks + * is discouraged. */ + @Deprecated public static final int WEP104 = 1; /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */ public static final int TKIP = 2; @@ -203,7 +225,8 @@ public class WifiConfiguration implements Parcelable { public static final String varName = "group"; public static final String[] strings = - { "WEP40", "WEP104", "TKIP", "CCMP", "GTK_NOT_USED" }; + { /* deprecated */ "WEP40", /* deprecated */ "WEP104", + "TKIP", "CCMP", "GTK_NOT_USED" }; } /** Possible status of a network configuration. */ @@ -267,8 +290,15 @@ public class WifiConfiguration implements Parcelable { public static final int AP_BAND_5GHZ = 1; /** + * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability, + * operating country code and current radio conditions. + * @hide + */ + public static final int AP_BAND_ANY = -1; + + /** * The band which AP resides on - * 0-2G 1-5G + * -1:Any 0:2G 1:5G * By default, 2G is chosen * @hide */ @@ -302,10 +332,16 @@ public class WifiConfiguration implements Parcelable { * When the value of one of these keys is read, the actual key is * not returned, just a "*" if the key has a value, or the null * string otherwise. + * @deprecated Due to security and performance limitations, use of WEP networks + * is discouraged. */ + @Deprecated public String[] wepKeys; - /** Default WEP key index, ranging from 0 to 3. */ + /** Default WEP key index, ranging from 0 to 3. + * @deprecated Due to security and performance limitations, use of WEP networks + * is discouraged. */ + @Deprecated public int wepTxKeyIndex; /** @@ -404,6 +440,7 @@ public class WifiConfiguration implements Parcelable { /** * @hide */ + @NonNull private IpConfiguration mIpConfiguration; /** @@ -845,6 +882,55 @@ public class WifiConfiguration implements Parcelable { @SystemApi public int numAssociation; + /** + * @hide + * Randomized MAC address to use with this particular network + */ + private MacAddress mRandomizedMacAddress; + + /** + * @hide + * Checks if the given MAC address can be used for Connected Mac Randomization + * by verifying that it is non-null, unicast, and locally assigned. + * @param mac MacAddress to check + * @return true if mac is good to use + */ + private boolean isValidMacAddressForRandomization(MacAddress mac) { + return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned(); + } + + /** + * @hide + * Returns Randomized MAC address to use with the network. + * If it is not set/valid, create a new randomized address. + */ + public MacAddress getOrCreateRandomizedMacAddress() { + if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) { + mRandomizedMacAddress = MacAddress.createRandomUnicastAddress(); + } + return mRandomizedMacAddress; + } + + /** + * @hide + * Returns MAC address set to be the local randomized MAC address. + * Does not guarantee that the returned address is valid for use. + */ + public MacAddress getRandomizedMacAddress() { + if (mRandomizedMacAddress == null) { + mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS; + } + return mRandomizedMacAddress; + } + + /** + * @hide + * @param mac MacAddress to change into + */ + public void setRandomizedMacAddress(MacAddress mac) { + mRandomizedMacAddress = mac; + } + /** @hide * Boost given to RSSI on a home network for the purpose of calculating the score * This adds stickiness to home networks, as defined by: @@ -1534,6 +1620,7 @@ public class WifiConfiguration implements Parcelable { creatorUid = -1; shared = true; dtimInterval = 0; + mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS; } /** @@ -1942,6 +2029,7 @@ public class WifiConfiguration implements Parcelable { /** @hide */ public void setIpConfiguration(IpConfiguration ipConfiguration) { + if (ipConfiguration == null) ipConfiguration = new IpConfiguration(); mIpConfiguration = ipConfiguration; } @@ -2117,6 +2205,7 @@ public class WifiConfiguration implements Parcelable { updateTime = source.updateTime; shared = source.shared; recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus()); + mRandomizedMacAddress = source.mRandomizedMacAddress; } } @@ -2184,6 +2273,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(shared ? 1 : 0); dest.writeString(mPasspointManagementObjectTree); dest.writeInt(recentFailure.getAssociationStatus()); + dest.writeParcelable(mRandomizedMacAddress, flags); } /** Implement the Parcelable interface {@hide} */ @@ -2223,7 +2313,7 @@ public class WifiConfiguration implements Parcelable { config.allowedGroupCiphers = readBitSet(in); config.enterpriseConfig = in.readParcelable(null); - config.mIpConfiguration = in.readParcelable(null); + config.setIpConfiguration(in.readParcelable(null)); config.dhcpServer = in.readString(); config.defaultGwMacAddress = in.readString(); config.selfAdded = in.readInt() != 0; @@ -2252,6 +2342,7 @@ public class WifiConfiguration implements Parcelable { config.shared = in.readInt() != 0; config.mPasspointManagementObjectTree = in.readString(); config.recentFailure.setAssociationStatus(in.readInt()); + config.mRandomizedMacAddress = in.readParcelable(null); return config; } diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.java b/wifi/java/android/net/wifi/WifiConnectionStatistics.java deleted file mode 100644 index 1120c66ea418..000000000000 --- a/wifi/java/android/net/wifi/WifiConnectionStatistics.java +++ /dev/null @@ -1,158 +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.annotation.SystemApi; - -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import java.util.HashMap; - -/** - * Wifi Connection Statistics: gather various stats regarding WiFi connections, - * connection requests, auto-join - * and WiFi usage. - * @hide - * @removed - */ -@SystemApi -public class WifiConnectionStatistics implements Parcelable { - private static final String TAG = "WifiConnnectionStatistics"; - - /** - * history of past connection to untrusted SSID - * Key = SSID - * Value = num connection - */ - public HashMap<String, WifiNetworkConnectionStatistics> untrustedNetworkHistory; - - // Number of time we polled the chip and were on 5GHz - public int num5GhzConnected; - - // Number of time we polled the chip and were on 2.4GHz - public int num24GhzConnected; - - // Number autojoin attempts - public int numAutoJoinAttempt; - - // Number auto-roam attempts - public int numAutoRoamAttempt; - - // Number wifimanager join attempts - public int numWifiManagerJoinAttempt; - - public WifiConnectionStatistics() { - untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>(); - } - - public void incrementOrAddUntrusted(String SSID, int connection, int usage) { - WifiNetworkConnectionStatistics stats; - if (TextUtils.isEmpty(SSID)) - return; - if (untrustedNetworkHistory.containsKey(SSID)) { - stats = untrustedNetworkHistory.get(SSID); - if (stats != null){ - stats.numConnection = connection + stats.numConnection; - stats.numUsage = usage + stats.numUsage; - } - } else { - stats = new WifiNetworkConnectionStatistics(connection, usage); - } - if (stats != null) { - untrustedNetworkHistory.put(SSID, stats); - } - } - - @Override - public String toString() { - StringBuilder sbuf = new StringBuilder(); - sbuf.append("Connected on: 2.4Ghz=").append(num24GhzConnected); - sbuf.append(" 5Ghz=").append(num5GhzConnected).append("\n"); - sbuf.append(" join=").append(numWifiManagerJoinAttempt); - sbuf.append("\\").append(numAutoJoinAttempt).append("\n"); - sbuf.append(" roam=").append(numAutoRoamAttempt).append("\n"); - - for (String Key : untrustedNetworkHistory.keySet()) { - WifiNetworkConnectionStatistics stats = untrustedNetworkHistory.get(Key); - if (stats != null) { - sbuf.append(Key).append(" ").append(stats.toString()).append("\n"); - } - } - return sbuf.toString(); - } - - /** copy constructor*/ - public WifiConnectionStatistics(WifiConnectionStatistics source) { - untrustedNetworkHistory = new HashMap<String, WifiNetworkConnectionStatistics>(); - if (source != null) { - untrustedNetworkHistory.putAll(source.untrustedNetworkHistory); - } - } - - /** Implement the Parcelable interface */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(num24GhzConnected); - dest.writeInt(num5GhzConnected); - dest.writeInt(numAutoJoinAttempt); - dest.writeInt(numAutoRoamAttempt); - dest.writeInt(numWifiManagerJoinAttempt); - - dest.writeInt(untrustedNetworkHistory.size()); - for (String Key : untrustedNetworkHistory.keySet()) { - WifiNetworkConnectionStatistics num = untrustedNetworkHistory.get(Key); - dest.writeString(Key); - dest.writeInt(num.numConnection); - dest.writeInt(num.numUsage); - - } - } - - /** Implement the Parcelable interface */ - public static final Creator<WifiConnectionStatistics> CREATOR = - new Creator<WifiConnectionStatistics>() { - public WifiConnectionStatistics createFromParcel(Parcel in) { - WifiConnectionStatistics stats = new WifiConnectionStatistics(); - stats.num24GhzConnected = in.readInt(); - stats.num5GhzConnected = in.readInt(); - stats.numAutoJoinAttempt = in.readInt(); - stats.numAutoRoamAttempt = in.readInt(); - stats.numWifiManagerJoinAttempt = in.readInt(); - int n = in.readInt(); - while (n-- > 0) { - String Key = in.readString(); - int numConnection = in.readInt(); - int numUsage = in.readInt(); - WifiNetworkConnectionStatistics st = - new WifiNetworkConnectionStatistics(numConnection, numUsage); - stats.untrustedNetworkHistory.put(Key, st); - } - return stats; - } - - public WifiConnectionStatistics[] newArray(int size) { - return new WifiConnectionStatistics[size]; - } - }; -} 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..897b1eaa2a64 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -16,6 +16,8 @@ package android.net.wifi; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -32,6 +34,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; @@ -52,6 +56,8 @@ import com.android.server.net.NetworkPinner; import dalvik.system.CloseGuard; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.net.InetAddress; import java.util.Collections; @@ -429,6 +435,17 @@ public class WifiManager { */ public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode"; + /** @hide */ + @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = { + WIFI_AP_STATE_DISABLING, + WIFI_AP_STATE_DISABLED, + WIFI_AP_STATE_ENABLING, + WIFI_AP_STATE_ENABLED, + WIFI_AP_STATE_FAILED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface WifiApState {} + /** * Wi-Fi AP is currently being disabled. The state will change to * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully. @@ -483,6 +500,14 @@ public class WifiManager { @SystemApi public static final int WIFI_AP_STATE_FAILED = 14; + /** @hide */ + @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = { + SAP_START_FAILURE_GENERAL, + SAP_START_FAILURE_NO_CHANNEL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SapStartFailure {} + /** * If WIFI AP start failed, this reason code means there is no legal channel exists on * user selected band by regulatory @@ -554,14 +579,9 @@ public class WifiManager { public static final String EXTRA_SUPPLICANT_CONNECTED = "connected"; /** * Broadcast intent action indicating that the state of Wi-Fi connectivity - * has changed. One extra provides the new state - * in the form of a {@link android.net.NetworkInfo} object. If the new - * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of - * the access point. - * as a {@code String}. + * has changed. An extra provides the new state + * in the form of a {@link android.net.NetworkInfo} object. * @see #EXTRA_NETWORK_INFO - * @see #EXTRA_BSSID - * @see #EXTRA_WIFI_INFO */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE"; @@ -573,17 +593,16 @@ public class WifiManager { public static final String EXTRA_NETWORK_INFO = "networkInfo"; /** * The lookup key for a String giving the BSSID of the access point to which - * we are connected. Only present when the new state is CONNECTED. - * Retrieve with - * {@link android.content.Intent#getStringExtra(String)}. + * we are connected. No longer used. */ + @Deprecated public static final String EXTRA_BSSID = "bssid"; /** * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the - * information about the access point to which we are connected. Only present - * when the new state is CONNECTED. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. + * information about the access point to which we are connected. + * No longer used. */ + @Deprecated public static final String EXTRA_WIFI_INFO = "wifiInfo"; /** * Broadcast intent action indicating that the state of establishing a connection to @@ -692,11 +711,11 @@ public class WifiManager { * representing if the scan was successful or not. * Scans may fail for multiple reasons, these may include: * <ol> - * <li>A non-privileged app requested too many scans in a certain period of time. - * This may lead to additional scan request rejections via "scan throttling". - * See - * <a href="https://developer.android.com/preview/features/background-location-limits.html"> - * here</a> for details. + * <li>An app requested too many scans in a certain period of time. + * This may lead to additional scan request rejections via "scan throttling" for both + * foreground and background apps. + * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are + * exempted from scan throttling. * </li> * <li>The device is idle and scanning is disabled.</li> * <li>Wifi hardware reported a scan failure.</li> @@ -970,8 +989,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 { @@ -1003,35 +1021,41 @@ public class WifiManager { } /** + * Returns a WifiConfiguration matching this ScanResult + * + * @param scanResult scanResult that represents the BSSID + * @return {@link WifiConfiguration} that matches this BSSID or null + * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide - * @removed */ - @SystemApi - @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL) - public WifiConnectionStatistics getConnectionStatistics() { + public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) { try { - return mService.getConnectionStatistics(); + return mService.getMatchingWifiConfig(scanResult); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Returns a WifiConfiguration matching this ScanResult + * 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 {@link WifiConfiguration} that matches this BSSID or null + * @return A list of {@link WifiConfiguration} * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ - public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) { + public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) { try { - return mService.getMatchingWifiConfig(scanResult); + 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. * @@ -1108,7 +1132,7 @@ public class WifiManager { */ private int addOrUpdateNetwork(WifiConfiguration config) { try { - return mService.addOrUpdateNetwork(config); + return mService.addOrUpdateNetwork(config, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1129,7 +1153,7 @@ public class WifiManager { */ public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) { try { - if (!mService.addOrUpdatePasspointConfiguration(config)) { + if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) { throw new IllegalArgumentException(); } } catch (RemoteException e) { @@ -1146,7 +1170,7 @@ public class WifiManager { */ public void removePasspointConfiguration(String fqdn) { try { - if (!mService.removePasspointConfiguration(fqdn)) { + if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) { throw new IllegalArgumentException(); } } catch (RemoteException e) { @@ -1232,7 +1256,7 @@ public class WifiManager { */ public boolean removeNetwork(int netId) { try { - return mService.removeNetwork(netId); + return mService.removeNetwork(netId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1278,7 +1302,7 @@ public class WifiManager { boolean success; try { - success = mService.enableNetwork(netId, attemptConnect); + success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1304,7 +1328,7 @@ public class WifiManager { */ public boolean disableNetwork(int netId) { try { - return mService.disableNetwork(netId); + return mService.disableNetwork(netId, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1317,7 +1341,7 @@ public class WifiManager { */ public boolean disconnect() { try { - mService.disconnect(); + mService.disconnect(mContext.getOpPackageName()); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1332,7 +1356,7 @@ public class WifiManager { */ public boolean reconnect() { try { - mService.reconnect(); + mService.reconnect(mContext.getOpPackageName()); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1347,7 +1371,7 @@ public class WifiManager { */ public boolean reassociate() { try { - mService.reassociate(); + mService.reassociate(mContext.getOpPackageName()); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1574,7 +1598,10 @@ public class WifiManager { * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li> * </ol> * @return {@code true} if the operation succeeded, i.e., the scan was initiated. + * @deprecated The ability for apps to trigger scan requests will be removed in a future + * release. */ + @Deprecated public boolean startScan() { return startScan(null); } @@ -1593,65 +1620,14 @@ public class WifiManager { } /** - * startLocationRestrictedScan() - * Trigger a scan which will not make use of DFS channels and is thus not suitable for - * establishing wifi connection. - * @deprecated This API is nolonger supported. - * Use {@link android.net.wifi.WifiScanner} API - * @hide - * @removed - */ - @Deprecated - @SystemApi - @SuppressLint("Doclava125") - public boolean startLocationRestrictedScan(WorkSource workSource) { - return false; - } - - /** - * Check if the Batched Scan feature is supported. - * - * @return false if not supported. - * @deprecated This API is nolonger supported. - * Use {@link android.net.wifi.WifiScanner} API - * @hide - * @removed - */ - @Deprecated - @SystemApi - @SuppressLint("Doclava125") - public boolean isBatchedScanSupported() { - return false; - } - - /** - * Retrieve the latest batched scan result. This should be called immediately after - * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received. - * @deprecated This API is nolonger supported. - * Use {@link android.net.wifi.WifiScanner} API - * @hide - * @removed - */ - @Deprecated - @SystemApi - @SuppressLint("Doclava125") - public List<BatchedScanResult> getBatchedScanResults() { - return null; - } - - /** - * Creates a configuration token describing the current network of MIME type - * application/vnd.wfa.wsc. Can be used to configure WiFi networks via NFC. + * WPS has been deprecated from Client mode operation. * - * @return hex-string encoded configuration token or null if there is no current network + * @return null * @hide + * @deprecated This API is deprecated */ public String getCurrentNetworkWpsNfcConfigurationToken() { - try { - return mService.getCurrentNetworkWpsNfcConfigurationToken(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return null; } /** @@ -1712,30 +1688,25 @@ public class WifiManager { * existing networks. You should assume the network IDs can be different * after calling this method. * - * @return {@code true} if the operation succeeded + * @return {@code false} Will always return true. * @deprecated There is no need to call this method - * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)} * and {@link #removeNetwork(int)} already persist the configurations automatically. */ @Deprecated public boolean saveConfiguration() { - try { - return mService.saveConfiguration(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return true; } /** * 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 +1755,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 +1842,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}, @@ -2186,7 +2127,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) { try { - mService.setWifiApConfiguration(wifiConfig); + mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName()); return true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2261,20 +2202,34 @@ public class WifiManager { /** @hide */ public static final int SAVE_NETWORK_SUCCEEDED = BASE + 9; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int START_WPS = BASE + 10; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int START_WPS_SUCCEEDED = BASE + 11; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int WPS_FAILED = BASE + 12; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int WPS_COMPLETED = BASE + 13; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int CANCEL_WPS = BASE + 14; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int CANCEL_WPS_FAILED = BASE + 15; - /** @hide */ + /** @hide + * @deprecated This is deprecated + */ public static final int CANCEL_WPS_SUCCEDED = BASE + 16; /** @hide */ @@ -2314,15 +2269,25 @@ public class WifiManager { public static final int BUSY = 2; /* WPS specific errors */ - /** WPS overlap detected */ + /** WPS overlap detected + * @deprecated This is deprecated + */ public static final int WPS_OVERLAP_ERROR = 3; - /** WEP on WPS is prohibited */ + /** WEP on WPS is prohibited + * @deprecated This is deprecated + */ public static final int WPS_WEP_PROHIBITED = 4; - /** TKIP only prohibited */ + /** TKIP only prohibited + * @deprecated This is deprecated + */ public static final int WPS_TKIP_ONLY_PROHIBITED = 5; - /** Authentication failure on WPS */ + /** Authentication failure on WPS + * @deprecated This is deprecated + */ public static final int WPS_AUTH_FAILURE = 6; - /** WPS timed out */ + /** WPS timed out + * @deprecated This is deprecated + */ public static final int WPS_TIMED_OUT = 7; /** @@ -2363,12 +2328,19 @@ public class WifiManager { public void onFailure(int reason); } - /** Interface for callback invocation on a start WPS action */ + /** Interface for callback invocation on a start WPS action + * @deprecated This is deprecated + */ public static abstract class WpsCallback { - /** WPS start succeeded */ + + /** WPS start succeeded + * @deprecated This API is deprecated + */ public abstract void onStarted(String pin); - /** WPS operation completed successfully */ + /** WPS operation completed successfully + * @deprecated This API is deprecated + */ public abstract void onSucceeded(); /** @@ -2377,6 +2349,7 @@ public class WifiManager { * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR}, * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE} * and some generic errors. + * @deprecated This API is deprecated */ public abstract void onFailed(int reason); } @@ -2397,6 +2370,119 @@ public class WifiManager { } /** + * Base class for soft AP callback. Should be extended by applications and set when calling + * {@link WifiManager#registerSoftApCallback(SoftApCallback, Handler)}. + * + * @hide + */ + public interface SoftApCallback { + /** + * Called when soft AP state changes. + * + * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED}, + * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, + * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} + * @param failureReason reason when in failed state. One of + * {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL} + */ + public abstract void onStateChanged(@WifiApState int state, + @SapStartFailure int failureReason); + + /** + * Called when number of connected clients to soft AP changes. + * + * @param numClients number of connected clients + */ + public abstract void onNumClientsChanged(int numClients); + } + + /** + * Callback proxy for SoftApCallback objects. + * + * @hide + */ + private static class SoftApCallbackProxy extends ISoftApCallback.Stub { + private final Handler mHandler; + private final SoftApCallback mCallback; + + SoftApCallbackProxy(Looper looper, SoftApCallback callback) { + mHandler = new Handler(looper); + mCallback = callback; + } + + @Override + public void onStateChanged(int state, int failureReason) throws RemoteException { + Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state + ", failureReason=" + + failureReason); + mHandler.post(() -> { + mCallback.onStateChanged(state, failureReason); + }); + } + + @Override + public void onNumClientsChanged(int numClients) throws RemoteException { + Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients); + mHandler.post(() -> { + mCallback.onNumClientsChanged(numClients); + }); + } + } + + /** + * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the current + * soft AP state and number of connected devices immediately after a successful call to this API + * via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state + * indicates that the latest attempt to start soft AP has failed. Caller can unregister a + * previously registered callback using {@link unregisterSoftApCallback} + * <p> + * Applications should have the + * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers + * without the permission will trigger a {@link java.lang.SecurityException}. + * <p> + * + * @param callback Callback for soft AP events + * @param handler The Handler on whose thread to execute the callbacks of the {@code callback} + * object. If null, then the application's main thread will be used. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void registerSoftApCallback(@NonNull SoftApCallback callback, + @Nullable Handler handler) { + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", handler=" + handler); + + Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper(); + Binder binder = new Binder(); + try { + mService.registerSoftApCallback(binder, new SoftApCallbackProxy(looper, callback), + callback.hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Allow callers to unregister a previously registered callback. After calling this method, + * applications will no longer receive soft AP events. + * + * @param callback Callback to unregister for soft AP events + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void unregisterSoftApCallback(@NonNull SoftApCallback callback) { + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + Log.v(TAG, "unregisterSoftApCallback: callback=" + callback); + + try { + mService.unregisterSoftApCallback(callback.hashCode()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * LocalOnlyHotspotReservation that contains the {@link WifiConfiguration} for the active * LocalOnlyHotspot request. * <p> @@ -2756,36 +2842,6 @@ public class WifiManager { ((ActionListener) listener).onSuccess(); } break; - case WifiManager.START_WPS_SUCCEEDED: - if (listener != null) { - WpsResult result = (WpsResult) message.obj; - ((WpsCallback) listener).onStarted(result.pin); - //Listener needs to stay until completion or failure - synchronized (mListenerMapLock) { - mListenerMap.put(message.arg2, listener); - } - } - break; - case WifiManager.WPS_COMPLETED: - if (listener != null) { - ((WpsCallback) listener).onSucceeded(); - } - break; - case WifiManager.WPS_FAILED: - if (listener != null) { - ((WpsCallback) listener).onFailed(message.arg1); - } - break; - case WifiManager.CANCEL_WPS_SUCCEDED: - if (listener != null) { - ((WpsCallback) listener).onSucceeded(); - } - break; - case WifiManager.CANCEL_WPS_FAILED: - if (listener != null) { - ((WpsCallback) listener).onFailed(message.arg1); - } - break; case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED: if (listener != null) { RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj; @@ -2855,8 +2911,7 @@ public class WifiManager { * gets added to the list of configured networks for the foreground user. * * For a new network, this function is used instead of a - * sequence of addNetwork(), enableNetwork(), saveConfiguration() and - * reconnect() + * sequence of addNetwork(), enableNetwork(), and reconnect() * * @param config the set of variables that describe the configuration, * contained in a {@link WifiConfiguration} object. @@ -2878,8 +2933,7 @@ public class WifiManager { /** * Connect to a network with the given networkId. * - * This function is used instead of a enableNetwork(), saveConfiguration() and - * reconnect() + * This function is used instead of a enableNetwork() and reconnect() * * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link * getConfiguredNetworks}. @@ -2899,10 +2953,12 @@ public class WifiManager { * is updated. Any new network is enabled by default. * * For a new network, this function is used instead of a - * sequence of addNetwork(), enableNetwork() and saveConfiguration(). + * sequence of addNetwork() and enableNetwork(). * * For an existing network, it accomplishes the task of updateNetwork() - * and saveConfiguration() + * + * This API will cause reconnect if the crecdentials of the current active + * connection has been changed. * * @param config the set of variables that describe the configuration, * contained in a {@link WifiConfiguration} object. @@ -2921,7 +2977,6 @@ public class WifiManager { * foreground user. * * This function is used instead of a sequence of removeNetwork() - * and saveConfiguration(). * * @param config the set of variables that describe the configuration, * contained in a {@link WifiConfiguration} object. @@ -2958,34 +3013,39 @@ public class WifiManager { public void disableEphemeralNetwork(String SSID) { if (SSID == null) throw new IllegalArgumentException("SSID cannot be null"); try { - mService.disableEphemeralNetwork(SSID); + mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Start Wi-fi Protected Setup + * WPS suport has been deprecated from Client mode and this method will immediately trigger + * {@link WpsCallback#onFailed(int)} with a generic error. * * @param config WPS configuration (does not support {@link WpsInfo#LABEL}) * @param listener for callbacks on success or failure. Can be null. - * @throws IllegalStateException if the WifiManager instance needs to be - * initialized again + * @throws IllegalStateException if the WifiManager instance needs to be initialized again + * @deprecated This API is deprecated */ public void startWps(WpsInfo config, WpsCallback listener) { - if (config == null) throw new IllegalArgumentException("config cannot be null"); - getChannel().sendMessage(START_WPS, 0, putListener(listener), config); + if (listener != null ) { + listener.onFailed(ERROR); + } } /** - * Cancel any ongoing Wi-fi Protected Setup + * WPS support has been deprecated from Client mode and this method will immediately trigger + * {@link WpsCallback#onFailed(int)} with a generic error. * * @param listener for callbacks on success or failure. Can be null. - * @throws IllegalStateException if the WifiManager instance needs to be - * initialized again + * @throws IllegalStateException if the WifiManager instance needs to be initialized again + * @deprecated This API is deprecated */ public void cancelWps(WpsCallback listener) { - getChannel().sendMessage(CANCEL_WPS, 0, putListener(listener)); + if (listener != null) { + listener.onFailed(ERROR); + } } /** @@ -2997,7 +3057,7 @@ public class WifiManager { */ public Messenger getWifiServiceMessenger() { try { - return mService.getWifiServiceMessenger(); + return mService.getWifiServiceMessenger(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3133,7 +3193,7 @@ public class WifiManager { public void setWorkSource(WorkSource ws) { synchronized (mBinder) { - if (ws != null && ws.size() == 0) { + if (ws != null && ws.isEmpty()) { ws = null; } boolean changed = true; @@ -3145,7 +3205,7 @@ public class WifiManager { changed = mWorkSource != null; mWorkSource = new WorkSource(ws); } else { - changed = mWorkSource.diff(ws); + changed = !mWorkSource.equals(ws); if (changed) { mWorkSource.set(ws); } @@ -3448,6 +3508,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); @@ -3471,62 +3532,13 @@ public class WifiManager { } /** - * Set wifi Aggressive Handover. Called from developer settings. - * @hide - */ - public void enableAggressiveHandover(int enabled) { - try { - mService.enableAggressiveHandover(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the WiFi Handover aggressiveness.This is used by settings - * to decide what to show within the picker. - * @hide - */ - public int getAggressiveHandover() { - try { - return mService.getAggressiveHandover(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set setting for allowing Scans when traffic is ongoing. - * @hide - */ - public void setAllowScansWithTraffic(int enabled) { - try { - mService.setAllowScansWithTraffic(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get setting for allowing Scans when traffic is ongoing. - * @hide - */ - public int getAllowScansWithTraffic() { - try { - return mService.getAllowScansWithTraffic(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Resets all wifi manager settings back to factory defaults. + * Removes all saved wifi networks. * * @hide */ public void factoryReset() { try { - mService.factoryReset(); + mService.factoryReset(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3546,29 +3558,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 +3626,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..928a1da8b51c 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -160,6 +160,24 @@ public class WifiScanner { */ public static final int REPORT_EVENT_NO_BATCH = (1 << 2); + /** + * This is used to indicate the purpose of the scan to the wifi chip in + * {@link ScanSettings#type}. + * On devices with multiple hardware radio chains (and hence different modes of scan), + * this type serves as an indication to the hardware on what mode of scan to perform. + * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value. + * + * Note: This serves as an intent and not as a stipulation, the wifi chip + * might honor or ignore the indication based on the current radio conditions. Always + * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used + * to receive the corresponding scan result. + */ + /** {@hide} */ + public static final int TYPE_LOW_LATENCY = 0; + /** {@hide} */ + public static final int TYPE_LOW_POWER = 1; + /** {@hide} */ + public static final int TYPE_HIGH_ACCURACY = 2; /** {@hide} */ public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings"; @@ -193,7 +211,8 @@ public class WifiScanner { * list of hidden networks to scan for. Explicit probe requests are sent out for such * networks during scan. Only valid for single scan requests. * {@hide} - * */ + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public HiddenNetwork[] hiddenNetworks; /** period of background scan; in millisecond, 0 => single shot scan */ public int periodInMs; @@ -223,6 +242,13 @@ public class WifiScanner { * {@hide} */ public boolean isPnoScan; + /** + * Indicate the type of scan to be performed by the wifi chip. + * Default value: {@link #TYPE_LOW_LATENCY}. + * {@hide} + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public int type = TYPE_LOW_LATENCY; /** Implement the Parcelable interface {@hide} */ public int describeContents() { @@ -239,6 +265,7 @@ public class WifiScanner { dest.writeInt(maxPeriodInMs); dest.writeInt(stepCount); dest.writeInt(isPnoScan ? 1 : 0); + dest.writeInt(type); if (channels != null) { dest.writeInt(channels.length); for (int i = 0; i < channels.length; i++) { @@ -272,6 +299,7 @@ public class WifiScanner { settings.maxPeriodInMs = in.readInt(); settings.stepCount = in.readInt(); settings.isPnoScan = in.readInt() == 1; + settings.type = in.readInt(); int num_channels = in.readInt(); settings.channels = new ChannelSpec[num_channels]; for (int i = 0; i < num_channels; i++) { @@ -1105,8 +1133,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 +1141,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 +1375,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..699f54cf13fb 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -20,9 +20,10 @@ 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 com.android.internal.annotations.VisibleForTesting; + import dalvik.system.CloseGuard; import java.lang.ref.WeakReference; @@ -143,6 +144,34 @@ public class DiscoverySession implements AutoCloseable { } /** + * Access the client ID of the Aware session. + * + * Note: internal visibility for testing. + * + * @return The internal client ID. + * + * @hide + */ + @VisibleForTesting + public int getClientId() { + return mClientId; + } + + /** + * Access the discovery session ID of the Aware session. + * + * Note: internal visibility for testing. + * + * @return The internal discovery session ID. + * + * @hide + */ + @VisibleForTesting + public int getSessionId() { + return mSessionId; + } + + /** * Sends a message to the specified destination. Aware messages are transmitted in the context * of a discovery session - executed subsequent to a publish/subscribe * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, @@ -224,37 +253,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 @@ -278,8 +276,7 @@ public class DiscoverySession implements AutoCloseable { * or * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}. * On a RESPONDER this value is used to gate the acceptance of a connection - * request from only that peer. A RESPONDER may specify a {@code null} - - * indicating that it will accept connection requests from any device. + * request from only that peer. * * @return A {@link NetworkSpecifier} to be used to construct * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to @@ -287,7 +284,7 @@ public class DiscoverySession implements AutoCloseable { * android.net.ConnectivityManager.NetworkCallback)} * [or other varieties of that API]. */ - public NetworkSpecifier createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { + public NetworkSpecifier createNetworkSpecifierOpen(@NonNull PeerHandle peerHandle) { if (mTerminated) { Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session"); return null; @@ -327,8 +324,7 @@ public class DiscoverySession implements AutoCloseable { * byte[], java.util.List)} or * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request - * from only that peer. A RESPONDER may specify a {@code null} - indicating - * that it will accept connection requests from any device. + * from only that peer. * @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from * the passphrase. Use the * {@link #createNetworkSpecifierOpen(PeerHandle)} API to @@ -341,7 +337,7 @@ public class DiscoverySession implements AutoCloseable { * [or other varieties of that API]. */ public NetworkSpecifier createNetworkSpecifierPassphrase( - @Nullable PeerHandle peerHandle, @NonNull String passphrase) { + @NonNull PeerHandle peerHandle, @NonNull String passphrase) { if (!WifiAwareUtils.validatePassphrase(passphrase)) { throw new IllegalArgumentException("Passphrase must meet length requirements"); } @@ -386,8 +382,7 @@ public class DiscoverySession implements AutoCloseable { * byte[], java.util.List)} or * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request - * from only that peer. A RESPONDER may specify a null - indicating that - * it will accept connection requests from any device. + * from only that peer. * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for * encrypting the data-path. Use the * {@link #createNetworkSpecifierPassphrase(PeerHandle, String)} to specify a @@ -403,7 +398,7 @@ public class DiscoverySession implements AutoCloseable { * @hide */ @SystemApi - public NetworkSpecifier createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, + public NetworkSpecifier createNetworkSpecifierPmk(@NonNull PeerHandle peerHandle, @NonNull byte[] pmk) { if (!WifiAwareUtils.validatePmk(pmk)) { throw new IllegalArgumentException("PMK must 32 bytes"); diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java index 115b86d156e5..2052f155abee 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java @@ -113,6 +113,31 @@ 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. + */ + 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/IRttManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl index 383180995b21..0e7289cd9c46 100644 --- a/wifi/java/android/net/wifi/IRttManager.aidl +++ b/wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -14,15 +14,14 @@ * limitations under the License. */ -package android.net.wifi; -import android.os.Messenger; -import android.net.wifi.RttManager; +package android.net.wifi.aware; /** - * {@hide} + * Callback for IWifiAwareManager.getMacAddressFromPeerHandle + * + * @hide */ -interface IRttManager +oneway interface IWifiAwareMacAddressProvider { - Messenger getMessenger(in IBinder binder, out int[] key); - RttManager.RttCapabilities getRttCapabilities(); + 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..c4b24cfa2394 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 @@ -42,9 +42,9 @@ interface IWifiAwareManager in ConfigRequest configRequest, boolean notifyOnIdentityChanged); void disconnect(int clientId, in IBinder binder); - void publish(int clientId, in PublishConfig publishConfig, + void publish(in String callingPackage, int clientId, in PublishConfig publishConfig, in IWifiAwareDiscoverySessionCallback callback); - void subscribe(int clientId, in SubscribeConfig subscribeConfig, + void subscribe(in String callingPackage, int clientId, in SubscribeConfig subscribeConfig, in IWifiAwareDiscoverySessionCallback callback); // session API @@ -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..7a0250bf0700 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); } /** @@ -180,7 +182,7 @@ public final class PublishConfig implements Parcelable { * * @hide */ - public void assertValid(Characteristics characteristics) + public void assertValid(Characteristics characteristics, boolean rttSupported) throws IllegalArgumentException { WifiAwareUtils.validateServiceName(mServiceName); @@ -214,6 +216,10 @@ public final class PublishConfig implements Parcelable { "Match filter longer than supported by device characteristics"); } } + + if (!rttSupported && mEnableRanging) { + throw new IllegalArgumentException("Ranging is not supported"); + } } /** @@ -226,6 +232,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 +359,36 @@ 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. + * <p> + * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked + * as described in {@link android.net.wifi.rtt}. + * + * @param enable If true, ranging is supported on request of the peer. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + 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..2eab76a10cb4 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; } @@ -179,7 +224,7 @@ public final class SubscribeConfig implements Parcelable { * * @hide */ - public void assertValid(Characteristics characteristics) + public void assertValid(Characteristics characteristics, boolean rttSupported) throws IllegalArgumentException { WifiAwareUtils.validateServiceName(mServiceName); @@ -213,6 +258,21 @@ 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"); + } + + if (!rttSupported && (mMinDistanceMmSet || mMaxDistanceMmSet)) { + throw new IllegalArgumentException("Ranging is not supported"); + } } /** @@ -225,6 +285,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 +414,71 @@ 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. + * <p> + * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked + * as described in {@link android.net.wifi.rtt}. + * + * @param minDistanceMm Minimum distance, in mm, to the publisher above which to trigger + * discovery. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + 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. + * <p> + * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked + * as described in {@link android.net.wifi.rtt}. + * + * @param maxDistanceMm Maximum distance, in mm, to the publisher below which to trigger + * discovery. + * + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + 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..06a5c2e2710b 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; @@ -277,6 +269,10 @@ public class WifiAwareManager { + identityChangedListener); } + if (attachCallback == null) { + throw new IllegalArgumentException("Null callback provided"); + } + synchronized (mLock) { Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); @@ -308,8 +304,12 @@ public class WifiAwareManager { DiscoverySessionCallback callback) { if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig); + if (callback == null) { + throw new IllegalArgumentException("Null callback provided"); + } + try { - mService.publish(clientId, publishConfig, + mService.publish(mContext.getOpPackageName(), clientId, publishConfig, new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback, clientId)); } catch (RemoteException e) { @@ -341,8 +341,12 @@ public class WifiAwareManager { } } + if (callback == null) { + throw new IllegalArgumentException("Null callback provided"); + } + try { - mService.subscribe(clientId, subscribeConfig, + mService.subscribe(mContext.getOpPackageName(), clientId, subscribeConfig, new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback, clientId)); } catch (RemoteException e) { @@ -401,29 +405,8 @@ 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) { + @NonNull PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId + ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId) @@ -437,12 +420,9 @@ public class WifiAwareManager { "createNetworkSpecifier: Invalid 'role' argument when creating a network " + "specifier"); } - if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) { - if (peerHandle == null) { - throw new IllegalArgumentException( - "createNetworkSpecifier: Invalid peer handle (value of null) - not " - + "permitted on INITIATOR"); - } + if (peerHandle == null) { + throw new IllegalArgumentException( + "createNetworkSpecifier: Invalid peer handle - cannot be null"); } return new WifiAwareNetworkSpecifier( @@ -460,7 +440,7 @@ public class WifiAwareManager { /** @hide */ public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role, - @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { + @NonNull byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) { if (VDBG) { Log.v(TAG, "createNetworkSpecifier: role=" + role + ", pmk=" + ((pmk == null) ? "null" : "non-null") @@ -473,11 +453,9 @@ public class WifiAwareManager { "createNetworkSpecifier: Invalid 'role' argument when creating a network " + "specifier"); } - if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) { - if (peer == null) { - throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC " - + "address - null not permitted on INITIATOR"); - } + if (peer == null) { + throw new IllegalArgumentException( + "createNetworkSpecifier: Invalid peer MAC - cannot be null"); } if (peer != null && peer.length != 6) { throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address"); @@ -500,29 +478,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 +528,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 +559,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 +571,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 +626,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 +639,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 +701,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/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index f26b9f5aacfc..321965330e0b 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -25,6 +25,8 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import dalvik.system.CloseGuard; import java.lang.ref.WeakReference; @@ -97,6 +99,20 @@ public class WifiAwareSession implements AutoCloseable { } /** + * Access the client ID of the Aware session. + * + * Note: internal visibility for testing. + * + * @return The internal client ID. + * + * @hide + */ + @VisibleForTesting + public int getClientId() { + return mClientId; + } + + /** * Issue a request to the Aware service to create a new Aware publish discovery session, using * the specified {@code publishConfig} configuration. The results of the publish operation * are routed to the callbacks of {@link DiscoverySessionCallback}: @@ -207,8 +223,7 @@ public class WifiAwareSession implements AutoCloseable { * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this * value is used to gate the acceptance of a connection request from only that - * peer. A RESPONDER may specify a {@code null} - indicating that it will accept - * connection requests from any device. + * peer. * * @return A {@link NetworkSpecifier} to be used to construct * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to @@ -217,7 +232,7 @@ public class WifiAwareSession implements AutoCloseable { * [or other varieties of that API]. */ public NetworkSpecifier createNetworkSpecifierOpen( - @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer) { + @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager"); @@ -246,8 +261,7 @@ public class WifiAwareSession implements AutoCloseable { * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this * value is used to gate the acceptance of a connection request from only that - * peer. A RESPONDER may specify a {@code null} - indicating that it will accept - * connection requests from any device. + * peer. * @param passphrase The passphrase to be used to encrypt the link. The PMK is generated from * the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to * specify an open (unencrypted) link. @@ -259,7 +273,7 @@ public class WifiAwareSession implements AutoCloseable { * [or other varieties of that API]. */ public NetworkSpecifier createNetworkSpecifierPassphrase( - @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, + @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull String passphrase) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { @@ -293,8 +307,7 @@ public class WifiAwareSession implements AutoCloseable { * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER} * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this * value is used to gate the acceptance of a connection request from only that - * peer. A RESPONDER may specify a null - indicating that it will accept - * connection requests from any device. + * peer. * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for * encrypting the data-path. Use the * {@link #createNetworkSpecifierPassphrase(int, byte[], String)} to specify a @@ -311,7 +324,7 @@ public class WifiAwareSession implements AutoCloseable { */ @SystemApi public NetworkSpecifier createNetworkSpecifierPmk( - @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, @NonNull byte[] pmk) { + @WifiAwareManager.DataPathRole int role, @NonNull byte[] peer, @NonNull byte[] pmk) { WifiAwareManager mgr = mMgr.get(); if (mgr == null) { Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager"); 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..2ea6e797ec93 --- /dev/null +++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java @@ -0,0 +1,113 @@ +/* + * 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 reason code for Provisioning Failure due to connection failure to OSU AP. + * @hide + */ + public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; + + /** + * The reason code for Provisioning Failure due to connection failure to OSU AP. + * @hide + */ + public static final int OSU_FAILURE_SERVER_CONNECTION = 3; + + /** + * The reason code for Provisioning Failure due to connection failure to OSU AP. + * @hide + */ + public static final int OSU_FAILURE_SERVER_VALIDATION = 4; + + /** + * The reason code for Provisioning Failure due to connection failure to OSU AP. + * @hide + */ + public static final int OSU_FAILURE_PROVIDER_VERIFICATION = 5; + + /** + * The reason code for Provisioning Failure when a provisioning flow is aborted. + * @hide + */ + public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; + + /** + * The reason code for Provisioning Failure when a provisioning flow is aborted. + * @hide + */ + public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; + + /** + * 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; + + /** + * The status code for Provisioning flow to indicate connecting to OSU AP + * @hide + */ + public static final int OSU_STATUS_SERVER_CONNECTED = 3; + + /** + * The status code for Provisioning flow to indicate connecting to OSU AP + * @hide + */ + public static final int OSU_STATUS_SERVER_VALIDATED = 4; + + /** + * The status code for Provisioning flow to indicate connecting to OSU AP + * @hide + */ + public static final int OSU_STATUS_PROVIDER_VERIFIED = 5; + + /** + * 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/LocationCivic.java b/wifi/java/android/net/wifi/rtt/LocationCivic.java new file mode 100644 index 000000000000..610edb6399b4 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/LocationCivic.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018 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.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Location Civic Report (LCR). + * <p> + * The information matches the IEEE 802.11-2016 LCR report. + * <p> + * Note: depending on the mechanism by which this information is returned (i.e. the API which + * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case + * the information is NOT validated - use with caution. Consider validating it with other sources + * of information before using it. + */ +public final class LocationCivic implements Parcelable { + private final byte[] mData; + + /** + * Parse the raw LCR information element (byte array) and extract the LocationCivic structure. + * + * Note: any parsing errors or invalid/unexpected errors will result in a null being returned. + * + * @hide + */ + @Nullable + public static LocationCivic parseInformationElement(byte id, byte[] data) { + // TODO + return null; + } + + /** @hide */ + public LocationCivic(byte[] data) { + mData = data; + } + + /** + * Return the Location Civic data reported by the peer. + * + * @return An arbitrary location information. + */ + public byte[] getData() { + return mData; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(mData); + } + + public static final Parcelable.Creator<LocationCivic> CREATOR = + new Parcelable.Creator<LocationCivic>() { + @Override + public LocationCivic[] newArray(int size) { + return new LocationCivic[size]; + } + + @Override + public LocationCivic createFromParcel(Parcel in) { + byte[] data = in.createByteArray(); + + return new LocationCivic(data); + } + }; + + /** @hide */ + @Override + public String toString() { + return new StringBuilder("LCR: data=").append(Arrays.toString(mData)).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof LocationCivic)) { + return false; + } + + LocationCivic lhs = (LocationCivic) o; + + return Arrays.equals(mData, lhs.mData); + } + + @Override + public int hashCode() { + return Objects.hash(mData); + } +} diff --git a/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java b/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java new file mode 100644 index 000000000000..8aba56aa0ee7 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/LocationConfigurationInformation.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2018 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.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * The Device Location Configuration Information (LCI) specifies the location information of a peer + * device (e.g. an Access Point). + * <p> + * The information matches the IEEE 802.11-2016 LCI report (Location configuration information + * report). + * <p> + * Note: depending on the mechanism by which this information is returned (i.e. the API which + * returns an instance of this class) it is possibly Self Reported (by the peer). In such a case + * the information is NOT validated - use with caution. Consider validating it with other sources + * of information before using it. + */ +public final class LocationConfigurationInformation implements Parcelable { + /** @hide */ + @IntDef({ + ALTITUDE_UNKNOWN, ALTITUDE_IN_METERS, ALTITUDE_IN_FLOORS }) + @Retention(RetentionPolicy.SOURCE) + public @interface AltitudeTypes { + } + + /** + * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location + * does not specify an altitude or altitude uncertainty. The corresponding methods, + * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} are not valid and will throw + * an exception. + */ + public static final int ALTITUDE_UNKNOWN = 0; + + /** + * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the location + * specifies the altitude and altitude uncertainty in meters. The corresponding methods, + * {@link #getAltitude()} and {@link #getAltitudeUncertainty()} return a valid value in meters. + */ + public static final int ALTITUDE_IN_METERS = 1; + + /** + * Define an Altitude Type returned by {@link #getAltitudeType()}. Indicates that the + * location specifies the altitude in floors, and does not specify an altitude uncertainty. + * The {@link #getAltitude()} method returns valid value in floors, and the + * {@link #getAltitudeUncertainty()} method is not valid and will throw an exception. + */ + public static final int ALTITUDE_IN_FLOORS = 2; + + private final double mLatitude; + private final double mLatitudeUncertainty; + private final double mLongitude; + private final double mLongitudeUncertainty; + private final int mAltitudeType; + private final double mAltitude; + private final double mAltitudeUncertainty; + + /** + * Parse the raw LCI information element (byte array) and extract the + * LocationConfigurationInformation structure. + * + * Note: any parsing errors or invalid/unexpected errors will result in a null being returned. + * + * @hide + */ + @Nullable + public static LocationConfigurationInformation parseInformationElement(byte id, byte[] data) { + // TODO + return null; + } + + /** @hide */ + public LocationConfigurationInformation(double latitude, double latitudeUncertainty, + double longitude, double longitudeUncertainty, @AltitudeTypes int altitudeType, + double altitude, double altitudeUncertainty) { + mLatitude = latitude; + mLatitudeUncertainty = latitudeUncertainty; + mLongitude = longitude; + mLongitudeUncertainty = longitudeUncertainty; + mAltitudeType = altitudeType; + mAltitude = altitude; + mAltitudeUncertainty = altitudeUncertainty; + } + + /** + * Get latitude in degrees. Values are per WGS 84 reference system. Valid values are between + * -90 and 90. + * + * @return Latitude in degrees. + */ + public double getLatitude() { + return mLatitude; + } + + /** + * Get the uncertainty of the latitude {@link #getLatitude()} in degrees. A value of 0 indicates + * an unknown uncertainty. + * + * @return Uncertainty of the latitude in degrees. + */ + public double getLatitudeUncertainty() { + return mLatitudeUncertainty; + } + + /** + * Get longitude in degrees. Values are per WGS 84 reference system. Valid values are between + * -180 and 180. + * + * @return Longitude in degrees. + */ + public double getLongitude() { + return mLongitude; + } + + /** + * Get the uncertainty of the longitude {@link #getLongitude()} ()} in degrees. A value of 0 + * indicates an unknown uncertainty. + * + * @return Uncertainty of the longitude in degrees. + */ + public double getLongitudeUncertainty() { + return mLongitudeUncertainty; + } + + /** + * Specifies the type of the altitude measurement returned by {@link #getAltitude()} and + * {@link #getAltitudeUncertainty()}. The possible values are: + * <li>{@link #ALTITUDE_UNKNOWN}: The altitude and altitude uncertainty are not provided. + * <li>{@link #ALTITUDE_IN_METERS}: The altitude and altitude uncertainty are provided in + * meters. Values are per WGS 84 reference system. + * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors, the altitude uncertainty + * is not provided. + * + * @return The type of the altitude and altitude uncertainty. + */ + public @AltitudeTypes int getAltitudeType() { + return mAltitudeType; + } + + /** + * The altitude is interpreted according to the {@link #getAltitudeType()}. The possible values + * are: + * <li>{@link #ALTITUDE_UNKNOWN}: The altitude is not provided - this method will throw an + * exception. + * <li>{@link #ALTITUDE_IN_METERS}: The altitude is provided in meters. Values are per WGS 84 + * reference system. + * <li>{@link #ALTITUDE_IN_FLOORS}: The altitude is provided in floors. + * + * @return Altitude value whose meaning is specified by {@link #getAltitudeType()}. + */ + public double getAltitude() { + if (mAltitudeType == ALTITUDE_UNKNOWN) { + throw new IllegalStateException( + "getAltitude(): invoked on an invalid type: getAltitudeType()==UNKNOWN"); + } + return mAltitude; + } + + /** + * Only valid if the the {@link #getAltitudeType()} is equal to {@link #ALTITUDE_IN_METERS} - + * otherwise this method will throw an exception. + * <p> + * Get the uncertainty of the altitude {@link #getAltitude()} in meters. A value of 0 + * indicates an unknown uncertainty. + * + * @return Uncertainty of the altitude in meters. + */ + public double getAltitudeUncertainty() { + if (mAltitudeType != ALTITUDE_IN_METERS) { + throw new IllegalStateException( + "getAltitude(): invoked on an invalid type: getAltitudeType()!=IN_METERS"); + } + return mAltitudeUncertainty; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeDouble(mLatitude); + dest.writeDouble(mLatitudeUncertainty); + dest.writeDouble(mLongitude); + dest.writeDouble(mLongitudeUncertainty); + dest.writeInt(mAltitudeType); + dest.writeDouble(mAltitude); + dest.writeDouble(mAltitudeUncertainty); + } + + public static final Creator<LocationConfigurationInformation> CREATOR = + new Creator<LocationConfigurationInformation>() { + @Override + public LocationConfigurationInformation[] newArray(int size) { + return new LocationConfigurationInformation[size]; + } + + @Override + public LocationConfigurationInformation createFromParcel(Parcel in) { + double latitude = in.readDouble(); + double latitudeUnc = in.readDouble(); + double longitude = in.readDouble(); + double longitudeUnc = in.readDouble(); + int altitudeType = in.readInt(); + double altitude = in.readDouble(); + double altitudeUnc = in.readDouble(); + + return new LocationConfigurationInformation(latitude, latitudeUnc, longitude, + longitudeUnc, altitudeType, altitude, altitudeUnc); + } + }; + + /** @hide */ + @Override + public String toString() { + return new StringBuilder("LCI: latitude=").append(mLatitude).append( + ", latitudeUncertainty=").append(mLatitudeUncertainty).append( + ", longitude=").append(mLongitude).append(", longitudeUncertainty=").append( + mLongitudeUncertainty).append(", altitudeType=").append(mAltitudeType).append( + ", altitude=").append(mAltitude).append(", altitudeUncertainty=").append( + mAltitudeUncertainty).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof LocationConfigurationInformation)) { + return false; + } + + LocationConfigurationInformation lhs = (LocationConfigurationInformation) o; + + return mLatitude == lhs.mLatitude && mLatitudeUncertainty == lhs.mLatitudeUncertainty + && mLongitude == lhs.mLongitude + && mLongitudeUncertainty == lhs.mLongitudeUncertainty + && mAltitudeType == lhs.mAltitudeType && mAltitude == lhs.mAltitude + && mAltitudeUncertainty == lhs.mAltitudeUncertainty; + } + + @Override + public int hashCode() { + return Objects.hash(mLatitude, mLatitudeUncertainty, mLongitude, mLongitudeUncertainty, + mAltitudeType, mAltitude, mAltitudeUncertainty); + } +} diff --git a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl index 601facea37ba..8053c9416aeb 100644 --- a/wifi/java/android/net/wifi/WifiConnectionStatistics.aidl +++ b/wifi/java/android/net/wifi/rtt/RangingRequest.aidl @@ -1,19 +1,19 @@ -/** - * Copyright (c) 2014, The Android Open Source Project +/* + * 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 + * 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 + * 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 + * 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; +package android.net.wifi.rtt; -parcelable WifiConnectionStatistics; +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..52b3d8691c79 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java @@ -0,0 +1,256 @@ +/* + * 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.annotation.SystemApi; +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)}). + */ +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. + * <p> + * 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)}. + * <p> + * Note: in order to use this API the device must support Wi-Fi Aware + * {@link android.net.wifi.aware}. The peer device which is being ranged to must be + * configured to publish a service (with any name) with: + * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}. + * <li>Ranging enabled + * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}. + * + * @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. + * <p> + * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g. + * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}. + * <p> + * Note: in order to use this API the device must support Wi-Fi Aware + * {@link android.net.wifi.aware}. The peer device which is being ranged to must be + * configured to publish a service (with any name) with: + * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}. + * <li>Ranging enabled + * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}. + * + * @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..f7c85671c220 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingResult.java @@ -0,0 +1,354 @@ +/* + * 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.annotation.Nullable; +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}. + */ +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; + + /** + * Individual range request status, {@link #getStatus()}. Indicates that the ranging operation + * failed because the specified peer does not support IEEE 802.11mc RTT operations. Support by + * an Access Point can be confirmed using + * {@link android.net.wifi.ScanResult#is80211mcResponder()}. + * <p> + * On such a failure, the individual result fields of {@link RangingResult} such as + * {@link RangingResult#getDistanceMm()} are invalid. + * + * @hide + */ + public static final int STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC = 2; + + 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 LocationConfigurationInformation mLci; + private final LocationCivic mLcr; + private final long mTimestamp; + + /** @hide */ + public RangingResult(@RangeResultStatus int status, @NonNull MacAddress mac, int distanceMm, + int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr, + long timestamp) { + mStatus = status; + mMac = mac; + mPeerHandle = null; + mDistanceMm = distanceMm; + mDistanceStdDevMm = distanceStdDevMm; + mRssi = rssi; + mLci = lci; + mLcr = lcr; + mTimestamp = timestamp; + } + + /** @hide */ + public RangingResult(@RangeResultStatus int status, PeerHandle peerHandle, int distanceMm, + int distanceStdDevMm, int rssi, LocationConfigurationInformation lci, LocationCivic lcr, + long timestamp) { + mStatus = status; + mMac = null; + mPeerHandle = peerHandle; + mDistanceMm = distanceMm; + mDistanceStdDevMm = distanceStdDevMm; + mRssi = rssi; + mLci = lci; + mLcr = lcr; + 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. + */ + @Nullable + 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. + */ + @Nullable 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 Location Configuration Information (LCI) as self-reported by the peer. + * <p> + * Note: the information is NOT validated - use with caution. Consider validating it with + * other sources of information before using it. + */ + @Nullable + public LocationConfigurationInformation getReportedLocationConfigurationInformation() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getReportedLocationConfigurationInformation(): invoked on an invalid result: " + + "getStatus()=" + mStatus); + } + return mLci; + } + + /** + * @return The Location Civic report (LCR) as self-reported by the peer. + * <p> + * Note: the information is NOT validated - use with caution. Consider validating it with + * other sources of information before using it. + */ + @Nullable + public LocationCivic getReportedLocationCivic() { + if (mStatus != STATUS_SUCCESS) { + throw new IllegalStateException( + "getReportedLocationCivic(): invoked on an invalid result: getStatus()=" + + mStatus); + } + return mLcr; + } + + /** + * @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; + } + + @Override + public int describeContents() { + return 0; + } + + @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); + if (mLci == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + mLci.writeToParcel(dest, flags); + } + if (mLcr == null) { + dest.writeBoolean(false); + } else { + dest.writeBoolean(true); + mLcr.writeToParcel(dest, flags); + } + dest.writeLong(mTimestamp); + } + + 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(); + boolean lciPresent = in.readBoolean(); + LocationConfigurationInformation lci = null; + if (lciPresent) { + lci = LocationConfigurationInformation.CREATOR.createFromParcel(in); + } + boolean lcrPresent = in.readBoolean(); + LocationCivic lcr = null; + if (lcrPresent) { + lcr = LocationCivic.CREATOR.createFromParcel(in); + } + long timestamp = in.readLong(); + if (peerHandlePresent) { + return new RangingResult(status, peerHandle, distanceMm, distanceStdDevMm, rssi, + lci, lcr, timestamp); + } else { + return new RangingResult(status, mac, distanceMm, distanceStdDevMm, rssi, + lci, lcr, 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(", lci=").append(mLci).append(", lcr=").append( + mLcr).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 + && Objects.equals(mLci, lhs.mLci) && Objects.equals(mLcr, lhs.mLcr) + && mTimestamp == lhs.mTimestamp; + } + + @Override + public int hashCode() { + return Objects.hash(mStatus, mMac, mPeerHandle, mDistanceMm, mDistanceStdDevMm, mRssi, + mLci, mLcr, 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..9639dc803a7d --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/RangingResultCallback.java @@ -0,0 +1,71 @@ +/* + * 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.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()}. + */ +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(@NonNull 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..fb723c594e15 --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/ResponderConfig.java @@ -0,0 +1,476 @@ +/* + * 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.annotation.SystemApi; +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 final 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. + */ + public final 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 final 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, using a MAC address to identify the Responder. + * + * @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, using a Wi-Fi Aware PeerHandle to identify the Responder. + * + * @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; + } + + /** + * Constructs Responder configuration. This is an internal-only constructor which specifies both + * a MAC address and a Wi-Fi PeerHandle to identify the Responder. + * + * @param macAddress The MAC address of the Responder. + * @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}. + * @hide + */ + public ResponderConfig(@NonNull MacAddress macAddress, @NonNull PeerHandle peerHandle, + @ResponderType int responderType, boolean supports80211mc, + @ChannelWidth int channelWidth, int frequency, int centerFreq0, int centerFreq1, + @PreambleType int preamble) { + this.macAddress = macAddress; + 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 = translateScanResultChannelWidth(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 translateScanResultChannelWidth(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( + "translateScanResultChannelWidth: 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..ec6c46ec4a7d --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 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 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.NonNull; +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. + */ +@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. + * <p>Note: availability of RTT does not mean that the app can use the API. The app's + * permissions and platform Location Mode are validated at run-time. + * + * @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(@NonNull RangingRequest request, + @NonNull 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, @NonNull RangingRequest request, + @NonNull RangingResultCallback callback, @Nullable Handler handler) { + if (VDBG) { + Log.v(TAG, "startRanging: workSource=" + workSource + ", request=" + request + + ", callback=" + callback + ", handler=" + handler); + } + + if (callback == null) { + throw new IllegalArgumentException("Null callback provided"); + } + + 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(@Nullable 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..11ac05800a7c --- /dev/null +++ b/wifi/java/android/net/wifi/rtt/package.html @@ -0,0 +1,41 @@ +<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>Usage of the API is also gated by the device's Location Mode: whether it permits Wi-Fi based +location to be queried.</p> + +<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> |