1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi.aware;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 import java.util.Arrays;
23 
24 /**
25  * Defines a request object to configure a Wi-Fi Aware network. Built using
26  * {@link ConfigRequest.Builder}. Configuration is requested using
27  * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}.
28  * Note that the actual achieved configuration may be different from the
29  * requested configuration - since different applications may request different
30  * configurations.
31  *
32  * @hide
33  */
34 public final class ConfigRequest implements Parcelable {
35     /**
36      * Lower range of possible cluster ID.
37      */
38     public static final int CLUSTER_ID_MIN = 0;
39 
40     /**
41      * Upper range of possible cluster ID.
42      */
43     public static final int CLUSTER_ID_MAX = 0xFFFF;
44 
45     /**
46      * Indices for configuration variables which are specified per band.
47      */
48     public static final int NAN_BAND_24GHZ = 0;
49     public static final int NAN_BAND_5GHZ = 1;
50 
51     /**
52      * Magic values for Discovery Window (DW) interval configuration
53      */
54     public static final int DW_INTERVAL_NOT_INIT = -1;
55     public static final int DW_DISABLE = 0; // only valid for 5GHz
56 
57     /**
58      * Indicates whether 5G band support is requested.
59      */
60     public final boolean mSupport5gBand;
61 
62     /**
63      * Specifies the desired master preference.
64      */
65     public final int mMasterPreference;
66 
67     /**
68      * Specifies the desired lower range of the cluster ID. Must be lower then
69      * {@link ConfigRequest#mClusterHigh}.
70      */
71     public final int mClusterLow;
72 
73     /**
74      * Specifies the desired higher range of the cluster ID. Must be higher then
75      * {@link ConfigRequest#mClusterLow}.
76      */
77     public final int mClusterHigh;
78 
79     /**
80      * Specifies the discovery window interval for the device on NAN_BAND_*.
81      */
82     public final int mDiscoveryWindowInterval[];
83 
ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow, int clusterHigh, int discoveryWindowInterval[])84     private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
85             int clusterHigh, int discoveryWindowInterval[]) {
86         mSupport5gBand = support5gBand;
87         mMasterPreference = masterPreference;
88         mClusterLow = clusterLow;
89         mClusterHigh = clusterHigh;
90         mDiscoveryWindowInterval = discoveryWindowInterval;
91     }
92 
93     @Override
toString()94     public String toString() {
95         return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
96                 + mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
97                 + mClusterHigh + ", mDiscoveryWindowInterval="
98                 + Arrays.toString(mDiscoveryWindowInterval) + "]";
99     }
100 
101     @Override
describeContents()102     public int describeContents() {
103         return 0;
104     }
105 
106     @Override
writeToParcel(Parcel dest, int flags)107     public void writeToParcel(Parcel dest, int flags) {
108         dest.writeInt(mSupport5gBand ? 1 : 0);
109         dest.writeInt(mMasterPreference);
110         dest.writeInt(mClusterLow);
111         dest.writeInt(mClusterHigh);
112         dest.writeIntArray(mDiscoveryWindowInterval);
113     }
114 
115     public static final @android.annotation.NonNull Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
116         @Override
117         public ConfigRequest[] newArray(int size) {
118             return new ConfigRequest[size];
119         }
120 
121         @Override
122         public ConfigRequest createFromParcel(Parcel in) {
123             boolean support5gBand = in.readInt() != 0;
124             int masterPreference = in.readInt();
125             int clusterLow = in.readInt();
126             int clusterHigh = in.readInt();
127             int discoveryWindowInterval[] = in.createIntArray();
128 
129             return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
130                     discoveryWindowInterval);
131         }
132     };
133 
134     @Override
equals(Object o)135     public boolean equals(Object o) {
136         if (this == o) {
137             return true;
138         }
139 
140         if (!(o instanceof ConfigRequest)) {
141             return false;
142         }
143 
144         ConfigRequest lhs = (ConfigRequest) o;
145 
146         return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
147                 && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
148                 && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
149     }
150 
151     @Override
hashCode()152     public int hashCode() {
153         int result = 17;
154 
155         result = 31 * result + (mSupport5gBand ? 1 : 0);
156         result = 31 * result + mMasterPreference;
157         result = 31 * result + mClusterLow;
158         result = 31 * result + mClusterHigh;
159         result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval);
160 
161         return result;
162     }
163 
164     /**
165      * Verifies that the contents of the ConfigRequest are valid. Otherwise
166      * throws an IllegalArgumentException.
167      */
validate()168     public void validate() throws IllegalArgumentException {
169         if (mMasterPreference < 0) {
170             throw new IllegalArgumentException(
171                     "Master Preference specification must be non-negative");
172         }
173         if (mMasterPreference == 1 || mMasterPreference == 255 || mMasterPreference > 255) {
174             throw new IllegalArgumentException("Master Preference specification must not "
175                     + "exceed 255 or use 1 or 255 (reserved values)");
176         }
177         if (mClusterLow < CLUSTER_ID_MIN) {
178             throw new IllegalArgumentException("Cluster specification must be non-negative");
179         }
180         if (mClusterLow > CLUSTER_ID_MAX) {
181             throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
182         }
183         if (mClusterHigh < CLUSTER_ID_MIN) {
184             throw new IllegalArgumentException("Cluster specification must be non-negative");
185         }
186         if (mClusterHigh > CLUSTER_ID_MAX) {
187             throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
188         }
189         if (mClusterLow > mClusterHigh) {
190             throw new IllegalArgumentException(
191                     "Invalid argument combination - must have Cluster Low <= Cluster High");
192         }
193         if (mDiscoveryWindowInterval.length != 2) {
194             throw new IllegalArgumentException(
195                     "Invalid discovery window interval: must have 2 elements (2.4 & 5");
196         }
197         if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
198                 (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
199                 || mDiscoveryWindowInterval[NAN_BAND_24GHZ] > 5)) {
200             throw new IllegalArgumentException(
201                     "Invalid discovery window interval for 2.4GHz: valid is UNSET or [1,5]");
202         }
203         if (mDiscoveryWindowInterval[NAN_BAND_5GHZ] != DW_INTERVAL_NOT_INIT &&
204                 (mDiscoveryWindowInterval[NAN_BAND_5GHZ] < 0 // valid for 5GHz: [0-5]
205                 || mDiscoveryWindowInterval[NAN_BAND_5GHZ] > 5)) {
206             throw new IllegalArgumentException(
207                 "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
208         }
209 
210     }
211 
212     /**
213      * Builder used to build {@link ConfigRequest} objects.
214      */
215     public static final class Builder {
216         private boolean mSupport5gBand = true;
217         private int mMasterPreference = 0;
218         private int mClusterLow = CLUSTER_ID_MIN;
219         private int mClusterHigh = CLUSTER_ID_MAX;
220         private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
221 
222         /**
223          * Specify whether 5G band support is required in this request. Disabled by default.
224          *
225          * @param support5gBand Support for 5G band is required.
226          *
227          * @return The builder to facilitate chaining
228          *         {@code builder.setXXX(..).setXXX(..)}.
229          */
setSupport5gBand(boolean support5gBand)230         public Builder setSupport5gBand(boolean support5gBand) {
231             mSupport5gBand = support5gBand;
232             return this;
233         }
234 
235         /**
236          * Specify the Master Preference requested. The permitted range is 0 (the default) to
237          * 255 with 1 and 255 excluded (reserved).
238          *
239          * @param masterPreference The requested master preference
240          *
241          * @return The builder to facilitate chaining
242          *         {@code builder.setXXX(..).setXXX(..)}.
243          */
setMasterPreference(int masterPreference)244         public Builder setMasterPreference(int masterPreference) {
245             if (masterPreference < 0) {
246                 throw new IllegalArgumentException(
247                         "Master Preference specification must be non-negative");
248             }
249             if (masterPreference == 1 || masterPreference == 255 || masterPreference > 255) {
250                 throw new IllegalArgumentException("Master Preference specification must not "
251                         + "exceed 255 or use 1 or 255 (reserved values)");
252             }
253 
254             mMasterPreference = masterPreference;
255             return this;
256         }
257 
258         /**
259          * The Cluster ID is generated randomly for new Aware networks. Specify
260          * the lower range of the cluster ID. The upper range is specified using
261          * the {@link ConfigRequest.Builder#setClusterHigh(int)}. The permitted
262          * range is 0 (the default) to the value specified by
263          * {@link ConfigRequest.Builder#setClusterHigh(int)}. Equality of Low and High is
264          * permitted which restricts the Cluster ID to the specified value.
265          *
266          * @param clusterLow The lower range of the generated cluster ID.
267          *
268          * @return The builder to facilitate chaining
269          *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
270          */
setClusterLow(int clusterLow)271         public Builder setClusterLow(int clusterLow) {
272             if (clusterLow < CLUSTER_ID_MIN) {
273                 throw new IllegalArgumentException("Cluster specification must be non-negative");
274             }
275             if (clusterLow > CLUSTER_ID_MAX) {
276                 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
277             }
278 
279             mClusterLow = clusterLow;
280             return this;
281         }
282 
283         /**
284          * The Cluster ID is generated randomly for new Aware networks. Specify
285          * the lower upper of the cluster ID. The lower range is specified using
286          * the {@link ConfigRequest.Builder#setClusterLow(int)}. The permitted
287          * range is the value specified by
288          * {@link ConfigRequest.Builder#setClusterLow(int)} to 0xFFFF (the default). Equality of
289          * Low and High is permitted which restricts the Cluster ID to the specified value.
290          *
291          * @param clusterHigh The upper range of the generated cluster ID.
292          *
293          * @return The builder to facilitate chaining
294          *         {@code builder.setClusterLow(..).setClusterHigh(..)}.
295          */
setClusterHigh(int clusterHigh)296         public Builder setClusterHigh(int clusterHigh) {
297             if (clusterHigh < CLUSTER_ID_MIN) {
298                 throw new IllegalArgumentException("Cluster specification must be non-negative");
299             }
300             if (clusterHigh > CLUSTER_ID_MAX) {
301                 throw new IllegalArgumentException("Cluster specification must not exceed 0xFFFF");
302             }
303 
304             mClusterHigh = clusterHigh;
305             return this;
306         }
307 
308         /**
309          * The discovery window interval specifies the discovery windows in which the device will be
310          * awake. The configuration enables trading off latency vs. power (higher interval means
311          * higher discovery latency but lower power).
312          *
313          * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
314          * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
315          *                 the 5GHz band a value of 0 indicates that the device will not be awake
316          *                 for any discovery windows.
317          *
318          * @return The builder itself to facilitate chaining operations
319          *         {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
320          */
setDiscoveryWindowInterval(int band, int interval)321         public Builder setDiscoveryWindowInterval(int band, int interval) {
322             if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
323                 throw new IllegalArgumentException("Invalid band value");
324             }
325             if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
326                     || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
327                 throw new IllegalArgumentException(
328                         "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
329             }
330 
331             mDiscoveryWindowInterval[band] = interval;
332             return this;
333         }
334 
335         /**
336          * Build {@link ConfigRequest} given the current requests made on the
337          * builder.
338          */
build()339         public ConfigRequest build() {
340             if (mClusterLow > mClusterHigh) {
341                 throw new IllegalArgumentException(
342                         "Invalid argument combination - must have Cluster Low <= Cluster High");
343             }
344 
345             return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
346                     mDiscoveryWindowInterval);
347         }
348     }
349 }
350