diff options
Diffstat (limited to 'wifi')
27 files changed, 2251 insertions, 1743 deletions
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 9268a2b7cbe2..3674f0f4baa7 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -169,5 +169,11 @@ interface IWifiManager void factoryReset(); Network getCurrentNetwork(); + + byte[] retrieveBackupData(); + + void restoreBackupData(in byte[] data); + + void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData); } diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl index 5c6d44710ea5..9479cf0b936e 100644 --- a/wifi/java/android/net/wifi/RttManager.aidl +++ b/wifi/java/android/net/wifi/RttManager.aidl @@ -15,4 +15,7 @@ */ package android.net.wifi; -parcelable RttManager.RttCapabilities;
\ No newline at end of file + +parcelable RttManager.RttCapabilities; +parcelable RttManager.ParcelableRttResults; +parcelable RttManager.ParcelableRttParams; diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 590ff1b1bfaa..ff632a5cdc7c 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -472,6 +472,34 @@ public class RttManager { preamble = PREAMBLE_HT; bandwidth = RTT_BW_20_SUPPORT; } + + /** + * {@hide} + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("deviceType=" + deviceType); + sb.append(", requestType=" + requestType); + sb.append(", secure=" + secure); + sb.append(", bssid=" + bssid); + sb.append(", frequency=" + frequency); + sb.append(", channelWidth=" + channelWidth); + sb.append(", centerFreq0=" + centerFreq0); + sb.append(", centerFreq1=" + centerFreq1); + sb.append(", num_samples=" + num_samples); + sb.append(", num_retries=" + num_retries); + sb.append(", numberBurst=" + numberBurst); + sb.append(", interval=" + interval); + sb.append(", numSamplesPerBurst=" + numSamplesPerBurst); + sb.append(", numRetriesPerMeasurementFrame=" + numRetriesPerMeasurementFrame); + sb.append(", numRetriesPerFTMR=" + numRetriesPerFTMR); + sb.append(", LCIRequest=" + LCIRequest); + sb.append(", LCRRequest=" + LCRRequest); + sb.append(", burstTimeout=" + burstTimeout); + sb.append(", preamble=" + preamble); + sb.append(", bandwidth=" + bandwidth); + return sb.toString(); + } } /** pseudo-private class used to parcel arguments */ @@ -727,6 +755,51 @@ public class RttManager { mResults = results; } + /** + * {@hide} + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < mResults.length; ++i) { + sb.append("[" + i + "]: "); + sb.append("bssid=" + mResults[i].bssid); + sb.append(", burstNumber=" + mResults[i].burstNumber); + sb.append(", measurementFrameNumber=" + mResults[i].measurementFrameNumber); + sb.append(", successMeasurementFrameNumber=" + + mResults[i].successMeasurementFrameNumber); + sb.append(", frameNumberPerBurstPeer=" + mResults[i].frameNumberPerBurstPeer); + sb.append(", status=" + mResults[i].status); + sb.append(", requestType=" + mResults[i].requestType); + sb.append(", measurementType=" + mResults[i].measurementType); + sb.append(", retryAfterDuration=" + mResults[i].retryAfterDuration); + sb.append(", ts=" + mResults[i].ts); + sb.append(", rssi=" + mResults[i].rssi); + sb.append(", rssi_spread=" + mResults[i].rssi_spread); + sb.append(", rssiSpread=" + mResults[i].rssiSpread); + sb.append(", tx_rate=" + mResults[i].tx_rate); + sb.append(", txRate=" + mResults[i].txRate); + sb.append(", rxRate=" + mResults[i].rxRate); + sb.append(", rtt_ns=" + mResults[i].rtt_ns); + sb.append(", rtt=" + mResults[i].rtt); + sb.append(", rtt_sd_ns=" + mResults[i].rtt_sd_ns); + sb.append(", rttStandardDeviation=" + mResults[i].rttStandardDeviation); + sb.append(", rtt_spread_ns=" + mResults[i].rtt_spread_ns); + sb.append(", rttSpread=" + mResults[i].rttSpread); + sb.append(", distance_cm=" + mResults[i].distance_cm); + sb.append(", distance=" + mResults[i].distance); + sb.append(", distance_sd_cm=" + mResults[i].distance_sd_cm); + sb.append(", distanceStandardDeviation=" + mResults[i].distanceStandardDeviation); + sb.append(", distance_spread_cm=" + mResults[i].distance_spread_cm); + sb.append(", distanceSpread=" + mResults[i].distanceSpread); + sb.append(", burstDuration=" + mResults[i].burstDuration); + sb.append(", negotiatedBurstNum=" + mResults[i].negotiatedBurstNum); + sb.append(", LCI=" + mResults[i].LCI); + sb.append(", LCR=" + mResults[i].LCR); + sb.append(", secure=" + mResults[i].secure); + } + return sb.toString(); + } + /** Implement the Parcelable interface {@hide} */ @Override public int describeContents() { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 9d0c20ce4c5d..3bf88b79b8a1 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -837,25 +837,33 @@ public class WifiConfiguration implements Parcelable { */ public static final int DISABLED_DNS_FAILURE = 5; /** + * This network is disabled because we started WPS + */ + public static final int DISABLED_WPS_START = 6; + /** * This network is disabled because EAP-TLS failure */ - public static final int DISABLED_TLS_VERSION_MISMATCH = 6; + public static final int DISABLED_TLS_VERSION_MISMATCH = 7; /** - * This network is disabled due to WifiManager disable it explicitly + * This network is disabled due to absence of user credentials */ - public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 7; + public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 8; /** * This network is disabled because no Internet connected and user do not want */ - public static final int DISABLED_NO_INTERNET = 8; + public static final int DISABLED_NO_INTERNET = 9; /** * This network is disabled due to WifiManager disable it explicitly */ - public static final int DISABLED_BY_WIFI_MANAGER = 9; + public static final int DISABLED_BY_WIFI_MANAGER = 10; + /** + * This network is disabled due to user switching + */ + public static final int DISABLED_DUE_TO_USER_SWITCH = 11; /** * This Maximum disable reason value */ - public static final int NETWORK_SELECTION_DISABLED_MAX = 10; + public static final int NETWORK_SELECTION_DISABLED_MAX = 12; /** * Quality network selection disable reason String (for debug purpose) @@ -867,10 +875,13 @@ public class WifiConfiguration implements Parcelable { "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE", "NETWORK_SELECTION_DISABLED_DHCP_FAILURE", "NETWORK_SELECTION_DISABLED_DNS_FAILURE", + "NETWORK_SELECTION_DISABLED_WPS_START", "NETWORK_SELECTION_DISABLED_TLS_VERSION", "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS", "NETWORK_SELECTION_DISABLED_NO_INTERNET", - "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER"}; + "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER", + "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH" + }; /** * Invalid time stamp for network selection disable @@ -1054,7 +1065,7 @@ public class WifiConfiguration implements Parcelable { return mHasEverConnected; } - private NetworkSelectionStatus() { + public NetworkSelectionStatus() { // previously stored configs will not have this parameter, so we default to false. mHasEverConnected = false; }; @@ -1302,7 +1313,7 @@ public class WifiConfiguration implements Parcelable { * @hide * network selection related member */ - private final NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus(); + private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus(); /** * @hide @@ -1311,6 +1322,15 @@ public class WifiConfiguration implements Parcelable { public NetworkSelectionStatus getNetworkSelectionStatus() { return mNetworkSelectionStatus; } + + /** + * Set the network selection status + * @hide + */ + public void setNetworkSelectionStatus(NetworkSelectionStatus status) { + mNetworkSelectionStatus = status; + } + /** * @hide * Linked Configurations: represent the set of Wificonfigurations that are equivalent diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index bbc3d2fd5927..6cf1921524b3 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2737,4 +2737,41 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } + + /** + * Retrieve the data to be backed to save the current state. + * @hide + */ + public byte[] retrieveBackupData() { + try { + return mService.retrieveBackupData(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Restore state from the backed up data. + * @hide + */ + public void restoreBackupData(byte[] data) { + try { + mService.restoreBackupData(data); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Restore state from the older version of back up data. + * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file. + * @hide + */ + public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { + try { + mService.restoreSupplicantBackupData(supplicantData, ipConfigData); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/wifi/java/android/net/wifi/nan/ConfigRequest.java b/wifi/java/android/net/wifi/nan/ConfigRequest.java index 23e37547b9f0..759098e9b0c2 100644 --- a/wifi/java/android/net/wifi/nan/ConfigRequest.java +++ b/wifi/java/android/net/wifi/nan/ConfigRequest.java @@ -22,9 +22,10 @@ import android.os.Parcelable; /** * Defines a request object to configure a Wi-Fi NAN network. Built using * {@link ConfigRequest.Builder}. Configuration is requested using - * {@link WifiNanManager#requestConfig(ConfigRequest)}. Note that the actual - * achieved configuration may be different from the requested configuration - - * since multiple applications may request different configurations. + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)} + * . Note that the actual achieved configuration may be different from the + * requested configuration - since multiple applications may request different + * configurations. * * @hide PROPOSED_NAN_API */ @@ -73,19 +74,28 @@ public class ConfigRequest implements Parcelable { */ public final int mClusterHigh; + /** + * Indicates whether we want to get callbacks when our identity is changed. + * + * @hide + */ + public final boolean mEnableIdentityChangeCallback; + private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow, - int clusterHigh) { + int clusterHigh, boolean enableIdentityChangeCallback) { mSupport5gBand = support5gBand; mMasterPreference = masterPreference; mClusterLow = clusterLow; mClusterHigh = clusterHigh; + mEnableIdentityChangeCallback = enableIdentityChangeCallback; } @Override public String toString() { return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference=" + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh=" - + mClusterHigh + "]"; + + mClusterHigh + ", mEnableIdentityChangeCallback=" + mEnableIdentityChangeCallback + + "]"; } @Override @@ -99,6 +109,7 @@ public class ConfigRequest implements Parcelable { dest.writeInt(mMasterPreference); dest.writeInt(mClusterLow); dest.writeInt(mClusterHigh); + dest.writeInt(mEnableIdentityChangeCallback ? 1 : 0); } public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() { @@ -113,7 +124,9 @@ public class ConfigRequest implements Parcelable { int masterPreference = in.readInt(); int clusterLow = in.readInt(); int clusterHigh = in.readInt(); - return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh); + boolean enableIdentityChangeCallback = in.readInt() != 0; + return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh, + enableIdentityChangeCallback); } }; @@ -130,6 +143,31 @@ public class ConfigRequest implements Parcelable { ConfigRequest lhs = (ConfigRequest) o; return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference + && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh + && mEnableIdentityChangeCallback == lhs.mEnableIdentityChangeCallback; + } + + /** + * Checks for equality of two configuration - but only considering their + * on-the-air NAN configuration impact. + * + * @param o Object to compare to. + * @return true if configuration objects have the same on-the-air + * configuration, false otherwise. + * @hide + */ + public boolean equalsOnTheAir(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof ConfigRequest)) { + return false; + } + + ConfigRequest lhs = (ConfigRequest) o; + + return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh; } @@ -141,28 +179,53 @@ public class ConfigRequest implements Parcelable { result = 31 * result + mMasterPreference; result = 31 * result + mClusterLow; result = 31 * result + mClusterHigh; + result = 31 * result + (mEnableIdentityChangeCallback ? 1 : 0); return result; } /** + * Validates that the contents of the ConfigRequest are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mMasterPreference < 0) { + throw new IllegalArgumentException( + "Master Preference specification must be non-negative"); + } + if (mMasterPreference == 1 || mMasterPreference == 255 || mMasterPreference > 255) { + throw new IllegalArgumentException("Master Preference specification must not " + + "exceed 255 or use 1 or 255 (reserved values)"); + } + if (mClusterLow < CLUSTER_ID_MIN) { + throw new IllegalArgumentException("Cluster specification must be non-negative"); + } + if (mClusterLow > CLUSTER_ID_MAX) { + throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); + } + if (mClusterHigh < CLUSTER_ID_MIN) { + throw new IllegalArgumentException("Cluster specification must be non-negative"); + } + if (mClusterHigh > CLUSTER_ID_MAX) { + throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF"); + } + if (mClusterLow > mClusterHigh) { + throw new IllegalArgumentException( + "Invalid argument combination - must have Cluster Low <= Cluster High"); + } + } + + /** * Builder used to build {@link ConfigRequest} objects. */ public static final class Builder { - private boolean mSupport5gBand; - private int mMasterPreference; - private int mClusterLow; - private int mClusterHigh; - - /** - * Default constructor for the Builder. - */ - public Builder() { - mSupport5gBand = false; - mMasterPreference = 0; - mClusterLow = 0; - mClusterHigh = CLUSTER_ID_MAX; - } + private boolean mSupport5gBand = false; + private int mMasterPreference = 0; + private int mClusterLow = CLUSTER_ID_MIN; + private int mClusterHigh = CLUSTER_ID_MAX; + private boolean mEnableIdentityChangeCallback = false; /** * Specify whether 5G band support is required in this request. @@ -170,6 +233,7 @@ public class ConfigRequest implements Parcelable { * @param support5gBand Support for 5G band is required. * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setSupport5gBand(boolean support5gBand) { mSupport5gBand = support5gBand; @@ -183,6 +247,7 @@ public class ConfigRequest implements Parcelable { * @param masterPreference The requested master preference * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setMasterPreference(int masterPreference) { if (masterPreference < 0) { @@ -209,6 +274,7 @@ public class ConfigRequest implements Parcelable { * @param clusterLow The lower range of the generated cluster ID. * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setClusterLow(int clusterLow) { if (clusterLow < CLUSTER_ID_MIN) { @@ -233,6 +299,7 @@ public class ConfigRequest implements Parcelable { * @param clusterHigh The upper range of the generated cluster ID. * @return The builder to facilitate chaining * {@code builder.setClusterLow(..).setClusterHigh(..)}. + * @hide PROPOSED_NAN_SYSTEM_API */ public Builder setClusterHigh(int clusterHigh) { if (clusterHigh < CLUSTER_ID_MIN) { @@ -247,6 +314,25 @@ public class ConfigRequest implements Parcelable { } /** + * Indicate whether or not we want to enable the callback to the + * listener on the event when the NAN device identity is changed. A + * device identity is it's Discovery MAC address. Depending on use-case + * we may want to perform some activity (e.g. re-publish). In other + * use-cases (typically where we're silent) there's no reason to be + * woken up repeatedly. Note that the MAC address is randomized at + * regular intervals - so do not enable unless specifically required. + * + * @param enableIdentityChangeCallback Enable the callback informing + * listener when identity is changed. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setEnableIdentityChangeCallback(boolean enableIdentityChangeCallback) { + mEnableIdentityChangeCallback = enableIdentityChangeCallback; + return this; + } + + /** * Build {@link ConfigRequest} given the current requests made on the * builder. */ @@ -256,7 +342,8 @@ public class ConfigRequest implements Parcelable { "Invalid argument combination - must have Cluster Low <= Cluster High"); } - return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh); + return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh, + mEnableIdentityChangeCallback); } } } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl index fa666afd1c27..b95140e88ae7 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl @@ -17,16 +17,20 @@ package android.net.wifi.nan; import android.net.wifi.nan.ConfigRequest; +import android.net.wifi.RttManager; /** * Callback interface that WifiNanManager implements * * {@hide} */ -oneway interface IWifiNanEventListener +oneway interface IWifiNanEventCallback { - void onConfigCompleted(in ConfigRequest completedConfig); - void onConfigFailed(in ConfigRequest failedConfig, int reason); - void onNanDown(int reason); + void onConnectSuccess(); + void onConnectFail(int reason); void onIdentityChanged(); + + 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/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl index f382d97762d3..efa6211a8063 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl @@ -19,12 +19,11 @@ package android.net.wifi.nan; import android.app.PendingIntent; import android.net.wifi.nan.ConfigRequest; -import android.net.wifi.nan.IWifiNanEventListener; -import android.net.wifi.nan.IWifiNanSessionListener; -import android.net.wifi.nan.PublishData; -import android.net.wifi.nan.PublishSettings; -import android.net.wifi.nan.SubscribeData; -import android.net.wifi.nan.SubscribeSettings; +import android.net.wifi.nan.IWifiNanEventCallback; +import android.net.wifi.nan.IWifiNanSessionCallback; +import android.net.wifi.nan.PublishConfig; +import android.net.wifi.nan.SubscribeConfig; +import android.net.wifi.RttManager; /** * Interface that WifiNanService implements @@ -33,18 +32,25 @@ import android.net.wifi.nan.SubscribeSettings; */ interface IWifiNanManager { + // NAN API + void enableUsage(); + void disableUsage(); + boolean isUsageEnabled(); + // client API - void connect(in IBinder binder, in IWifiNanEventListener listener, int events); - void disconnect(in IBinder binder); - void requestConfig(in ConfigRequest configRequest); + int connect(in IBinder binder, in IWifiNanEventCallback callback, + in ConfigRequest configRequest); + void disconnect(int clientId, in IBinder binder); + + void publish(int clientId, in PublishConfig publishConfig, in IWifiNanSessionCallback callback); + void subscribe(int clientId, in SubscribeConfig subscribeConfig, + in IWifiNanSessionCallback callback); // session API - int createSession(in IWifiNanSessionListener listener, int events); - void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings); - void subscribe(int sessionId, in SubscribeData subscribeData, - in SubscribeSettings subscribeSettings); - void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength, - int messageId); - void stopSession(int sessionId); - void destroySession(int sessionId); + void updatePublish(int clientId, int sessionId, in PublishConfig publishConfig); + void updateSubscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig); + void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageLength, + int messageId, int retryCount); + void terminateSession(int clientId, int sessionId); + int startRanging(int clientId, int sessionId, in RttManager.ParcelableRttParams parms); } diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl index d60d8caae70e..7162be72a3c5 100644 --- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl +++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl @@ -21,13 +21,12 @@ package android.net.wifi.nan; * * {@hide} */ -oneway interface IWifiNanSessionListener +oneway interface IWifiNanSessionCallback { - void onPublishFail(int reason); - void onPublishTerminated(int reason); - - void onSubscribeFail(int reason); - void onSubscribeTerminated(int reason); + void onSessionStarted(int sessionId); + void onSessionConfigSuccess(); + void onSessionConfigFail(int reason); + void onSessionTerminated(int reason); void onMatch(int peerId, in byte[] serviceSpecificInfo, int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength); diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.aidl b/wifi/java/android/net/wifi/nan/PublishConfig.aidl index 662fdb83f74c..5f66d168a1da 100644 --- a/wifi/java/android/net/wifi/nan/SubscribeData.aidl +++ b/wifi/java/android/net/wifi/nan/PublishConfig.aidl @@ -16,4 +16,4 @@ package android.net.wifi.nan; -parcelable SubscribeData; +parcelable PublishConfig; diff --git a/wifi/java/android/net/wifi/nan/PublishData.java b/wifi/java/android/net/wifi/nan/PublishConfig.java index 80119eb0f4fd..d7cba8fcdfb3 100644 --- a/wifi/java/android/net/wifi/nan/PublishData.java +++ b/wifi/java/android/net/wifi/nan/PublishConfig.java @@ -16,19 +16,45 @@ package android.net.wifi.nan; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * Defines the data for a NAN publish session. Built using - * {@link PublishData.Builder}. Publish is done using - * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)} - * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}. + * Defines the configuration of a NAN publish session. Built using + * {@link PublishConfig.Builder}. Publish is done using + * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or + * {@link WifiNanPublishSession#updatePublish(PublishConfig)}. + * * @hide PROPOSED_NAN_API */ -public class PublishData implements Parcelable { +public class PublishConfig implements Parcelable { + @IntDef({ + PUBLISH_TYPE_UNSOLICITED, PUBLISH_TYPE_SOLICITED }) + @Retention(RetentionPolicy.SOURCE) + public @interface PublishTypes { + } + + /** + * Defines an unsolicited publish session - i.e. a publish session where + * publish packets are transmitted over-the-air. Configuration is done using + * {@link PublishConfig.Builder#setPublishType(int)}. + */ + public static final int PUBLISH_TYPE_UNSOLICITED = 0; + + /** + * Defines a solicited publish session - i.e. a publish session where + * publish packets are not transmitted over-the-air and the device listens + * and matches to transmitted subscribe packets. Configuration is done using + * {@link PublishConfig.Builder#setPublishType(int)}. + */ + public static final int PUBLISH_TYPE_SOLICITED = 1; + /** * @hide */ @@ -64,9 +90,30 @@ public class PublishData implements Parcelable { */ public final byte[] mRxFilter; - private PublishData(String serviceName, byte[] serviceSpecificInfo, + /** + * @hide + */ + public final int mPublishType; + + /** + * @hide + */ + public final int mPublishCount; + + /** + * @hide + */ + public final int mTtlSec; + + /** + * @hide + */ + public final boolean mEnableTerminateNotification; + + private PublishConfig(String serviceName, byte[] serviceSpecificInfo, int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter, - int rxFilterLength) { + int rxFilterLength, int publishType, int publichCount, int ttlSec, + boolean enableTerminateNotification) { mServiceName = serviceName; mServiceSpecificInfoLength = serviceSpecificInfoLength; mServiceSpecificInfo = serviceSpecificInfo; @@ -74,17 +121,23 @@ public class PublishData implements Parcelable { mTxFilter = txFilter; mRxFilterLength = rxFilterLength; mRxFilter = rxFilter; + mPublishType = publishType; + mPublishCount = publichCount; + mTtlSec = ttlSec; + mEnableTerminateNotification = enableTerminateNotification; } @Override public String toString() { - return "PublishData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='" + return "PublishConfig [mServiceName='" + mServiceName + "', mServiceSpecificInfo='" + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength)) + "', mTxFilter=" + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString() + ", mRxFilter=" + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString() - + "']"; + + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount + + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification=" + + mEnableTerminateNotification + "]"; } @Override @@ -92,7 +145,6 @@ public class PublishData implements Parcelable { return 0; } - @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mServiceName); @@ -108,16 +160,20 @@ public class PublishData implements Parcelable { if (mRxFilterLength != 0) { dest.writeByteArray(mRxFilter, 0, mRxFilterLength); } + dest.writeInt(mPublishType); + dest.writeInt(mPublishCount); + dest.writeInt(mTtlSec); + dest.writeInt(mEnableTerminateNotification ? 1 : 0); } - public static final Creator<PublishData> CREATOR = new Creator<PublishData>() { + public static final Creator<PublishConfig> CREATOR = new Creator<PublishConfig>() { @Override - public PublishData[] newArray(int size) { - return new PublishData[size]; + public PublishConfig[] newArray(int size) { + return new PublishConfig[size]; } @Override - public PublishData createFromParcel(Parcel in) { + public PublishConfig createFromParcel(Parcel in) { String serviceName = in.readString(); int ssiLength = in.readInt(); byte[] ssi = new byte[ssiLength]; @@ -134,9 +190,14 @@ public class PublishData implements Parcelable { if (rxFilterLength != 0) { in.readByteArray(rxFilter); } - - return new PublishData(serviceName, ssi, ssiLength, txFilter, txFilterLength, rxFilter, - rxFilterLength); + int publishType = in.readInt(); + int publishCount = in.readInt(); + int ttlSec = in.readInt(); + boolean enableTerminateNotification = in.readInt() != 0; + + return new PublishConfig(serviceName, ssi, ssiLength, txFilter, txFilterLength, + rxFilter, rxFilterLength, publishType, publishCount, ttlSec, + enableTerminateNotification); } }; @@ -146,11 +207,11 @@ public class PublishData implements Parcelable { return true; } - if (!(o instanceof PublishData)) { + if (!(o instanceof PublishConfig)) { return false; } - PublishData lhs = (PublishData) o; + PublishConfig lhs = (PublishConfig) o; if (!mServiceName.equals(lhs.mServiceName) || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength @@ -189,7 +250,9 @@ public class PublishData implements Parcelable { return false; // invalid != invalid } - return true; + return mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount + && mTtlSec == lhs.mTtlSec + && mEnableTerminateNotification == lhs.mEnableTerminateNotification; } @Override @@ -203,12 +266,55 @@ public class PublishData implements Parcelable { result = 31 * result + Arrays.hashCode(mTxFilter); result = 31 * result + mRxFilterLength; result = 31 * result + Arrays.hashCode(mRxFilter); + result = 31 * result + mPublishType; + result = 31 * result + mPublishCount; + result = 31 * result + mTtlSec; + result = 31 * result + (mEnableTerminateNotification ? 1 : 0); return result; } /** - * Builder used to build {@link PublishData} objects. + * Validates that the contents of the PublishConfig are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null + || mServiceSpecificInfo.length < mServiceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } + if (mTxFilterLength != 0 && (mTxFilter == null || mTxFilter.length < mTxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } + if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } + if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) { + throw new IllegalArgumentException("Invalid publishType - " + mPublishType); + } + if (mPublishCount < 0) { + throw new IllegalArgumentException("Invalid publishCount - must be non-negative"); + } + if (mTtlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + if (mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED && mRxFilterLength != 0) { + throw new IllegalArgumentException("Invalid publish config: UNSOLICITED " + + "publishes (active) can't have an Rx filter"); + } + if (mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED && mTxFilterLength != 0) { + throw new IllegalArgumentException("Invalid publish config: SOLICITED " + + "publishes (passive) can't have a Tx filter"); + } + } + + /** + * Builder used to build {@link PublishConfig} objects. */ public static final class Builder { private String mServiceName; @@ -218,6 +324,10 @@ public class PublishData implements Parcelable { private byte[] mTxFilter = new byte[0]; private int mRxFilterLength; private byte[] mRxFilter = new byte[0]; + private int mPublishType = PUBLISH_TYPE_UNSOLICITED; + private int mPublishCount = 0; + private int mTtlSec = 0; + private boolean mEnableTerminateNotification = true; /** * Specify the service name of the publish session. The actual on-air @@ -227,7 +337,7 @@ public class PublishData implements Parcelable { * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. */ - public Builder setServiceName(String serviceName) { + public Builder setServiceName(@NonNull String serviceName) { mServiceName = serviceName; return this; } @@ -260,7 +370,7 @@ public class PublishData implements Parcelable { /** * Specify service specific information for the publish session - same - * as {@link PublishData.Builder#setServiceSpecificInfo(byte[], int)} + * as {@link PublishConfig.Builder#setServiceSpecificInfo(byte[], int)} * but obtaining the data from a String. * * @param serviceSpecificInfoStr The service specific information string @@ -269,7 +379,7 @@ public class PublishData implements Parcelable { * @return The builder to facilitate chaining * {@code builder.setXXX(..).setXXX(..)}. */ - public Builder setServiceSpecificInfo(String serviceSpecificInfoStr) { + public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) { mServiceSpecificInfoLength = serviceSpecificInfoStr.length(); mServiceSpecificInfo = serviceSpecificInfoStr.getBytes(); return this; @@ -277,8 +387,8 @@ public class PublishData implements Parcelable { /** * The transmit filter for an active publish session - * {@link PublishSettings.Builder#setPublishType(int)} and - * {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}. Included in + * {@link PublishConfig.Builder#setPublishType(int)} and + * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}. Included in * transmitted publish packets and used by receivers (subscribers) to * determine whether they match - in addition to just relying on the * service name. @@ -305,8 +415,8 @@ public class PublishData implements Parcelable { /** * The transmit filter for a passive publish session - * {@link PublishSettings.Builder#setPublishType(int)} and - * {@link PublishSettings#PUBLISH_TYPE_SOLICITED}. Used by the publisher + * {@link PublishConfig.Builder#setPublishType(int)} and + * {@link PublishConfig#PUBLISH_TYPE_SOLICITED}. Used by the publisher * to determine whether they match transmitted subscriber packets * (active subscribers) - in addition to just relying on the service * name. @@ -332,12 +442,88 @@ public class PublishData implements Parcelable { } /** - * Build {@link PublishData} given the current requests made on the + * Sets the type of the publish session: solicited (aka active - publish + * packets are transmitted over-the-air), or unsolicited (aka passive - + * no publish packets are transmitted, a match is made against an active + * subscribe session whose packets are transmitted over-the-air). + * + * @param publishType Publish session type: solicited ( + * {@link PublishConfig#PUBLISH_TYPE_SOLICITED}) or + * unsolicited ( + * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}). + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setPublishType(@PublishTypes int publishType) { + if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) { + throw new IllegalArgumentException("Invalid publishType - " + publishType); + } + mPublishType = publishType; + return this; + } + + /** + * Sets the number of times a solicited ( + * {@link PublishConfig.Builder#setPublishType(int)}) publish session + * will transmit a packet. When the count is reached an event will be + * generated for {@link WifiNanSessionCallback#onSessionTerminated(int)} + * with reason={@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * + * @param publishCount Number of publish packets to transmit. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setPublishCount(int publishCount) { + if (publishCount < 0) { + throw new IllegalArgumentException("Invalid publishCount - must be non-negative"); + } + mPublishCount = publishCount; + return this; + } + + /** + * Sets the time interval (in seconds) a solicited ( + * {@link PublishConfig.Builder#setPublishCount(int)}) publish session + * will be alive - i.e. transmitting a packet. When the TTL is reached + * an event will be generated for + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= + * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * + * @param ttlSec Lifetime of a publish session in seconds. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setTtlSec(int ttlSec) { + if (ttlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + mTtlSec = ttlSec; + return this; + } + + /** + * Configure whether a publish terminate notification + * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported + * back to the callback. + * + * @param enable If true the terminate callback will be called when the + * publish is terminated. Otherwise it will not be called. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setEnableTerminateNotification(boolean enable) { + mEnableTerminateNotification = enable; + return this; + } + + /** + * Build {@link PublishConfig} given the current requests made on the * builder. */ - public PublishData build() { - return new PublishData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength, - mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength); + public PublishConfig build() { + return new PublishConfig(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength, + mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength, mPublishType, + mPublishCount, mTtlSec, mEnableTerminateNotification); } } } diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.aidl b/wifi/java/android/net/wifi/nan/PublishSettings.aidl deleted file mode 100644 index ff692936bf06..000000000000 --- a/wifi/java/android/net/wifi/nan/PublishSettings.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -parcelable PublishSettings; diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.java b/wifi/java/android/net/wifi/nan/PublishSettings.java deleted file mode 100644 index bbc53408f2b5..000000000000 --- a/wifi/java/android/net/wifi/nan/PublishSettings.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Defines the settings (configuration) for a NAN publish session. Built using - * {@link PublishSettings.Builder}. Publish is done using - * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)} - * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}. - * - * @hide PROPOSED_NAN_API - */ -public class PublishSettings implements Parcelable { - - /** - * Defines an unsolicited publish session - i.e. a publish session where - * publish packets are transmitted over-the-air. Configuration is done using - * {@link PublishSettings.Builder#setPublishType(int)}. - */ - public static final int PUBLISH_TYPE_UNSOLICITED = 0; - - /** - * Defines a solicited publish session - i.e. a publish session where - * publish packets are not transmitted over-the-air and the device listens - * and matches to transmitted subscribe packets. Configuration is done using - * {@link PublishSettings.Builder#setPublishType(int)}. - */ - public static final int PUBLISH_TYPE_SOLICITED = 1; - - /** - * @hide - */ - public final int mPublishType; - - /** - * @hide - */ - public final int mPublishCount; - - /** - * @hide - */ - public final int mTtlSec; - - private PublishSettings(int publishType, int publichCount, int ttlSec) { - mPublishType = publishType; - mPublishCount = publichCount; - mTtlSec = ttlSec; - } - - @Override - public String toString() { - return "PublishSettings [mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount - + ", mTtlSec=" + mTtlSec + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mPublishType); - dest.writeInt(mPublishCount); - dest.writeInt(mTtlSec); - } - - public static final Creator<PublishSettings> CREATOR = new Creator<PublishSettings>() { - @Override - public PublishSettings[] newArray(int size) { - return new PublishSettings[size]; - } - - @Override - public PublishSettings createFromParcel(Parcel in) { - int publishType = in.readInt(); - int publishCount = in.readInt(); - int ttlSec = in.readInt(); - return new PublishSettings(publishType, publishCount, ttlSec); - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof PublishSettings)) { - return false; - } - - PublishSettings lhs = (PublishSettings) o; - - return mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount - && mTtlSec == lhs.mTtlSec; - } - - @Override - public int hashCode() { - int result = 17; - - result = 31 * result + mPublishType; - result = 31 * result + mPublishCount; - result = 31 * result + mTtlSec; - - return result; - } - - /** - * Builder used to build {@link PublishSettings} objects. - */ - public static final class Builder { - int mPublishType; - int mPublishCount; - int mTtlSec; - - /** - * Sets the type of the publish session: solicited (aka active - publish - * packets are transmitted over-the-air), or unsolicited (aka passive - - * no publish packets are transmitted, a match is made against an active - * subscribe session whose packets are transmitted over-the-air). - * - * @param publishType Publish session type: solicited ( - * {@link PublishSettings#PUBLISH_TYPE_SOLICITED}) or - * unsolicited ( - * {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}). - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setPublishType(int publishType) { - if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) { - throw new IllegalArgumentException("Invalid publishType - " + publishType); - } - mPublishType = publishType; - return this; - } - - /** - * Sets the number of times a solicited ( - * {@link PublishSettings.Builder#setPublishType(int)}) publish session - * will transmit a packet. When the count is reached an event will be - * generated for {@link WifiNanSessionListener#onPublishTerminated(int)} - * with reason={@link WifiNanSessionListener#TERMINATE_REASON_DONE}. - * - * @param publishCount Number of publish packets to transmit. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setPublishCount(int publishCount) { - if (publishCount < 0) { - throw new IllegalArgumentException("Invalid publishCount - must be non-negative"); - } - mPublishCount = publishCount; - return this; - } - - /** - * Sets the time interval (in seconds) a solicited ( - * {@link PublishSettings.Builder#setPublishCount(int)}) publish session - * will be alive - i.e. transmitting a packet. When the TTL is reached - * an event will be generated for - * {@link WifiNanSessionListener#onPublishTerminated(int)} with reason= - * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}. - * - * @param ttlSec Lifetime of a publish session in seconds. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setTtlSec(int ttlSec) { - if (ttlSec < 0) { - throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); - } - mTtlSec = ttlSec; - return this; - } - - /** - * Build {@link PublishSettings} given the current requests made on the - * builder. - */ - public PublishSettings build() { - return new PublishSettings(mPublishType, mPublishCount, mTtlSec); - } - } -} diff --git a/wifi/java/android/net/wifi/nan/PublishData.aidl b/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl index 15e4ddfd1c0b..92344a43daf2 100644 --- a/wifi/java/android/net/wifi/nan/PublishData.aidl +++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl @@ -16,4 +16,4 @@ package android.net.wifi.nan; -parcelable PublishData; +parcelable SubscribeConfig; diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java new file mode 100644 index 000000000000..847c8d002abb --- /dev/null +++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2016 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.nan; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; + +/** + * Defines the configuration of a NAN subscribe session. Built using + * {@link SubscribeConfig.Builder}. Subscribe is done using + * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} or + * {@link WifiNanSubscribeSession#updateSubscribe(SubscribeConfig)}. + * + * @hide PROPOSED_NAN_API + */ +public class SubscribeConfig implements Parcelable { + @IntDef({ + SUBSCRIBE_TYPE_PASSIVE, SUBSCRIBE_TYPE_ACTIVE }) + @Retention(RetentionPolicy.SOURCE) + public @interface SubscribeTypes { + } + + /** + * Defines a passive subscribe session - i.e. a subscribe session where + * subscribe packets are not transmitted over-the-air and the device listens + * and matches to transmitted publish packets. Configuration is done using + * {@link SubscribeConfig.Builder#setSubscribeType(int)}. + */ + public static final int SUBSCRIBE_TYPE_PASSIVE = 0; + + /** + * Defines an active subscribe session - i.e. a subscribe session where + * subscribe packets are transmitted over-the-air. Configuration is done + * using {@link SubscribeConfig.Builder#setSubscribeType(int)}. + */ + public static final int SUBSCRIBE_TYPE_ACTIVE = 1; + + @IntDef({ + MATCH_STYLE_FIRST_ONLY, MATCH_STYLE_ALL }) + @Retention(RetentionPolicy.SOURCE) + public @interface MatchStyles { + } + + /** + * Specifies that only the first match of a set of identical matches (same + * publish) will be reported to the subscriber. + */ + public static final int MATCH_STYLE_FIRST_ONLY = 0; + + /** + * Specifies that all matches of a set of identical matches (same publish) + * will be reported to the subscriber. + */ + public static final int MATCH_STYLE_ALL = 1; + + /** + * @hide + */ + public final String mServiceName; + + /** + * @hide + */ + public final int mServiceSpecificInfoLength; + + /** + * @hide + */ + public final byte[] mServiceSpecificInfo; + + /** + * @hide + */ + public final int mTxFilterLength; + + /** + * @hide + */ + public final byte[] mTxFilter; + + /** + * @hide + */ + public final int mRxFilterLength; + + /** + * @hide + */ + public final byte[] mRxFilter; + + /** + * @hide + */ + public final int mSubscribeType; + + /** + * @hide + */ + public final int mSubscribeCount; + + /** + * @hide + */ + public final int mTtlSec; + + /** + * @hide + */ + public final int mMatchStyle; + + /** + * @hide + */ + public final boolean mEnableTerminateNotification; + + private SubscribeConfig(String serviceName, byte[] serviceSpecificInfo, + int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter, + int rxFilterLength, int subscribeType, int publichCount, int ttlSec, int matchStyle, + boolean enableTerminateNotification) { + mServiceName = serviceName; + mServiceSpecificInfoLength = serviceSpecificInfoLength; + mServiceSpecificInfo = serviceSpecificInfo; + mTxFilterLength = txFilterLength; + mTxFilter = txFilter; + mRxFilterLength = rxFilterLength; + mRxFilter = rxFilter; + mSubscribeType = subscribeType; + mSubscribeCount = publichCount; + mTtlSec = ttlSec; + mMatchStyle = matchStyle; + mEnableTerminateNotification = enableTerminateNotification; + } + + @Override + public String toString() { + return "SubscribeConfig [mServiceName='" + mServiceName + "', mServiceSpecificInfo='" + + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength)) + + "', mTxFilter=" + + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString() + + ", mRxFilter=" + + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString() + + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount + + ", mTtlSec=" + mTtlSec + ", mMatchType=" + mMatchStyle + + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mServiceName); + dest.writeInt(mServiceSpecificInfoLength); + if (mServiceSpecificInfoLength != 0) { + dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength); + } + dest.writeInt(mTxFilterLength); + if (mTxFilterLength != 0) { + dest.writeByteArray(mTxFilter, 0, mTxFilterLength); + } + dest.writeInt(mRxFilterLength); + if (mRxFilterLength != 0) { + dest.writeByteArray(mRxFilter, 0, mRxFilterLength); + } + dest.writeInt(mSubscribeType); + dest.writeInt(mSubscribeCount); + dest.writeInt(mTtlSec); + dest.writeInt(mMatchStyle); + dest.writeInt(mEnableTerminateNotification ? 1 : 0); + } + + public static final Creator<SubscribeConfig> CREATOR = new Creator<SubscribeConfig>() { + @Override + public SubscribeConfig[] newArray(int size) { + return new SubscribeConfig[size]; + } + + @Override + public SubscribeConfig createFromParcel(Parcel in) { + String serviceName = in.readString(); + int ssiLength = in.readInt(); + byte[] ssi = new byte[ssiLength]; + if (ssiLength != 0) { + in.readByteArray(ssi); + } + int txFilterLength = in.readInt(); + byte[] txFilter = new byte[txFilterLength]; + if (txFilterLength != 0) { + in.readByteArray(txFilter); + } + int rxFilterLength = in.readInt(); + byte[] rxFilter = new byte[rxFilterLength]; + if (rxFilterLength != 0) { + in.readByteArray(rxFilter); + } + int subscribeType = in.readInt(); + int subscribeCount = in.readInt(); + int ttlSec = in.readInt(); + int matchStyle = in.readInt(); + boolean enableTerminateNotification = in.readInt() != 0; + + return new SubscribeConfig(serviceName, ssi, ssiLength, txFilter, txFilterLength, + rxFilter, rxFilterLength, subscribeType, subscribeCount, ttlSec, matchStyle, + enableTerminateNotification); + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof SubscribeConfig)) { + return false; + } + + SubscribeConfig lhs = (SubscribeConfig) o; + + if (!mServiceName.equals(lhs.mServiceName) + || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength + || mTxFilterLength != lhs.mTxFilterLength + || mRxFilterLength != lhs.mRxFilterLength) { + return false; + } + + if (mServiceSpecificInfo != null && lhs.mServiceSpecificInfo != null) { + for (int i = 0; i < mServiceSpecificInfoLength; ++i) { + if (mServiceSpecificInfo[i] != lhs.mServiceSpecificInfo[i]) { + return false; + } + } + } else if (mServiceSpecificInfoLength != 0) { + return false; // invalid != invalid + } + + if (mTxFilter != null && lhs.mTxFilter != null) { + for (int i = 0; i < mTxFilterLength; ++i) { + if (mTxFilter[i] != lhs.mTxFilter[i]) { + return false; + } + } + } else if (mTxFilterLength != 0) { + return false; // invalid != invalid + } + + if (mRxFilter != null && lhs.mRxFilter != null) { + for (int i = 0; i < mRxFilterLength; ++i) { + if (mRxFilter[i] != lhs.mRxFilter[i]) { + return false; + } + } + } else if (mRxFilterLength != 0) { + return false; // invalid != invalid + } + + return mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount + && mTtlSec == lhs.mTtlSec && mMatchStyle == lhs.mMatchStyle + && mEnableTerminateNotification == lhs.mEnableTerminateNotification; + } + + @Override + public int hashCode() { + int result = 17; + + result = 31 * result + mServiceName.hashCode(); + result = 31 * result + mServiceSpecificInfoLength; + result = 31 * result + Arrays.hashCode(mServiceSpecificInfo); + result = 31 * result + mTxFilterLength; + result = 31 * result + Arrays.hashCode(mTxFilter); + result = 31 * result + mRxFilterLength; + result = 31 * result + Arrays.hashCode(mRxFilter); + result = 31 * result + mSubscribeType; + result = 31 * result + mSubscribeCount; + result = 31 * result + mTtlSec; + result = 31 * result + mMatchStyle; + result = 31 * result + (mEnableTerminateNotification ? 1 : 0); + + return result; + } + + /** + * Validates that the contents of the SubscribeConfig are valid. Otherwise + * throws an IllegalArgumentException. + * + * @hide + */ + public void validate() throws IllegalArgumentException { + if (mServiceSpecificInfoLength != 0 && (mServiceSpecificInfo == null + || mServiceSpecificInfo.length < mServiceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } + if (mTxFilterLength != 0 && (mTxFilter == null || mTxFilter.length < mTxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } + if (mRxFilterLength != 0 && (mRxFilter == null || mRxFilter.length < mRxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } + if (mSubscribeType < SUBSCRIBE_TYPE_PASSIVE || mSubscribeType > SUBSCRIBE_TYPE_ACTIVE) { + throw new IllegalArgumentException("Invalid subscribeType - " + mSubscribeType); + } + if (mSubscribeCount < 0) { + throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative"); + } + if (mTtlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + if (mMatchStyle != MATCH_STYLE_FIRST_ONLY && mMatchStyle != MATCH_STYLE_ALL) { + throw new IllegalArgumentException( + "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL"); + } + if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE && mRxFilterLength != 0) { + throw new IllegalArgumentException( + "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter"); + } + if (mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE && mTxFilterLength != 0) { + throw new IllegalArgumentException( + "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter"); + } + } + + /** + * Builder used to build {@link SubscribeConfig} objects. + */ + public static final class Builder { + private String mServiceName; + private int mServiceSpecificInfoLength; + private byte[] mServiceSpecificInfo = new byte[0]; + private int mTxFilterLength; + private byte[] mTxFilter = new byte[0]; + private int mRxFilterLength; + private byte[] mRxFilter = new byte[0]; + private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE; + private int mSubscribeCount = 0; + private int mTtlSec = 0; + private int mMatchStyle = MATCH_STYLE_ALL; + private boolean mEnableTerminateNotification = true; + + /** + * Specify the service name of the subscribe session. The actual on-air + * value is a 6 byte hashed representation of this string. + * + * @param serviceName The service name for the subscribe session. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setServiceName(@NonNull String serviceName) { + mServiceName = serviceName; + return this; + } + + /** + * Specify service specific information for the subscribe session. This + * is a free-form byte array available to the application to send + * additional information as part of the discovery operation - i.e. it + * will not be used to determine whether a publish/subscribe match + * occurs. + * + * @param serviceSpecificInfo A byte-array for the service-specific + * information field. + * @param serviceSpecificInfoLength The length of the byte-array to be + * used. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setServiceSpecificInfo(byte[] serviceSpecificInfo, + int serviceSpecificInfoLength) { + if (serviceSpecificInfoLength != 0 && (serviceSpecificInfo == null + || serviceSpecificInfo.length < serviceSpecificInfoLength)) { + throw new IllegalArgumentException("Non-matching combination of " + + "serviceSpecificInfo and serviceSpecificInfoLength"); + } + mServiceSpecificInfoLength = serviceSpecificInfoLength; + mServiceSpecificInfo = serviceSpecificInfo; + return this; + } + + /** + * Specify service specific information for the subscribe session - same + * as + * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[], int)} + * but obtaining the data from a String. + * + * @param serviceSpecificInfoStr The service specific information string + * to be included (as a byte array) in the subscribe + * information. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setServiceSpecificInfo(@NonNull String serviceSpecificInfoStr) { + mServiceSpecificInfoLength = serviceSpecificInfoStr.length(); + mServiceSpecificInfo = serviceSpecificInfoStr.getBytes(); + return this; + } + + /** + * The transmit filter for an active subscribe session + * {@link SubscribeConfig.Builder#setSubscribeType(int)} and + * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Included in + * transmitted subscribe packets and used by receivers (passive + * publishers) to determine whether they match - in addition to just + * relying on the service name. + * <p> + * Format is an LV byte array - the {@link TlvBufferUtils} utility class + * is available to form and parse. + * + * @param txFilter The byte-array containing the LV formatted transmit + * filter. + * @param txFilterLength The number of bytes in the transmit filter + * argument. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setTxFilter(byte[] txFilter, int txFilterLength) { + if (txFilterLength != 0 && (txFilter == null || txFilter.length < txFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of txFilter and txFilterLength"); + } + mTxFilter = txFilter; + mTxFilterLength = txFilterLength; + return this; + } + + /** + * The transmit filter for a passive subsribe session + * {@link SubscribeConfig.Builder#setSubscribeType(int)} and + * {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}. Used by the + * subscriber to determine whether they match transmitted publish + * packets - in addition to just relying on the service name. + * <p> + * Format is an LV byte array - the {@link TlvBufferUtils} utility class + * is available to form and parse. + * + * @param rxFilter The byte-array containing the LV formatted receive + * filter. + * @param rxFilterLength The number of bytes in the receive filter + * argument. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setRxFilter(byte[] rxFilter, int rxFilterLength) { + if (rxFilterLength != 0 && (rxFilter == null || rxFilter.length < rxFilterLength)) { + throw new IllegalArgumentException( + "Non-matching combination of rxFilter and rxFilterLength"); + } + mRxFilter = rxFilter; + mRxFilterLength = rxFilterLength; + return this; + } + + /** + * Sets the type of the subscribe session: active (subscribe packets are + * transmitted over-the-air), or passive (no subscribe packets are + * transmitted, a match is made against a solicited/active publish + * session whose packets are transmitted over-the-air). + * + * @param subscribeType Subscribe session type: active ( + * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}) or passive + * ( {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE} ). + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setSubscribeType(@SubscribeTypes int subscribeType) { + if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) { + throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType); + } + mSubscribeType = subscribeType; + return this; + } + + /** + * Sets the number of times an active ( + * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe + * session will transmit a packet. When the count is reached an event + * will be generated for + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= + * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * + * @param subscribeCount Number of subscribe packets to transmit. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setSubscribeCount(int subscribeCount) { + if (subscribeCount < 0) { + throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative"); + } + mSubscribeCount = subscribeCount; + return this; + } + + /** + * Sets the time interval (in seconds) an active ( + * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe + * session will be alive - i.e. transmitting a packet. When the TTL is + * reached an event will be generated for + * {@link WifiNanSessionCallback#onSessionTerminated(int)} with reason= + * {@link WifiNanSessionCallback#TERMINATE_REASON_DONE}. + * + * @param ttlSec Lifetime of a subscribe session in seconds. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setTtlSec(int ttlSec) { + if (ttlSec < 0) { + throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); + } + mTtlSec = ttlSec; + return this; + } + + /** + * Sets the match style of the subscription - how are matches from a + * single match session (corresponding to the same publish action on the + * peer) reported to the host (using the + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} + * ). The options are: only report the first match and ignore the rest + * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single + * match {@link SubscribeConfig#MATCH_STYLE_ALL}. + * + * @param matchStyle The reporting style for the discovery match. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setMatchStyle(@MatchStyles int matchStyle) { + if (matchStyle != MATCH_STYLE_FIRST_ONLY && matchStyle != MATCH_STYLE_ALL) { + throw new IllegalArgumentException( + "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL"); + } + mMatchStyle = matchStyle; + return this; + } + + /** + * Configure whether a subscribe terminate notification + * {@link WifiNanSessionCallback#onSessionTerminated(int)} is reported + * back to the callback. + * + * @param enable If true the terminate callback will be called when the + * subscribe is terminated. Otherwise it will not be called. + * @return The builder to facilitate chaining + * {@code builder.setXXX(..).setXXX(..)}. + */ + public Builder setEnableTerminateNotification(boolean enable) { + mEnableTerminateNotification = enable; + return this; + } + + /** + * Build {@link SubscribeConfig} given the current requests made on the + * builder. + */ + public SubscribeConfig build() { + return new SubscribeConfig(mServiceName, mServiceSpecificInfo, + mServiceSpecificInfoLength, mTxFilter, mTxFilterLength, mRxFilter, + mRxFilterLength, mSubscribeType, mSubscribeCount, mTtlSec, mMatchStyle, + mEnableTerminateNotification); + } + } +} diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.java b/wifi/java/android/net/wifi/nan/SubscribeData.java deleted file mode 100644 index cd6e91882834..000000000000 --- a/wifi/java/android/net/wifi/nan/SubscribeData.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Arrays; - -/** - * Defines the data for a NAN subscribe session. Built using - * {@link SubscribeData.Builder}. Subscribe is done using - * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)} - * or - * {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}. - * @hide PROPOSED_NAN_API - */ -public class SubscribeData implements Parcelable { - /** - * @hide - */ - public final String mServiceName; - - /** - * @hide - */ - public final int mServiceSpecificInfoLength; - - /** - * @hide - */ - public final byte[] mServiceSpecificInfo; - - /** - * @hide - */ - public final int mTxFilterLength; - - /** - * @hide - */ - public final byte[] mTxFilter; - - /** - * @hide - */ - public final int mRxFilterLength; - - /** - * @hide - */ - public final byte[] mRxFilter; - - private SubscribeData(String serviceName, byte[] serviceSpecificInfo, - int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter, - int rxFilterLength) { - mServiceName = serviceName; - mServiceSpecificInfoLength = serviceSpecificInfoLength; - mServiceSpecificInfo = serviceSpecificInfo; - mTxFilterLength = txFilterLength; - mTxFilter = txFilter; - mRxFilterLength = rxFilterLength; - mRxFilter = rxFilter; - } - - @Override - public String toString() { - return "SubscribeData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='" - + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength)) - + "', mTxFilter=" - + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString() - + ", mRxFilter=" - + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString() - + "']"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mServiceName); - dest.writeInt(mServiceSpecificInfoLength); - if (mServiceSpecificInfoLength != 0) { - dest.writeByteArray(mServiceSpecificInfo, 0, mServiceSpecificInfoLength); - } - dest.writeInt(mTxFilterLength); - if (mTxFilterLength != 0) { - dest.writeByteArray(mTxFilter, 0, mTxFilterLength); - } - dest.writeInt(mRxFilterLength); - if (mRxFilterLength != 0) { - dest.writeByteArray(mRxFilter, 0, mRxFilterLength); - } - } - - public static final Creator<SubscribeData> CREATOR = new Creator<SubscribeData>() { - @Override - public SubscribeData[] newArray(int size) { - return new SubscribeData[size]; - } - - @Override - public SubscribeData createFromParcel(Parcel in) { - String serviceName = in.readString(); - int ssiLength = in.readInt(); - byte[] ssi = new byte[ssiLength]; - if (ssiLength != 0) { - in.readByteArray(ssi); - } - int txFilterLength = in.readInt(); - byte[] txFilter = new byte[txFilterLength]; - if (txFilterLength != 0) { - in.readByteArray(txFilter); - } - int rxFilterLength = in.readInt(); - byte[] rxFilter = new byte[rxFilterLength]; - if (rxFilterLength != 0) { - in.readByteArray(rxFilter); - } - - return new SubscribeData(serviceName, ssi, ssiLength, txFilter, txFilterLength, - rxFilter, rxFilterLength); - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof SubscribeData)) { - return false; - } - - SubscribeData lhs = (SubscribeData) o; - - if (!mServiceName.equals(lhs.mServiceName) - || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength - || mTxFilterLength != lhs.mTxFilterLength - || mRxFilterLength != lhs.mRxFilterLength) { - return false; - } - - if (mServiceSpecificInfo != null && lhs.mServiceSpecificInfo != null) { - for (int i = 0; i < mServiceSpecificInfoLength; ++i) { - if (mServiceSpecificInfo[i] != lhs.mServiceSpecificInfo[i]) { - return false; - } - } - } else if (mServiceSpecificInfoLength != 0) { - return false; // invalid != invalid - } - - if (mTxFilter != null && lhs.mTxFilter != null) { - for (int i = 0; i < mTxFilterLength; ++i) { - if (mTxFilter[i] != lhs.mTxFilter[i]) { - return false; - } - } - } else if (mTxFilterLength != 0) { - return false; // invalid != invalid - } - - if (mRxFilter != null && lhs.mRxFilter != null) { - for (int i = 0; i < mRxFilterLength; ++i) { - if (mRxFilter[i] != lhs.mRxFilter[i]) { - return false; - } - } - } else if (mRxFilterLength != 0) { - return false; // invalid != invalid - } - - return true; - } - - @Override - public int hashCode() { - int result = 17; - - result = 31 * result + mServiceName.hashCode(); - result = 31 * result + mServiceSpecificInfoLength; - result = 31 * result + Arrays.hashCode(mServiceSpecificInfo); - result = 31 * result + mTxFilterLength; - result = 31 * result + Arrays.hashCode(mTxFilter); - result = 31 * result + mRxFilterLength; - result = 31 * result + Arrays.hashCode(mRxFilter); - - return result; - } - - /** - * Builder used to build {@link SubscribeData} objects. - */ - public static final class Builder { - private String mServiceName; - private int mServiceSpecificInfoLength; - private byte[] mServiceSpecificInfo = new byte[0]; - private int mTxFilterLength; - private byte[] mTxFilter = new byte[0]; - private int mRxFilterLength; - private byte[] mRxFilter = new byte[0]; - - /** - * Specify the service name of the subscribe session. The actual on-air - * value is a 6 byte hashed representation of this string. - * - * @param serviceName The service name for the subscribe session. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setServiceName(String serviceName) { - mServiceName = serviceName; - return this; - } - - /** - * Specify service specific information for the subscribe session. This - * is a free-form byte array available to the application to send - * additional information as part of the discovery operation - i.e. it - * will not be used to determine whether a publish/subscribe match - * occurs. - * - * @param serviceSpecificInfo A byte-array for the service-specific - * information field. - * @param serviceSpecificInfoLength The length of the byte-array to be - * used. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setServiceSpecificInfo(byte[] serviceSpecificInfo, - int serviceSpecificInfoLength) { - mServiceSpecificInfoLength = serviceSpecificInfoLength; - mServiceSpecificInfo = serviceSpecificInfo; - return this; - } - - /** - * Specify service specific information for the subscribe session - same - * as {@link SubscribeData.Builder#setServiceSpecificInfo(byte[], int)} - * but obtaining the data from a String. - * - * @param serviceSpecificInfoStr The service specific information string - * to be included (as a byte array) in the subscribe - * information. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setServiceSpecificInfo(String serviceSpecificInfoStr) { - mServiceSpecificInfoLength = serviceSpecificInfoStr.length(); - mServiceSpecificInfo = serviceSpecificInfoStr.getBytes(); - return this; - } - - /** - * The transmit filter for an active subscribe session - * {@link SubscribeSettings.Builder#setSubscribeType(int)} and - * {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}. Included in - * transmitted subscribe packets and used by receivers (passive - * publishers) to determine whether they match - in addition to just - * relying on the service name. - * <p> - * Format is an LV byte array - the {@link TlvBufferUtils} utility class - * is available to form and parse. - * - * @param txFilter The byte-array containing the LV formatted transmit - * filter. - * @param txFilterLength The number of bytes in the transmit filter - * argument. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setTxFilter(byte[] txFilter, int txFilterLength) { - mTxFilter = txFilter; - mTxFilterLength = txFilterLength; - return this; - } - - /** - * The transmit filter for a passive subsribe session - * {@link SubscribeSettings.Builder#setSubscribeType(int)} and - * {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE}. Used by the - * subscriber to determine whether they match transmitted publish - * packets - in addition to just relying on the service name. - * <p> - * Format is an LV byte array - the {@link TlvBufferUtils} utility class - * is available to form and parse. - * - * @param rxFilter The byte-array containing the LV formatted receive - * filter. - * @param rxFilterLength The number of bytes in the receive filter - * argument. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setRxFilter(byte[] rxFilter, int rxFilterLength) { - mRxFilter = rxFilter; - mRxFilterLength = rxFilterLength; - return this; - } - - /** - * Build {@link SubscribeData} given the current requests made on the - * builder. - */ - public SubscribeData build() { - return new SubscribeData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength, - mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength); - } - } -} diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl deleted file mode 100644 index 44849bc04a57..000000000000 --- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -parcelable SubscribeSettings; diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.java b/wifi/java/android/net/wifi/nan/SubscribeSettings.java deleted file mode 100644 index 5c4f8fb385fa..000000000000 --- a/wifi/java/android/net/wifi/nan/SubscribeSettings.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Defines the settings (configuration) for a NAN subscribe session. Built using - * {@link SubscribeSettings.Builder}. Subscribe is done using - * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)} - * or {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}. - * - * @hide PROPOSED_NAN_API - */ -public class SubscribeSettings implements Parcelable { - - /** - * Defines a passive subscribe session - i.e. a subscribe session where - * subscribe packets are not transmitted over-the-air and the device listens - * and matches to transmitted publish packets. Configuration is done using - * {@link SubscribeSettings.Builder#setSubscribeType(int)}. - */ - public static final int SUBSCRIBE_TYPE_PASSIVE = 0; - - /** - * Defines an active subscribe session - i.e. a subscribe session where - * subscribe packets are transmitted over-the-air. Configuration is done - * using {@link SubscribeSettings.Builder#setSubscribeType(int)}. - */ - public static final int SUBSCRIBE_TYPE_ACTIVE = 1; - - /** - * @hide - */ - public final int mSubscribeType; - - /** - * @hide - */ - public final int mSubscribeCount; - - /** - * @hide - */ - public final int mTtlSec; - - private SubscribeSettings(int subscribeType, int publichCount, int ttlSec) { - mSubscribeType = subscribeType; - mSubscribeCount = publichCount; - mTtlSec = ttlSec; - } - - @Override - public String toString() { - return "SubscribeSettings [mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" - + mSubscribeCount + ", mTtlSec=" + mTtlSec + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mSubscribeType); - dest.writeInt(mSubscribeCount); - dest.writeInt(mTtlSec); - } - - public static final Creator<SubscribeSettings> CREATOR = new Creator<SubscribeSettings>() { - @Override - public SubscribeSettings[] newArray(int size) { - return new SubscribeSettings[size]; - } - - @Override - public SubscribeSettings createFromParcel(Parcel in) { - int subscribeType = in.readInt(); - int subscribeCount = in.readInt(); - int ttlSec = in.readInt(); - return new SubscribeSettings(subscribeType, subscribeCount, ttlSec); - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (!(o instanceof SubscribeSettings)) { - return false; - } - - SubscribeSettings lhs = (SubscribeSettings) o; - - return mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount - && mTtlSec == lhs.mTtlSec; - } - - @Override - public int hashCode() { - int result = 17; - - result = 31 * result + mSubscribeType; - result = 31 * result + mSubscribeCount; - result = 31 * result + mTtlSec; - - return result; - } - - /** - * Builder used to build {@link SubscribeSettings} objects. - */ - public static final class Builder { - int mSubscribeType; - int mSubscribeCount; - int mTtlSec; - - /** - * Sets the type of the subscribe session: active (subscribe packets are - * transmitted over-the-air), or passive (no subscribe packets are - * transmitted, a match is made against a solicited/active publish - * session whose packets are transmitted over-the-air). - * - * @param subscribeType Subscribe session type: active ( - * {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}) or - * passive ( {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE} - * ). - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setSubscribeType(int subscribeType) { - if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) { - throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType); - } - mSubscribeType = subscribeType; - return this; - } - - /** - * Sets the number of times an active ( - * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe - * session will transmit a packet. When the count is reached an event - * will be generated for - * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason= - * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}. - * - * @param subscribeCount Number of subscribe packets to transmit. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setSubscribeCount(int subscribeCount) { - if (subscribeCount < 0) { - throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative"); - } - mSubscribeCount = subscribeCount; - return this; - } - - /** - * Sets the time interval (in seconds) an active ( - * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe - * session will be alive - i.e. transmitting a packet. When the TTL is - * reached an event will be generated for - * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason= - * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}. - * - * @param ttlSec Lifetime of a subscribe session in seconds. - * @return The builder to facilitate chaining - * {@code builder.setXXX(..).setXXX(..)}. - */ - public Builder setTtlSec(int ttlSec) { - if (ttlSec < 0) { - throw new IllegalArgumentException("Invalid ttlSec - must be non-negative"); - } - mTtlSec = ttlSec; - return this; - } - - /** - * Build {@link SubscribeSettings} given the current requests made on - * the builder. - */ - public SubscribeSettings build() { - return new SubscribeSettings(mSubscribeType, mSubscribeCount, mTtlSec); - } - } -} diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java new file mode 100644 index 000000000000..2b9a5fa133b0 --- /dev/null +++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 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.nan; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base class for NAN events callbacks. Should be extended by applications + * wanting notifications. These are callbacks applying to the NAN connection as + * a whole - not to specific publish or subscribe sessions - for that see + * {@link WifiNanSessionCallback}. + * + * @hide PROPOSED_NAN_API + */ +public class WifiNanEventCallback { + @IntDef({ + REASON_INVALID_ARGS, REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG, REASON_OTHER + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EventReasonCodes { + } + + /** + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * invalid argument in the requested operation. + */ + public static final int REASON_INVALID_ARGS = 1000; + + /** + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * that a {@link ConfigRequest} passed in + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback, ConfigRequest)} + * couldn't be applied since other connections already exist with an + * incompatible configurations. + */ + public static final int REASON_ALREADY_CONNECTED_INCOMPAT_CONFIG = 1001; + + /** + * Failure reason flag for {@link WifiNanEventCallback} callbacks. Indicates + * an unspecified error occurred during the operation. + */ + public static final int REASON_OTHER = 1003; + + /** + * Called when NAN connect operation + * {@link WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)} + * is completed. Doesn't necessarily mean that have joined or started a NAN + * cluster. An indication is provided by {@link #onIdentityChanged()}. + */ + public void onConnectSuccess() { + /* empty */ + } + + /** + * Called when NAN connect operation + * {@code WifiNanManager#connect(android.os.Looper, WifiNanEventCallback)} + * failed. + * + * @param reason Failure reason code, see + * {@code WifiNanEventCallback.REASON_*}. + */ + public void onConnectFail(@EventReasonCodes int reason) { + /* empty */ + } + + /** + * Called when NAN identity has changed. This may be due to joining a + * cluster, starting a cluster, or discovery interface change. The + * implication is that peers you've been communicating with may no longer + * recognize you and you need to re-establish your identity. + */ + public void onIdentityChanged() { + /* empty */ + } +} diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java deleted file mode 100644 index 9e6ed4ee9634..000000000000 --- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -/** - * Base class for NAN events callbacks. Should be extended by applications - * wanting notifications. These are callbacks applying to the NAN connection as - * a whole - not to specific publish or subscribe sessions - for that see - * {@link WifiNanSessionListener}. - * <p> - * During registration specify which specific events are desired using a set of - * {@code NanEventListener.LISTEN_*} flags OR'd together. Only those events will - * be delivered to the registered listener. Override those callbacks - * {@code NanEventListener.on*} for the registered events. - * - * @hide PROPOSED_NAN_API - */ -public class WifiNanEventListener { - private static final String TAG = "WifiNanEventListener"; - private static final boolean DBG = false; - private static final boolean VDBG = false; // STOPSHIP if true - - /** - * Configuration completion callback event registration flag. Corresponding - * callback is {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)}. - */ - public static final int LISTEN_CONFIG_COMPLETED = 0x1 << 0; - - /** - * Configuration failed callback event registration flag. Corresponding - * callback is - * {@link WifiNanEventListener#onConfigFailed(ConfigRequest, int)}. - */ - public static final int LISTEN_CONFIG_FAILED = 0x1 << 1; - - /** - * NAN cluster is down callback event registration flag. Corresponding - * callback is {@link WifiNanEventListener#onNanDown(int)}. - */ - public static final int LISTEN_NAN_DOWN = 0x1 << 2; - - /** - * NAN identity has changed event registration flag. This may be due to - * joining a cluster, starting a cluster, or discovery interface change. The - * implication is that peers you've been communicating with may no longer - * recognize you and you need to re-establish your identity. Corresponding - * callback is {@link WifiNanEventListener#onIdentityChanged()}. - */ - public static final int LISTEN_IDENTITY_CHANGED = 0x1 << 3; - - private final Handler mHandler; - - /** - * Constructs a {@link WifiNanEventListener} using the looper of the current - * thread. I.e. all callbacks will be delivered on the current thread. - */ - public WifiNanEventListener() { - this(Looper.myLooper()); - } - - /** - * Constructs a {@link WifiNanEventListener} using the specified looper. I.e. - * all callbacks will delivered on the thread of the specified looper. - * - * @param looper The looper on which to execute the callbacks. - */ - public WifiNanEventListener(Looper looper) { - if (VDBG) Log.v(TAG, "ctor: looper=" + looper); - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); - switch (msg.what) { - case LISTEN_CONFIG_COMPLETED: - WifiNanEventListener.this.onConfigCompleted((ConfigRequest) msg.obj); - break; - case LISTEN_CONFIG_FAILED: - WifiNanEventListener.this.onConfigFailed((ConfigRequest) msg.obj, msg.arg1); - break; - case LISTEN_NAN_DOWN: - WifiNanEventListener.this.onNanDown(msg.arg1); - break; - case LISTEN_IDENTITY_CHANGED: - WifiNanEventListener.this.onIdentityChanged(); - break; - } - } - }; - } - - /** - * Called when NAN configuration is completed. Event will only be delivered - * if registered using {@link WifiNanEventListener#LISTEN_CONFIG_COMPLETED}. A - * dummy (empty implementation printing out a warning). Make sure to - * override if registered. - * - * @param completedConfig The actual configuration request which was - * completed. Note that it may be different from that requested - * by the application. The service combines configuration - * requests from all applications. - */ - public void onConfigCompleted(ConfigRequest completedConfig) { - Log.w(TAG, "onConfigCompleted: called in stub - override if interested or disable"); - } - - /** - * Called when NAN configuration failed. Event will only be delivered if - * registered using {@link WifiNanEventListener#LISTEN_CONFIG_FAILED}. A dummy - * (empty implementation printing out a warning). Make sure to override if - * registered. - * - * @param reason Failure reason code, see {@code NanSessionListener.FAIL_*}. - */ - public void onConfigFailed(ConfigRequest failedConfig, int reason) { - Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable"); - } - - /** - * Called when NAN cluster is down. Event will only be delivered if - * registered using {@link WifiNanEventListener#LISTEN_NAN_DOWN}. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. - * - * @param reason Reason code for event, see {@code NanSessionListener.FAIL_*}. - */ - public void onNanDown(int reason) { - Log.w(TAG, "onNanDown: called in stub - override if interested or disable"); - } - - /** - * Called when NAN identity has changed. This may be due to joining a - * cluster, starting a cluster, or discovery interface change. The - * implication is that peers you've been communicating with may no longer - * recognize you and you need to re-establish your identity. Event will only - * be delivered if registered using - * {@link WifiNanEventListener#LISTEN_IDENTITY_CHANGED}. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. - */ - public void onIdentityChanged() { - if (VDBG) Log.v(TAG, "onIdentityChanged: called in stub - override if interested"); - } - - /** - * {@hide} - */ - public IWifiNanEventListener callback = new IWifiNanEventListener.Stub() { - @Override - public void onConfigCompleted(ConfigRequest completedConfig) { - if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig); - - Message msg = mHandler.obtainMessage(LISTEN_CONFIG_COMPLETED); - msg.obj = completedConfig; - mHandler.sendMessage(msg); - } - - @Override - public void onConfigFailed(ConfigRequest failedConfig, int reason) { - if (VDBG) { - Log.v(TAG, "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason); - } - - Message msg = mHandler.obtainMessage(LISTEN_CONFIG_FAILED); - msg.arg1 = reason; - msg.obj = failedConfig; - mHandler.sendMessage(msg); - } - - @Override - public void onNanDown(int reason) { - if (VDBG) Log.v(TAG, "onNanDown: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_NAN_DOWN); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onIdentityChanged() { - if (VDBG) Log.v(TAG, "onIdentityChanged"); - - Message msg = mHandler.obtainMessage(LISTEN_IDENTITY_CHANGED); - mHandler.sendMessage(msg); - } - }; -} diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java index 1b78bebfbba7..905562266547 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanManager.java +++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java @@ -16,10 +16,25 @@ package android.net.wifi.nan; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.net.wifi.RttManager; import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; + +import java.lang.ref.WeakReference; +import java.util.Arrays; /** * This class provides the primary API for managing Wi-Fi NAN operation: @@ -41,9 +56,57 @@ public class WifiNanManager { private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true - private IBinder mBinder; + private static final int INVALID_CLIENT_ID = 0; + + /** + * Broadcast intent action to indicate whether Wi-Fi NAN is enabled or + * disabled. An extra {@link #EXTRA_WIFI_STATE} provides the state + * information as int. + * + * @see #EXTRA_WIFI_STATE + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String WIFI_NAN_STATE_CHANGED_ACTION = "android.net.wifi.nan.STATE_CHANGED"; + + /** + * The lookup key for an int that indicates whether Wi-Fi NAN is enabled or + * disabled. Retrieve it with + * {@link android.content.Intent#getIntExtra(String,int)}. + * + * @see #WIFI_NAN_STATE_DISABLED + * @see #WIFI_NAN_STATE_ENABLED + */ + public static final String EXTRA_WIFI_STATE = "wifi_nan_state"; + + /** + * Wi-Fi NAN is disabled. + * + * @see #WIFI_NAN_STATE_CHANGED_ACTION + */ + public static final int WIFI_NAN_STATE_DISABLED = 1; + + /** + * Wi-Fi NAN is enabled. + * + * @see #WIFI_NAN_STATE_CHANGED_ACTION + */ + public static final int WIFI_NAN_STATE_ENABLED = 2; + + private final IWifiNanManager mService; + + private final Object mLock = new Object(); // lock access to the following vars + + @GuardedBy("mLock") + private final IBinder mBinder = new Binder(); - private IWifiNanManager mService; + @GuardedBy("mLock") + private int mClientId = INVALID_CLIENT_ID; + + @GuardedBy("mLock") + private Looper mLooper; + + @GuardedBy("mLock") + private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>(); /** * {@hide} @@ -53,280 +116,720 @@ public class WifiNanManager { } /** - * Re-connect to the Wi-Fi NAN service - enabling the application to execute - * {@link WifiNanManager} APIs. Application don't normally need to call this - * API since it is executed in the constructor. However, applications which - * have explicitly {@link WifiNanManager#disconnect()} need to call this - * function to re-connect. + * Enable the usage of the NAN API. Doesn't actually turn on NAN cluster formation - that only + * happens when a connection is made. {@link #WIFI_NAN_STATE_CHANGED_ACTION} broadcast will be + * triggered. * - * @param listener A listener extended from {@link WifiNanEventListener}. - * @param events The set of events to be delivered to the {@code listener}. - * OR'd event flags from {@link WifiNanEventListener - * NanEventListener.LISTEN*}. + * @hide PROPOSED_NAN_SYSTEM_API */ - public void connect(WifiNanEventListener listener, int events) { + public void enableUsage() { try { - if (VDBG) Log.v(TAG, "connect()"); - if (listener == null) { - throw new IllegalArgumentException("Invalid listener - must not be null"); - } - if (mBinder == null) { - mBinder = new Binder(); - } - mService.connect(mBinder, listener.callback, events); + mService.enableUsage(); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } /** - * Disconnect from the Wi-Fi NAN service and destroy all outstanding - * operations - i.e. all publish and subscribes are terminated, any - * outstanding data-link is shut-down, and all requested NAN configurations - * are cancelled. - * <p> - * An application may then re-connect using - * {@link WifiNanManager#connect(WifiNanEventListener, int)} . + * Disable the usage of the NAN API. All attempts to connect() will be rejected. All open + * connections and sessions will be terminated. {@link #WIFI_NAN_STATE_CHANGED_ACTION} broadcast + * will be triggered. + * + * @hide PROPOSED_NAN_SYSTEM_API */ - public void disconnect() { + public void disableUsage() { try { - if (VDBG) Log.v(TAG, "disconnect()"); - mService.disconnect(mBinder); - mBinder = null; + mService.disableUsage(); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } /** - * Requests a NAN configuration, specified by {@link ConfigRequest}. Note - * that NAN is a shared resource and the device can only be a member of a - * single cluster. Thus the service may merge configuration requests from - * multiple applications and configure NAN differently from individual - * requests. - * <p> - * The {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)} will be - * called when configuration is completed (if a listener is registered for - * this specific event). + * Returns the current status of NAN API: whether or not usage is enabled. * - * @param configRequest The requested NAN configuration. + * @return A boolean indicating whether the app can use the NAN API (true) + * or not (false). */ - public void requestConfig(ConfigRequest configRequest) { - if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest); + public boolean isUsageEnabled() { try { - mService.requestConfig(configRequest); + return mService.isUsageEnabled(); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } + + return false; } /** - * Request a NAN publish session. The results of the publish session - * operation will result in callbacks to the indicated listener: - * {@link WifiNanSessionListener NanSessionListener.on*}. + * Connect to the Wi-Fi NAN service - enabling the application to execute + * {@link WifiNanManager} APIs. * - * @param publishData The {@link PublishData} specifying the contents of the - * publish session. - * @param publishSettings The {@link PublishSettings} specifying the - * settings for the publish session. - * @param listener The {@link WifiNanSessionListener} derived objects to be used - * for the event callbacks specified by {@code events}. - * @param events The list of events to be delivered to the {@code listener} - * object. An OR'd value of {@link WifiNanSessionListener - * NanSessionListener.LISTEN_*}. - * @return The {@link WifiNanPublishSession} which can be used to further - * control the publish session. + * @param looper The Looper on which to execute all callbacks related to the + * connection - including all sessions opened as part of this + * connection. + * @param callback A callback extended from {@link WifiNanEventCallback}. */ - public WifiNanPublishSession publish(PublishData publishData, PublishSettings publishSettings, - WifiNanSessionListener listener, int events) { - return publishRaw(publishData, publishSettings, listener, - events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); + public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback) { + connect(looper, callback, null); } /** - * Same as publish(*) but does not modify the event flag + * Connect to the Wi-Fi NAN service - enabling the application to execute + * {@link WifiNanManager} APIs. Allows requesting a specific configuration + * using {@link ConfigRequest} structure. Limited to privileged access. * - * @hide + * @param looper The Looper on which to execute all callbacks related to the + * connection - including all sessions opened as part of this + * connection. + * @param callback A callback extended from {@link WifiNanEventCallback}. + * @param configRequest The requested NAN configuration. */ - public WifiNanPublishSession publishRaw(PublishData publishData, - PublishSettings publishSettings, WifiNanSessionListener listener, int events) { - if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); - - if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED - && publishData.mRxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " - + "publishes (active) can't have an Rx filter"); - } - if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED - && publishData.mTxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " - + "publishes (passive) can't have a Tx filter"); + public void connect(@NonNull Looper looper, @NonNull WifiNanEventCallback callback, + @Nullable ConfigRequest configRequest) { + if (VDBG) { + Log.v(TAG, "connect(): looper=" + looper + ", callback=" + callback + ", configRequest=" + + configRequest); } - if (listener == null) { - throw new IllegalArgumentException("Invalid listener - must not be null"); + + synchronized (mLock) { + mLooper = looper; + + try { + mClientId = mService.connect(mBinder, + new WifiNanEventCallbackProxy(this, looper, callback), configRequest); + } catch (RemoteException e) { + mClientId = INVALID_CLIENT_ID; + mLooper = null; + e.rethrowFromSystemServer(); + } } + } - int sessionId; + /** + * Disconnect from the Wi-Fi NAN service and destroy all outstanding + * operations - i.e. all publish and subscribes are terminated, any + * outstanding data-link is shut-down, and all requested NAN configurations + * are cancelled. + * <p> + * An application may then re-connect using + * {@link WifiNanManager#connect(Looper, WifiNanEventCallback)} . + */ + public void disconnect() { + if (VDBG) Log.v(TAG, "disconnect()"); + + IBinder binder; + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.w(TAG, "disconnect(): called with invalid client ID - not connected first?"); + return; + } + + binder = mBinder; + clientId = mClientId; + + mLooper = null; + mClientId = INVALID_CLIENT_ID; + } try { - sessionId = mService.createSession(listener.callback, events); - if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId); - mService.publish(sessionId, publishData, publishSettings); + mService.disconnect(clientId, binder); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } + } - return new WifiNanPublishSession(this, sessionId); + @Override + protected void finalize() throws Throwable { + disconnect(); + super.finalize(); } /** - * {@hide} + * Request a NAN publish session. The actual publish session is provided by + * the + * {@link WifiNanSessionCallback#onPublishStarted(WifiNanPublishSession)} + * callback. Other results of the publish session operation will result in + * callbacks to the indicated callback: {@link WifiNanSessionCallback + * NanSessionCallback.on*}. + * + * @param publishConfig The {@link PublishConfig} specifying the + * configuration of the publish session. + * @param callback The {@link WifiNanSessionCallback} derived objects to be + * used for the event callbacks specified by {@code events}. */ - public void publish(int sessionId, PublishData publishData, PublishSettings publishSettings) { - if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings); + public void publish(@NonNull PublishConfig publishConfig, + @NonNull WifiNanSessionCallback callback) { + if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig); - if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED - && publishData.mRxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED " - + "publishes (active) can't have an Rx filter"); - } - if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED - && publishData.mTxFilterLength != 0) { - throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED " - + "publishes (passive) can't have a Tx filter"); - } + int clientId; + Looper looper; + synchronized (mLock) { + if (mLooper == null || mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "publish(): called with null looper or invalid client ID - " + + "not connected first?"); + return; + } + clientId = mClientId; + looper = mLooper; + } try { - mService.publish(sessionId, publishData, publishSettings); + mService.publish(clientId, publishConfig, + new WifiNanSessionCallbackProxy(this, looper, true, callback)); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } + /** - * Request a NAN subscribe session. The results of the subscribe session - * operation will result in callbacks to the indicated listener: - * {@link WifiNanSessionListener NanSessionListener.on*}. - * - * @param subscribeData The {@link SubscribeData} specifying the contents of - * the subscribe session. - * @param subscribeSettings The {@link SubscribeSettings} specifying the - * settings for the subscribe session. - * @param listener The {@link WifiNanSessionListener} derived objects to be used - * for the event callbacks specified by {@code events}. - * @param events The list of events to be delivered to the {@code listener} - * object. An OR'd value of {@link WifiNanSessionListener - * NanSessionListener.LISTEN_*}. - * @return The {@link WifiNanSubscribeSession} which can be used to further - * control the subscribe session. + * {@hide} */ - public WifiNanSubscribeSession subscribe(SubscribeData subscribeData, - SubscribeSettings subscribeSettings, - WifiNanSessionListener listener, int events) { - return subscribeRaw(subscribeData, subscribeSettings, listener, - events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS); + public void updatePublish(int sessionId, PublishConfig publishConfig) { + if (VDBG) Log.v(TAG, "updatePublish(): config=" + publishConfig); + + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "updatePublish(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; + } + try { + mService.updatePublish(clientId, sessionId, publishConfig); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** - * Same as subscribe(*) but does not modify the event flag + * Request a NAN subscribe session. The actual subscribe session is provided + * by the + * {@link WifiNanSessionCallback#onSubscribeStarted(WifiNanSubscribeSession)} + * callback. Other results of the subscribe session operation will result in + * callbacks to the indicated callback: {@link WifiNanSessionCallback + * NanSessionCallback.on*} * - * @hide + * @param subscribeConfig The {@link SubscribeConfig} specifying the + * configuration of the subscribe session. + * @param callback The {@link WifiNanSessionCallback} derived objects to be + * used for the event callbacks specified by {@code events}. */ - public WifiNanSubscribeSession subscribeRaw(SubscribeData subscribeData, - SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) { + public void subscribe(@NonNull SubscribeConfig subscribeConfig, + @NonNull WifiNanSessionCallback callback) { if (VDBG) { - Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); + Log.v(TAG, "subscribe(): config=" + subscribeConfig); } - if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE - && subscribeData.mRxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); - } - if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE - && subscribeData.mTxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); - } + int clientId; + Looper looper; + synchronized (mLock) { + if (mLooper == null || mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "subscribe(): called with null looper or invalid client ID - " + + "not connected first?"); + return; + } - int sessionId; + clientId = mClientId; + looper = mLooper; + } try { - sessionId = mService.createSession(listener.callback, events); - if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId); - mService.subscribe(sessionId, subscribeData, subscribeSettings); + mService.subscribe(clientId, subscribeConfig, + new WifiNanSessionCallbackProxy(this, looper, false, callback)); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } - - return new WifiNanSubscribeSession(this, sessionId); } /** * {@hide} */ - public void subscribe(int sessionId, SubscribeData subscribeData, - SubscribeSettings subscribeSettings) { + public void updateSubscribe(int sessionId, SubscribeConfig subscribeConfig) { if (VDBG) { - Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings); + Log.v(TAG, "subscribe(): config=" + subscribeConfig); } - if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE - && subscribeData.mRxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter"); - } - if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE - && subscribeData.mTxFilterLength != 0) { - throw new IllegalArgumentException( - "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter"); + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, + "updateSubscribe(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; } try { - mService.subscribe(sessionId, subscribeData, subscribeSettings); + mService.updateSubscribe(clientId, sessionId, subscribeConfig); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } /** * {@hide} */ - public void stopSession(int sessionId) { - if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId); + public void terminateSession(int sessionId) { + if (DBG) Log.d(TAG, "Terminate NAN session #" + sessionId); + + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, + "terminateSession(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; + } try { - mService.stopSession(sessionId); + mService.terminateSession(clientId, sessionId); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } /** * {@hide} */ - public void destroySession(int sessionId) { - if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId); + public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength, + int messageId, int retryCount) { + if (VDBG) { + Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId + + ", messageLength=" + messageLength + ", messageId=" + messageId + + ", retryCount=" + retryCount); + } + + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "sendMessage(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; + } try { - mService.destroySession(sessionId); + mService.sendMessage(clientId, sessionId, peerId, message, messageLength, messageId, + retryCount); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } /** * {@hide} */ - public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength, - int messageId) { + public void startRanging(int sessionId, RttManager.RttParams[] params, + RttManager.RttListener listener) { + if (VDBG) { + Log.v(TAG, "startRanging: sessionId=" + sessionId + ", " + "params=" + + Arrays.toString(params) + ", listener=" + listener); + } + + int clientId; + synchronized (mLock) { + if (mClientId == INVALID_CLIENT_ID) { + Log.e(TAG, "startRanging(): called with invalid client ID - not connected first?"); + return; + } + + clientId = mClientId; + } + + int rangingKey = 0; try { + rangingKey = mService.startRanging(clientId, sessionId, + new RttManager.ParcelableRttParams(params)); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + + synchronized (mLock) { + mRangingListeners.put(rangingKey, listener); + } + } + + private static class WifiNanEventCallbackProxy extends IWifiNanEventCallback.Stub { + 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<WifiNanManager> mNanManager; + + RttManager.RttListener getAndRemoveRangingListener(int rangingId) { + WifiNanManager mgr = mNanManager.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 WifiNanEventCallback} using the specified looper. + * I.e. all callbacks will delivered on the thread of the specified looper. + * + * @param looper The looper on which to execute the callbacks. + */ + WifiNanEventCallbackProxy(WifiNanManager mgr, Looper looper, + final WifiNanEventCallback originalCallback) { + mNanManager = new WeakReference<>(mgr); + + if (VDBG) Log.v(TAG, "WifiNanEventCallbackProxy ctor: looper=" + looper); + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + if (DBG) { + Log.d(TAG, "WifiNanEventCallbackProxy: What=" + msg.what + ", msg=" + msg); + } + + WifiNanManager mgr = mNanManager.get(); + if (mgr == null) { + Log.w(TAG, "WifiNanEventCallbackProxy: handleMessage post GC"); + return; + } + + switch (msg.what) { + case CALLBACK_CONNECT_SUCCESS: + originalCallback.onConnectSuccess(); + break; + case CALLBACK_CONNECT_FAIL: + synchronized (mgr.mLock) { + mgr.mLooper = null; + mgr.mClientId = INVALID_CLIENT_ID; + } + mNanManager.clear(); + originalCallback.onConnectFail(msg.arg1); + break; + case CALLBACK_IDENTITY_CHANGED: + originalCallback.onIdentityChanged(); + 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; + } + } + } + }; + } + + @Override + public void onConnectSuccess() { + if (VDBG) Log.v(TAG, "onConnectSuccess"); + + Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_SUCCESS); + mHandler.sendMessage(msg); + } + + @Override + public void onConnectFail(int reason) { + if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_CONNECT_FAIL); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onIdentityChanged() { + if (VDBG) Log.v(TAG, "onIdentityChanged"); + + Message msg = mHandler.obtainMessage(CALLBACK_IDENTITY_CHANGED); + mHandler.sendMessage(msg); + } + + @Override + public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) { if (VDBG) { - Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId - + ", messageLength=" + messageLength + ", messageId=" + messageId); + Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results); } - mService.sendMessage(sessionId, peerId, message, messageLength, messageId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + + 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 WifiNanSessionCallbackProxy extends IWifiNanSessionCallback.Stub { + private static final int CALLBACK_SESSION_STARTED = 0; + private static final int CALLBACK_SESSION_CONFIG_SUCCESS = 1; + private static final int CALLBACK_SESSION_CONFIG_FAIL = 2; + private static final int CALLBACK_SESSION_TERMINATED = 3; + private static final int CALLBACK_MATCH = 4; + 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 String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id"; + private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; + private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; + + private final WeakReference<WifiNanManager> mNanManager; + private final boolean mIsPublish; + private final WifiNanSessionCallback mOriginalCallback; + + private final Handler mHandler; + private WifiNanSession mSession; + + WifiNanSessionCallbackProxy(WifiNanManager mgr, Looper looper, boolean isPublish, + WifiNanSessionCallback originalCallback) { + mNanManager = new WeakReference<>(mgr); + mIsPublish = isPublish; + mOriginalCallback = originalCallback; + + if (VDBG) Log.v(TAG, "WifiNanSessionCallbackProxy ctor: isPublish=" + isPublish); + + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); + + if (mNanManager.get() == null) { + Log.w(TAG, "WifiNanSessionCallbackProxy: handleMessage post GC"); + return; + } + + switch (msg.what) { + case CALLBACK_SESSION_STARTED: + onProxySessionStarted(msg.arg1); + break; + case CALLBACK_SESSION_CONFIG_SUCCESS: + mOriginalCallback.onSessionConfigSuccess(); + break; + case CALLBACK_SESSION_CONFIG_FAIL: + mOriginalCallback.onSessionConfigFail(msg.arg1); + if (mSession == null) { + /* + * creation failed (as opposed to update + * failing) + */ + mNanManager.clear(); + } + break; + case CALLBACK_SESSION_TERMINATED: + onProxySessionTerminated(msg.arg1); + break; + case CALLBACK_MATCH: + mOriginalCallback.onMatch( + msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID), + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + msg.arg1, + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), + msg.arg2); + break; + case CALLBACK_MESSAGE_SEND_SUCCESS: + mOriginalCallback.onMessageSendSuccess(msg.arg1); + break; + case CALLBACK_MESSAGE_SEND_FAIL: + mOriginalCallback.onMessageSendFail(msg.arg1, msg.arg2); + break; + case CALLBACK_MESSAGE_RECEIVED: + mOriginalCallback.onMessageReceived(msg.arg2, + msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), + msg.arg1); + break; + } + } + }; + } + + @Override + public void onSessionStarted(int sessionId) { + if (VDBG) Log.v(TAG, "onSessionStarted: sessionId=" + sessionId); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_STARTED); + msg.arg1 = sessionId; + mHandler.sendMessage(msg); + } + + @Override + public void onSessionConfigSuccess() { + if (VDBG) Log.v(TAG, "onSessionConfigSuccess"); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_SUCCESS); + mHandler.sendMessage(msg); + } + + @Override + public void onSessionConfigFail(int reason) { + if (VDBG) Log.v(TAG, "onSessionConfigFail: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_CONFIG_FAIL); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onSessionTerminated(int reason) { + if (VDBG) Log.v(TAG, "onSessionTerminated: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_SESSION_TERMINATED); + msg.arg1 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onMatch(int peerId, byte[] serviceSpecificInfo, + int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { + if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); + + Bundle data = new Bundle(); + data.putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); + + Message msg = mHandler.obtainMessage(CALLBACK_MATCH); + msg.arg1 = serviceSpecificInfoLength; + msg.arg2 = matchFilterLength; + msg.setData(data); + mHandler.sendMessage(msg); + } + + @Override + public void onMessageSendSuccess(int messageId) { + if (VDBG) Log.v(TAG, "onMessageSendSuccess"); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_SUCCESS); + msg.arg1 = messageId; + mHandler.sendMessage(msg); + } + + @Override + public void onMessageSendFail(int messageId, int reason) { + if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_SEND_FAIL); + msg.arg1 = messageId; + msg.arg2 = reason; + mHandler.sendMessage(msg); + } + + @Override + public void onMessageReceived(int peerId, byte[] message, int messageLength) { + if (VDBG) { + Log.v(TAG, "onMessageReceived: peerId='" + peerId + "', messageLength=" + + messageLength); + } + + Bundle data = new Bundle(); + data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message); + + Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED); + msg.arg1 = messageLength; + msg.arg2 = peerId; + msg.setData(data); + mHandler.sendMessage(msg); + } + + /* + * Proxied methods + */ + public void onProxySessionStarted(int sessionId) { + if (VDBG) Log.v(TAG, "Proxy: onSessionStarted: sessionId=" + sessionId); + if (mSession != null) { + Log.e(TAG, + "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); + throw new IllegalStateException( + "onSessionStarted: sessionId=" + sessionId + ": session already created!?"); + } + + WifiNanManager mgr = mNanManager.get(); + if (mgr == null) { + Log.w(TAG, "onProxySessionStarted: mgr GC'd"); + return; + } + + if (mIsPublish) { + WifiNanPublishSession session = new WifiNanPublishSession(mgr, sessionId); + mSession = session; + mOriginalCallback.onPublishStarted(session); + } else { + WifiNanSubscribeSession session = new WifiNanSubscribeSession(mgr, sessionId); + mSession = session; + mOriginalCallback.onSubscribeStarted(session); + } + } + + public void onProxySessionTerminated(int reason) { + if (VDBG) Log.v(TAG, "Proxy: onSessionTerminated: reason=" + reason); + if (mSession != null) { + mSession.setTerminated(); + mSession = null; + } else { + Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?"); + } + mNanManager.clear(); + mOriginalCallback.onSessionTerminated(reason); } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java index 81b38f4c12a3..a0e3fbad36c9 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java @@ -16,15 +16,20 @@ package android.net.wifi.nan; +import android.annotation.NonNull; +import android.util.Log; + /** * A representation of a NAN publish session. Created when - * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)} - * is executed. The object can be used to stop and re-start (re-configure) the + * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} is + * executed. The object can be used to stop and re-start (re-configure) the * publish session. * * @hide PROPOSED_NAN_API */ public class WifiNanPublishSession extends WifiNanSession { + private static final String TAG = "WifiNanPublishSession"; + /** * {@hide} */ @@ -33,15 +38,25 @@ public class WifiNanPublishSession extends WifiNanSession { } /** - * Restart/re-configure the publish session. Note that the - * {@link WifiNanSessionListener} is not replaced - the same listener used at - * creation is still used. + * Re-configure the publish session. Note that the + * {@link WifiNanSessionCallback} is not replaced - the same listener used + * at creation is still used. * - * @param publishData The data ({@link PublishData}) to publish. - * @param publishSettings The settings ({@link PublishSettings}) of the + * @param publishConfig The configuration ({@link PublishConfig}) of the * publish session. */ - public void publish(PublishData publishData, PublishSettings publishSettings) { - mManager.publish(mSessionId, publishData, publishSettings); + public void updatePublish(@NonNull PublishConfig publishConfig) { + if (mTerminated) { + Log.w(TAG, "updatePublish: called on terminated session"); + return; + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "updatePublish: called post GC on WifiNanManager"); + return; + } + + mgr.updatePublish(mSessionId, publishConfig); + } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java index bc1787fee478..3533c02184b3 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java @@ -16,8 +16,11 @@ package android.net.wifi.nan; +import android.net.wifi.RttManager; import android.util.Log; +import java.lang.ref.WeakReference; + /** * A representation of a single publish or subscribe NAN session. This object * will not be created directly - only its child classes are available: @@ -30,20 +33,22 @@ public class WifiNanSession { private static final boolean DBG = false; private static final boolean VDBG = false; // STOPSHIP if true + public static final int MAX_SEND_RETRY_COUNT = 5; + /** - * {@hide} + * @hide */ - protected WifiNanManager mManager; + protected WeakReference<WifiNanManager> mMgr; /** - * {@hide} + * @hide */ - protected int mSessionId; + protected final int mSessionId; /** - * {@hide} + * @hide */ - private boolean mDestroyed; + protected boolean mTerminated = false; /** * {@hide} @@ -51,63 +56,129 @@ public class WifiNanSession { public WifiNanSession(WifiNanManager manager, int sessionId) { if (VDBG) Log.v(TAG, "New client created: manager=" + manager + ", sessionId=" + sessionId); - mManager = manager; + mMgr = new WeakReference<>(manager); mSessionId = sessionId; - mDestroyed = false; } /** * Terminate the current publish or subscribe session - i.e. stop * transmitting packet on-air (for an active session) or listening for - * matches (for a passive session). Note that the session may still receive - * incoming messages and may be re-configured/re-started at a later time. + * matches (for a passive session). The session may not be used for any + * additional operations are termination. */ - public void stop() { - mManager.stopSession(mSessionId); + public void terminate() { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "terminate: called post GC on WifiNanManager"); + return; + } + mgr.terminateSession(mSessionId); + mTerminated = true; + mMgr.clear(); } /** - * Destroy the current publish or subscribe session. Performs a - * {@link WifiNanSession#stop()} function but in addition destroys the session - - * it will not be able to receive any messages or to be restarted at a later - * time. + * Sets the status of the session to terminated - i.e. an indication that + * already terminated rather than executing a termination. + * + * @hide */ - public void destroy() { - mManager.destroySession(mSessionId); - mDestroyed = true; + public void setTerminated() { + if (mTerminated) { + Log.w(TAG, "terminate: already terminated."); + return; + } + mTerminated = true; + mMgr.clear(); } - /** - * {@hide} - */ @Override protected void finalize() throws Throwable { - if (!mDestroyed) { + if (!mTerminated) { Log.w(TAG, "WifiNanSession mSessionId=" + mSessionId - + " was not explicitly destroyed. The session may use resources until " - + "destroyed so step should be done explicitly"); + + " was not explicitly terminated. The session may use resources until " + + "terminated so step should be done explicitly"); + terminate(); } - destroy(); + super.finalize(); } /** - * Sends a message to the specified destination. Message transmission is - * part of the current discovery session - i.e. executed subsequent to a - * publish/subscribe - * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)} - * event. + * Sends a message to the specified destination. Message transmission is part of the current + * discovery session - i.e. executed subsequent to a publish/subscribe + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} event. * * @param peerId The peer's ID for the message. Must be a result of an - * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)} - * event. + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} event. * @param message The message to be transmitted. - * @param messageLength The number of bytes from the {@code message} to be - * transmitted. - * @param messageId An arbitrary integer used by the caller to identify the - * message. The same integer ID will be returned in the callbacks - * indicated message send success or failure. + * @param messageLength The number of bytes from the {@code message} to be transmitted. + * @param messageId An arbitrary integer used by the caller to identify the message. The same + * integer ID will be returned in the callbacks indicated message send success or + * failure. + * @param retryCount An integer specifying how many additional service-level (as opposed to PHY + * or MAC level) retries should be attempted if there is no ACK from the receiver + * (note: no retransmissions are attempted in other failure cases). A value of 0 + * indicates no retries. Max possible value is {@link #MAX_SEND_RETRY_COUNT}. + */ + public void sendMessage(int peerId, byte[] message, int messageLength, int messageId, + int retryCount) { + if (mTerminated) { + Log.w(TAG, "sendMessage: called on terminated session"); + return; + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "sendMessage: called post GC on WifiNanManager"); + return; + } + + mgr.sendMessage(mSessionId, peerId, message, messageLength, messageId, retryCount); + } + } + + /** + * Sends a message to the specified destination. Message transmission is part of the current + * discovery session - i.e. executed subsequent to a publish/subscribe + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} event. This is + * equivalent to {@link #sendMessage(int, byte[], int, int, int)} with a {@code retryCount} of + * 0. + * + * @param peerId The peer's ID for the message. Must be a result of an + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} event. + * @param message The message to be transmitted. + * @param messageLength The number of bytes from the {@code message} to be transmitted. + * @param messageId An arbitrary integer used by the caller to identify the message. The same + * integer ID will be returned in the callbacks indicated message send success or + * failure. */ public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) { - mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId); + sendMessage(peerId, message, messageLength, messageId, 0); + } + + /** + * Start a ranging operation with the specified peers. The peer IDs are obtained from an + * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)} or + * {@link WifiNanSessionCallback#onMessageReceived(int, byte[], int)} operation - i.e. 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. + */ + public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) { + if (mTerminated) { + Log.w(TAG, "startRanging: called on terminated session"); + return; + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "startRanging: called post GC on WifiNanManager"); + return; + } + + mgr.startRanging(mSessionId, params, listener); + } } } diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java new file mode 100644 index 000000000000..b1f41006413b --- /dev/null +++ b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2016 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.nan; + +import android.annotation.IntDef; +import android.annotation.NonNull; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base class for NAN session events callbacks. Should be extended by + * applications wanting notifications. The callbacks are registered when a + * publish or subscribe session is created using + * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback)} or + * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} . + * These are callbacks applying to a specific NAN session. + * <p> + * A single callback is registered at session creation - it cannot be replaced. + * + * @hide PROPOSED_NAN_API + */ +public class WifiNanSessionCallback { + @IntDef({ + REASON_NO_RESOURCES, REASON_INVALID_ARGS, REASON_NO_MATCH_SESSION, + REASON_TX_FAIL, REASON_OTHER }) + @Retention(RetentionPolicy.SOURCE) + public @interface SessionReasonCodes { + } + + @IntDef({ + TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL }) + @Retention(RetentionPolicy.SOURCE) + public @interface SessionTerminateCodes { + } + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates no resources to execute the requested operation. + */ + public static final int REASON_NO_RESOURCES = 0; + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates invalid argument in the requested operation. + */ + public static final int REASON_INVALID_ARGS = 1; + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates a message is transmitted without a match (i.e. a discovery) + * occurring first. + */ + public static final int REASON_NO_MATCH_SESSION = 2; + + /** + * Failure reason flag for + * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} callback. + * Indicates transmission failure: this may be due to local transmission + * failure or to no ACK received - i.e. remote device didn't receive the + * sent message. + */ + public static final int REASON_TX_FAIL = 3; + + /** + * Failure reason flag for {@link WifiNanSessionCallback} callbacks. + * Indicates an unspecified error occurred during the operation. + */ + public static final int REASON_OTHER = 4; + + /** + * Failure reason flag for + * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback. + * Indicates that publish or subscribe session is done - i.e. all the + * requested operations (per {@link PublishConfig} or + * {@link SubscribeConfig}) have been executed. + */ + public static final int TERMINATE_REASON_DONE = 100; + + /** + * Failure reason flag for + * {@link WifiNanSessionCallback#onSessionTerminated(int)} callback. + * Indicates that publish or subscribe session is terminated due to a + * failure. + */ + public static final int TERMINATE_REASON_FAIL = 101; + + /** + * Called when a publish operation is started successfully. + * + * @param session The {@link WifiNanPublishSession} used to control the + * discovery session. + */ + public void onPublishStarted(@NonNull WifiNanPublishSession session) { + /* empty */ + } + + /** + * Called when a subscribe operation is started successfully. + * + * @param session The {@link WifiNanSubscribeSession} used to control the + * discovery session. + */ + public void onSubscribeStarted(@NonNull WifiNanSubscribeSession session) { + /* empty */ + } + + /** + * Called when a session update configuration (publish or subscribe update) + * succeeds. + */ + public void onSessionConfigSuccess() { + /* empty */ + } + + /** + * Called when a session configuration (publish or subscribe setup or + * update) fails. + * + * @param reason The failure reason using + * {@code WifiNanSessionCallback.REASON_*} codes. + */ + public void onSessionConfigFail(@SessionReasonCodes int reason) { + /* empty */ + } + + /** + * Called when a session (publish or subscribe) terminates. + * + * @param reason The termination reason using + * {@code WifiNanSessionCallback.TERMINATE_*} codes. + */ + public void onSessionTerminated(@SessionTerminateCodes int reason) { + /* empty */ + } + + /** + * Called when a discovery (publish or subscribe) operation results in a + * match - i.e. when a peer is discovered. + * + * @param peerId The ID of the peer matching our discovery operation. + * @param serviceSpecificInfo The service specific information (arbitrary + * byte array) provided by the peer as part of its discovery + * packet. + * @param serviceSpecificInfoLength The length of the service specific + * information array. + * @param matchFilter The filter (Tx on advertiser and Rx on listener) which + * resulted in this match. + * @param matchFilterLength The length of the match filter array. + */ + public void onMatch(int peerId, byte[] serviceSpecificInfo, + int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { + /* empty */ + } + + /** + * Called when a message is transmitted successfully - i.e. when we know + * that it was received successfully (corresponding to an ACK being + * received). + * <p> + * Note that either this callback or + * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be + * received - never both. + */ + public void onMessageSendSuccess(@SuppressWarnings("unused") int messageId) { + /* empty */ + } + + /** + * Called when a message transmission fails - i.e. when no ACK is received. + * The hardware will usually attempt to re-transmit several times - this + * event is received after all retries are exhausted. There is a possibility + * that message was received by the destination successfully but the ACK was + * lost + * <p> + * Note that either this callback or + * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received + * - never both + * + * @param reason The failure reason using + * {@code WifiNanSessionCallback.REASON_*} codes. + */ + public void onMessageSendFail(@SuppressWarnings("unused") int messageId, + @SessionReasonCodes int reason) { + /* empty */ + } + + /** + * Called when a message is received from a discovery session peer. + * + * @param peerId The ID of the peer sending the message. + * @param message A byte array containing the message. + * @param messageLength The length of the byte array containing the relevant + * message bytes. + */ + public void onMessageReceived(int peerId, byte[] message, int messageLength) { + /* empty */ + } +} diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java deleted file mode 100644 index b9af7def6868..000000000000 --- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (C) 2016 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.nan; - -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -/** - * Base class for NAN session events callbacks. Should be extended by - * applications wanting notifications. The callbacks are registered when a - * publish or subscribe session is created using - * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)} - * or - * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)} - * . These are callbacks applying to a specific NAN session. Events - * corresponding to the NAN link are delivered using {@link WifiNanEventListener}. - * <p> - * A single listener is registered at session creation - it cannot be replaced. - * <p> - * During registration specify which specific events are desired using a set of - * {@code NanSessionListener.LISTEN_*} flags OR'd together. Only those events - * will be delivered to the registered listener. Override those callbacks - * {@code NanSessionListener.on*} for the registered events. - * - * @hide PROPOSED_NAN_API - */ -public class WifiNanSessionListener { - private static final String TAG = "WifiNanSessionListener"; - private static final boolean DBG = false; - private static final boolean VDBG = false; // STOPSHIP if true - - /** - * Publish fail callback event registration flag. Corresponding callback is - * {@link WifiNanSessionListener#onPublishFail(int)}. - * - * @hide - */ - public static final int LISTEN_PUBLISH_FAIL = 0x1 << 0; - - /** - * Publish terminated callback event registration flag. Corresponding - * callback is {@link WifiNanSessionListener#onPublishTerminated(int)}. - */ - public static final int LISTEN_PUBLISH_TERMINATED = 0x1 << 1; - - /** - * Subscribe fail callback event registration flag. Corresponding callback - * is {@link WifiNanSessionListener#onSubscribeFail(int)}. - * - * @hide - */ - public static final int LISTEN_SUBSCRIBE_FAIL = 0x1 << 2; - - /** - * Subscribe terminated callback event registration flag. Corresponding - * callback is {@link WifiNanSessionListener#onSubscribeTerminated(int)}. - */ - public static final int LISTEN_SUBSCRIBE_TERMINATED = 0x1 << 3; - - /** - * Match (discovery: publish or subscribe) callback event registration flag. - * Corresponding callback is - * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}. - * - * @hide - */ - public static final int LISTEN_MATCH = 0x1 << 4; - - /** - * Message sent successfully callback event registration flag. Corresponding - * callback is {@link WifiNanSessionListener#onMessageSendSuccess()}. - * - * @hide - */ - public static final int LISTEN_MESSAGE_SEND_SUCCESS = 0x1 << 5; - - /** - * Message sending failure callback event registration flag. Corresponding - * callback is {@link WifiNanSessionListener#onMessageSendFail(int)}. - * - * @hide - */ - public static final int LISTEN_MESSAGE_SEND_FAIL = 0x1 << 6; - - /** - * Message received callback event registration flag. Corresponding callback - * is {@link WifiNanSessionListener#onMessageReceived(int, byte[], int)}. - * - * @hide - */ - public static final int LISTEN_MESSAGE_RECEIVED = 0x1 << 7; - - /** - * List of hidden events: which are mandatory - i.e. they will be added to - * every request. - * - * @hide - */ - public static final int LISTEN_HIDDEN_FLAGS = LISTEN_PUBLISH_FAIL | LISTEN_SUBSCRIBE_FAIL - | LISTEN_MATCH | LISTEN_MESSAGE_SEND_SUCCESS | LISTEN_MESSAGE_SEND_FAIL - | LISTEN_MESSAGE_RECEIVED; - - /** - * Failure reason flag for {@link WifiNanEventListener} and - * {@link WifiNanSessionListener} callbacks. Indicates no resources to execute - * the requested operation. - */ - public static final int FAIL_REASON_NO_RESOURCES = 0; - - /** - * Failure reason flag for {@link WifiNanEventListener} and - * {@link WifiNanSessionListener} callbacks. Indicates invalid argument in the - * requested operation. - */ - public static final int FAIL_REASON_INVALID_ARGS = 1; - - /** - * Failure reason flag for {@link WifiNanEventListener} and - * {@link WifiNanSessionListener} callbacks. Indicates a message is transmitted - * without a match (i.e. a discovery) occurring first. - */ - public static final int FAIL_REASON_NO_MATCH_SESSION = 2; - - /** - * Failure reason flag for {@link WifiNanEventListener} and - * {@link WifiNanSessionListener} callbacks. Indicates an unspecified error - * occurred during the operation. - */ - public static final int FAIL_REASON_OTHER = 3; - - /** - * Failure reason flag for - * {@link WifiNanSessionListener#onPublishTerminated(int)} and - * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks. - * Indicates that publish or subscribe session is done - i.e. all the - * requested operations (per {@link PublishSettings} or - * {@link SubscribeSettings}) have been executed. - */ - public static final int TERMINATE_REASON_DONE = 0; - - /** - * Failure reason flag for - * {@link WifiNanSessionListener#onPublishTerminated(int)} and - * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks. - * Indicates that publish or subscribe session is terminated due to a - * failure. - */ - public static final int TERMINATE_REASON_FAIL = 1; - - private static final String MESSAGE_BUNDLE_KEY_PEER_ID = "peer_id"; - private static final String MESSAGE_BUNDLE_KEY_MESSAGE = "message"; - private static final String MESSAGE_BUNDLE_KEY_MESSAGE2 = "message2"; - - private final Handler mHandler; - - /** - * Constructs a {@link WifiNanSessionListener} using the looper of the current - * thread. I.e. all callbacks will be delivered on the current thread. - */ - public WifiNanSessionListener() { - this(Looper.myLooper()); - } - - /** - * Constructs a {@link WifiNanSessionListener} using the specified looper. I.e. - * all callbacks will delivered on the thread of the specified looper. - * - * @param looper The looper on which to execute the callbacks. - */ - public WifiNanSessionListener(Looper looper) { - if (VDBG) Log.v(TAG, "ctor: looper=" + looper); - mHandler = new Handler(looper) { - @Override - public void handleMessage(Message msg) { - if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg); - switch (msg.what) { - case LISTEN_PUBLISH_FAIL: - WifiNanSessionListener.this.onPublishFail(msg.arg1); - break; - case LISTEN_PUBLISH_TERMINATED: - WifiNanSessionListener.this.onPublishTerminated(msg.arg1); - break; - case LISTEN_SUBSCRIBE_FAIL: - WifiNanSessionListener.this.onSubscribeFail(msg.arg1); - break; - case LISTEN_SUBSCRIBE_TERMINATED: - WifiNanSessionListener.this.onSubscribeTerminated(msg.arg1); - break; - case LISTEN_MATCH: - WifiNanSessionListener.this.onMatch( - msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID), - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1, - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2); - break; - case LISTEN_MESSAGE_SEND_SUCCESS: - WifiNanSessionListener.this.onMessageSendSuccess(msg.arg1); - break; - case LISTEN_MESSAGE_SEND_FAIL: - WifiNanSessionListener.this.onMessageSendFail(msg.arg1, msg.arg2); - break; - case LISTEN_MESSAGE_RECEIVED: - WifiNanSessionListener.this.onMessageReceived(msg.arg2, - msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1); - break; - } - } - }; - } - - /** - * Called when a publish operation fails. It is dummy method (empty - * implementation printing out a log message). Override to implement your - * custom response. - * - * @param reason The failure reason using {@code NanSessionListener.FAIL_*} - * codes. - */ - public void onPublishFail(int reason) { - if (VDBG) Log.v(TAG, "onPublishFail: called in stub - override if interested"); - } - - /** - * Called when a publish operation terminates. Event will only be delivered - * if registered using {@link WifiNanSessionListener#LISTEN_PUBLISH_TERMINATED}. - * A dummy (empty implementation printing out a warning). Make sure to - * override if registered. - * - * @param reason The termination reason using - * {@code NanSessionListener.TERMINATE_*} codes. - */ - public void onPublishTerminated(int reason) { - Log.w(TAG, "onPublishTerminated: called in stub - override if interested or disable"); - } - - /** - * Called when a subscribe operation fails. It is dummy method (empty - * implementation printing out a log message). Override to implement your - * custom response. - * - * @param reason The failure reason using {@code NanSessionListener.FAIL_*} - * codes. - */ - public void onSubscribeFail(int reason) { - if (VDBG) Log.v(TAG, "onSubscribeFail: called in stub - override if interested"); - } - - /** - * Called when a subscribe operation terminates. Event will only be - * delivered if registered using - * {@link WifiNanSessionListener#LISTEN_SUBSCRIBE_TERMINATED}. A dummy (empty - * implementation printing out a warning). Make sure to override if - * registered. - * - * @param reason The termination reason using - * {@code NanSessionListener.TERMINATE_*} codes. - */ - public void onSubscribeTerminated(int reason) { - Log.w(TAG, "onSubscribeTerminated: called in stub - override if interested or disable"); - } - - /** - * Called when a discovery (publish or subscribe) operation results in a - * match - i.e. when a peer is discovered. It is dummy method (empty - * implementation printing out a log message). Override to implement your - * custom response. - * - * @param peerId The ID of the peer matching our discovery operation. - * @param serviceSpecificInfo The service specific information (arbitrary - * byte array) provided by the peer as part of its discovery - * packet. - * @param serviceSpecificInfoLength The length of the service specific - * information array. - * @param matchFilter The filter (Tx on advertiser and Rx on listener) which - * resulted in this match. - * @param matchFilterLength The length of the match filter array. - */ - public void onMatch(int peerId, byte[] serviceSpecificInfo, - int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { - if (VDBG) Log.v(TAG, "onMatch: called in stub - override if interested"); - } - - /** - * Called when a message is transmitted successfully - i.e. when we know - * that it was received successfully (corresponding to an ACK being - * received). It is dummy method (empty implementation printing out a log - * message). Override to implement your custom response. - * <p> - * Note that either this callback or - * {@link WifiNanSessionListener#onMessageSendFail(int, int)} will be - * received - never both. - */ - public void onMessageSendSuccess(int messageId) { - if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested"); - } - - /** - * Called when a message transmission fails - i.e. when no ACK is received. - * The hardware will usually attempt to re-transmit several times - this - * event is received after all retries are exhausted. There is a possibility - * that message was received by the destination successfully but the ACK was - * lost. It is dummy method (empty implementation printing out a log - * message). Override to implement your custom response. - * <p> - * Note that either this callback or - * {@link WifiNanSessionListener#onMessageSendSuccess(int)} will be received - * - never both - * - * @param reason The failure reason using {@code NanSessionListener.FAIL_*} - * codes. - */ - public void onMessageSendFail(int messageId, int reason) { - if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested"); - } - - /** - * Called when a message is received from a discovery session peer. It is - * dummy method (empty implementation printing out a log message). Override - * to implement your custom response. - * - * @param peerId The ID of the peer sending the message. - * @param message A byte array containing the message. - * @param messageLength The length of the byte array containing the relevant - * message bytes. - */ - public void onMessageReceived(int peerId, byte[] message, int messageLength) { - if (VDBG) Log.v(TAG, "onMessageReceived: called in stub - override if interested"); - } - - /** - * {@hide} - */ - public IWifiNanSessionListener callback = new IWifiNanSessionListener.Stub() { - @Override - public void onPublishFail(int reason) { - if (VDBG) Log.v(TAG, "onPublishFail: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_FAIL); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onPublishTerminated(int reason) { - if (VDBG) Log.v(TAG, "onPublishResponse: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_TERMINATED); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onSubscribeFail(int reason) { - if (VDBG) Log.v(TAG, "onSubscribeFail: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_FAIL); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onSubscribeTerminated(int reason) { - if (VDBG) Log.v(TAG, "onSubscribeTerminated: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_TERMINATED); - msg.arg1 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onMatch(int peerId, byte[] serviceSpecificInfo, - int serviceSpecificInfoLength, byte[] matchFilter, int matchFilterLength) { - if (VDBG) Log.v(TAG, "onMatch: peerId=" + peerId); - - Bundle data = new Bundle(); - data.putInt(MESSAGE_BUNDLE_KEY_PEER_ID, peerId); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter); - - Message msg = mHandler.obtainMessage(LISTEN_MATCH); - msg.arg1 = serviceSpecificInfoLength; - msg.arg2 = matchFilterLength; - msg.setData(data); - mHandler.sendMessage(msg); - } - - @Override - public void onMessageSendSuccess(int messageId) { - if (VDBG) Log.v(TAG, "onMessageSendSuccess"); - - Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS); - msg.arg1 = messageId; - mHandler.sendMessage(msg); - } - - @Override - public void onMessageSendFail(int messageId, int reason) { - if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason); - - Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL); - msg.arg1 = messageId; - msg.arg2 = reason; - mHandler.sendMessage(msg); - } - - @Override - public void onMessageReceived(int peerId, byte[] message, int messageLength) { - if (VDBG) { - Log.v(TAG, "onMessageReceived: peerId='" + peerId + "', messageLength=" - + messageLength); - } - - Bundle data = new Bundle(); - data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message); - - Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_RECEIVED); - msg.arg1 = messageLength; - msg.arg2 = peerId; - msg.setData(data); - mHandler.sendMessage(msg); - } - }; -} diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java index 7dfdd32a2f74..2e6d7695fb44 100644 --- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java +++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java @@ -16,15 +16,20 @@ package android.net.wifi.nan; +import android.annotation.NonNull; +import android.util.Log; + /** * A representation of a NAN subscribe session. Created when - * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)} - * is executed. The object can be used to stop and re-start (re-configure) the + * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback)} is + * executed. The object can be used to stop and re-start (re-configure) the * subscribe session. * * @hide PROPOSED_NAN_API */ public class WifiNanSubscribeSession extends WifiNanSession { + private static final String TAG = "WifiNanSubscribeSession"; + /** * {@hide} */ @@ -33,15 +38,25 @@ public class WifiNanSubscribeSession extends WifiNanSession { } /** - * Restart/re-configure the subscribe session. Note that the - * {@link WifiNanSessionListener} is not replaced - the same listener used at - * creation is still used. + * Re-configure the subscribe session. Note that the + * {@link WifiNanSessionCallback} is not replaced - the same listener used + * at creation is still used. * - * @param subscribeData The data ({@link SubscribeData}) to subscribe. - * @param subscribeSettings The settings ({@link SubscribeSettings}) of the + * @param subscribeConfig The configuration ({@link SubscribeConfig}) of the * subscribe session. */ - public void subscribe(SubscribeData subscribeData, SubscribeSettings subscribeSettings) { - mManager.subscribe(mSessionId, subscribeData, subscribeSettings); + public void updateSubscribe(@NonNull SubscribeConfig subscribeConfig) { + if (mTerminated) { + Log.w(TAG, "updateSubscribe: called on terminated session"); + return; + } else { + WifiNanManager mgr = mMgr.get(); + if (mgr == null) { + Log.w(TAG, "updateSubscribe: called post GC on WifiNanManager"); + return; + } + + mgr.updateSubscribe(mSessionId, subscribeConfig); + } } } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index a0cb035fb4d5..a68bcd98cac5 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -66,19 +66,28 @@ public class WifiP2pDevice implements Parcelable { /* Device Capability bitmap */ private static final int DEVICE_CAPAB_SERVICE_DISCOVERY = 1; + @SuppressWarnings("unused") private static final int DEVICE_CAPAB_CLIENT_DISCOVERABILITY = 1<<1; + @SuppressWarnings("unused") private static final int DEVICE_CAPAB_CONCURRENT_OPER = 1<<2; + @SuppressWarnings("unused") private static final int DEVICE_CAPAB_INFRA_MANAGED = 1<<3; + @SuppressWarnings("unused") private static final int DEVICE_CAPAB_DEVICE_LIMIT = 1<<4; private static final int DEVICE_CAPAB_INVITATION_PROCEDURE = 1<<5; /* Group Capability bitmap */ private static final int GROUP_CAPAB_GROUP_OWNER = 1; + @SuppressWarnings("unused") private static final int GROUP_CAPAB_PERSISTENT_GROUP = 1<<1; private static final int GROUP_CAPAB_GROUP_LIMIT = 1<<2; + @SuppressWarnings("unused") private static final int GROUP_CAPAB_INTRA_BSS_DIST = 1<<3; + @SuppressWarnings("unused") private static final int GROUP_CAPAB_CROSS_CONN = 1<<4; + @SuppressWarnings("unused") private static final int GROUP_CAPAB_PERSISTENT_RECONN = 1<<5; + @SuppressWarnings("unused") private static final int GROUP_CAPAB_GROUP_FORMATION = 1<<6; /** @@ -305,6 +314,7 @@ public class WifiP2pDevice implements Parcelable { return other.deviceAddress.equals(deviceAddress); } + @Override public String toString() { StringBuffer sbuf = new StringBuffer(); sbuf.append("Device: ").append(deviceName); @@ -320,6 +330,7 @@ public class WifiP2pDevice implements Parcelable { } /** Implement the Parcelable interface */ + @Override public int describeContents() { return 0; } @@ -340,6 +351,7 @@ public class WifiP2pDevice implements Parcelable { } /** Implement the Parcelable interface */ + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(deviceName); dest.writeString(deviceAddress); @@ -360,6 +372,7 @@ public class WifiP2pDevice implements Parcelable { /** Implement the Parcelable interface */ public static final Creator<WifiP2pDevice> CREATOR = new Creator<WifiP2pDevice>() { + @Override public WifiP2pDevice createFromParcel(Parcel in) { WifiP2pDevice device = new WifiP2pDevice(); device.deviceName = in.readString(); @@ -376,6 +389,7 @@ public class WifiP2pDevice implements Parcelable { return device; } + @Override public WifiP2pDevice[] newArray(int size) { return new WifiP2pDevice[size]; } |