• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.rtt;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.net.MacAddress;
23 import android.net.wifi.ScanResult;
24 import android.net.wifi.aware.AttachCallback;
25 import android.net.wifi.aware.DiscoverySessionCallback;
26 import android.net.wifi.aware.IdentityChangedListener;
27 import android.net.wifi.aware.PeerHandle;
28 import android.net.wifi.aware.WifiAwareManager;
29 import android.os.Handler;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.StringJoiner;
37 
38 /**
39  * Defines the ranging request to other devices. The ranging request is built using
40  * {@link RangingRequest.Builder}.
41  * A ranging request is executed using
42  * {@link WifiRttManager#startRanging(RangingRequest, java.util.concurrent.Executor, RangingResultCallback)}.
43  * <p>
44  * The ranging request is a batch request - specifying a set of devices (specified using
45  * {@link RangingRequest.Builder#addAccessPoint(ScanResult)} and
46  * {@link RangingRequest.Builder#addAccessPoints(List)}).
47  */
48 public final class RangingRequest implements Parcelable {
49     private static final int MAX_PEERS = 10;
50     private static final int DEFAULT_RTT_BURST_SIZE = 8;
51     private static final int MIN_RTT_BURST_SIZE = 2;
52     private static final int MAX_RTT_BURST_SIZE = 31;
53 
54     /**
55      * Returns the maximum number of peers to range which can be specified in a single {@code
56      * RangingRequest}. The limit applies no matter how the peers are added to the request, e.g.
57      * through {@link RangingRequest.Builder#addAccessPoint(ScanResult)} or
58      * {@link RangingRequest.Builder#addAccessPoints(List)}.
59      *
60      * @return Maximum number of peers.
61      */
getMaxPeers()62     public static int getMaxPeers() {
63         return MAX_PEERS;
64     }
65 
66     /**
67      * Returns the default RTT burst size used to determine the average range.
68      *
69      * @return the RTT burst size used by default
70      */
getDefaultRttBurstSize()71     public static int getDefaultRttBurstSize() {
72         return DEFAULT_RTT_BURST_SIZE;
73     }
74 
75     /**
76      * Returns the minimum RTT burst size that can be used to determine a average range.
77      *
78      * @return the minimum RTT burst size that can be used
79      */
getMinRttBurstSize()80     public static int getMinRttBurstSize() {
81         return MIN_RTT_BURST_SIZE;
82     }
83 
84     /**
85      * Returns the minimum RTT burst size that can be used to determine a average range.
86      *
87      * @return the maximum RTT burst size that can be used
88      */
getMaxRttBurstSize()89     public static int getMaxRttBurstSize() {
90         return MAX_RTT_BURST_SIZE;
91     }
92 
93     /** @hide */
94     public final List<ResponderConfig> mRttPeers;
95 
96     /** @hide */
97     public final int mRttBurstSize;
98 
99     /** @hide */
RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize)100     private RangingRequest(List<ResponderConfig> rttPeers, int rttBurstSize) {
101         mRttPeers = rttPeers;
102         mRttBurstSize = rttBurstSize;
103     }
104 
105     /**
106      * Returns the list of RTT capable responding peers.
107      *
108      * @return the list of RTT capable responding peers in a common system representation
109      *
110      * @hide
111      */
112     @SystemApi
113     @NonNull
getRttResponders()114     public List<ResponderConfig> getRttResponders() {
115         return mRttPeers;
116     }
117 
118     /**
119      * Returns the RTT burst size used to determine the average range.
120      *
121      * @return the RTT burst size used
122      */
getRttBurstSize()123     public int getRttBurstSize() {
124         return mRttBurstSize;
125     }
126 
127     @Override
describeContents()128     public int describeContents() {
129         return 0;
130     }
131 
132     @Override
writeToParcel(Parcel dest, int flags)133     public void writeToParcel(Parcel dest, int flags) {
134         dest.writeList(mRttPeers);
135         dest.writeInt(mRttBurstSize);
136     }
137 
138     public static final @android.annotation.NonNull Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() {
139         @Override
140         public RangingRequest[] newArray(int size) {
141             return new RangingRequest[size];
142         }
143 
144         @Override
145         public RangingRequest createFromParcel(Parcel in) {
146             return new RangingRequest(in.readArrayList(null), in.readInt());
147         }
148     };
149 
150     /** @hide */
151     @Override
toString()152     public String toString() {
153         StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", "]");
154         for (ResponderConfig rc : mRttPeers) {
155             sj.add(rc.toString());
156         }
157         return sj.toString();
158     }
159 
160     /** @hide */
enforceValidity(boolean awareSupported)161     public void enforceValidity(boolean awareSupported) {
162         if (mRttPeers.size() > MAX_PEERS) {
163             throw new IllegalArgumentException(
164                     "Ranging to too many peers requested. Use getMaxPeers() API to get limit.");
165         }
166         for (ResponderConfig peer: mRttPeers) {
167             if (!peer.isValid(awareSupported)) {
168                 throw new IllegalArgumentException("Invalid Responder specification");
169             }
170         }
171         if (mRttBurstSize < getMinRttBurstSize() || mRttBurstSize > getMaxRttBurstSize()) {
172             throw new IllegalArgumentException("RTT burst size is out of range");
173         }
174     }
175 
176     /**
177      * Builder class used to construct {@link RangingRequest} objects.
178      */
179     public static final class Builder {
180         private List<ResponderConfig> mRttPeers = new ArrayList<>();
181         private int mRttBurstSize = DEFAULT_RTT_BURST_SIZE;
182 
183         /**
184          * Set the RTT Burst size for the ranging request.
185          * <p>
186          * If not set, the default RTT burst size given by
187          * {@link #getDefaultRttBurstSize()} is used to determine the default value.
188          * If set, the value must be in the range {@link #getMinRttBurstSize()} and
189          * {@link #getMaxRttBurstSize()} inclusively, or a
190          * {@link java.lang.IllegalArgumentException} will be thrown.
191          *
192          * @param rttBurstSize The number of FTM packets used to estimate a range.
193          * @return The builder to facilitate chaining
194          * {@code builder.setXXX(..).setXXX(..)}.
195          */
196         @NonNull
setRttBurstSize(int rttBurstSize)197         public Builder setRttBurstSize(int rttBurstSize) {
198             if (rttBurstSize < MIN_RTT_BURST_SIZE || rttBurstSize > MAX_RTT_BURST_SIZE) {
199                 throw new IllegalArgumentException("RTT burst size out of range.");
200             }
201             mRttBurstSize = rttBurstSize;
202             return this;
203         }
204 
205         /**
206          * Add the device specified by the {@link ScanResult} to the list of devices with
207          * which to measure range. The total number of peers added to a request cannot exceed the
208          * limit specified by {@link #getMaxPeers()}.
209          * <p>
210          * Two-sided Ranging will be supported if the Access Point supports IEEE 802.11mc, also
211          * known as two-sided RTT, and this is determined by the method
212          * {@link ScanResult#is80211mcResponder()}. If not supported, one-sided RTT will be
213          * performed with no correction for the AP packet turnaround time.
214          *
215          * @param apInfo Information about an Access Point (AP) obtained in a Scan Result.
216          * @return The builder to facilitate chaining
217          *         {@code builder.setXXX(..).setXXX(..)}.
218          */
219         @NonNull
addAccessPoint(@onNull ScanResult apInfo)220         public Builder addAccessPoint(@NonNull ScanResult apInfo) {
221             if (apInfo == null) {
222                 throw new IllegalArgumentException("Null ScanResult!");
223             }
224             return addResponder(ResponderConfig.fromScanResult(apInfo));
225         }
226 
227         /**
228          * Add the devices specified by the {@link ScanResult}s to the list of devices with
229          * which to measure range. The total number of peers added to a request cannot exceed the
230          * limit specified by {@link #getMaxPeers()}.
231          * <p>
232          * Two-sided Ranging will be supported if the Access Point supports IEEE 802.11mc, also
233          * known as two-sided RTT, and this is determined by the method
234          * {@link ScanResult#is80211mcResponder()}. If not supported, one-sided RTT will be
235          * performed with no correction for the AP packet turnaround time.
236          *
237          * @param apInfos Information about Access Points (APs) obtained in a Scan Result.
238          * @return The builder to facilitate chaining
239          *         {@code builder.setXXX(..).setXXX(..)}.
240          */
241         @NonNull
addAccessPoints(@onNull List<ScanResult> apInfos)242         public Builder addAccessPoints(@NonNull List<ScanResult> apInfos) {
243             if (apInfos == null) {
244                 throw new IllegalArgumentException("Null list of ScanResults!");
245             }
246             for (ScanResult scanResult : apInfos) {
247                 addAccessPoint(scanResult);
248             }
249             return this;
250         }
251 
252         /**
253          * Add the Responder device specified by the {@link ResponderConfig} to the list of devices
254          * with which to measure range. The total number of peers added to the request cannot exceed
255          * the limit specified by {@link #getMaxPeers()}.
256          * <p>
257          * Two-sided Ranging will be supported if an Access Point supports IEEE 802.11mc, also
258          * known as two-sided RTT, and this is specified in the {@link ResponderConfig} builder.
259          * If not supported, one-sided RTT will be performed with no correction for
260          * the AP packet turnaround time.
261          *
262          * @param responder Information on the RTT Responder.
263          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
264          */
265         @NonNull
addResponder(@onNull ResponderConfig responder)266         public Builder addResponder(@NonNull ResponderConfig responder) {
267             if (responder == null) {
268                 throw new IllegalArgumentException("Null Responder!");
269             }
270 
271             mRttPeers.add(responder);
272             return this;
273         }
274 
275         /**
276          * Add the devices specified by the {@link ResponderConfig}s to the list of devices with
277          * which to measure range. The total number of peers added to a request cannot exceed the
278          * limit specified by {@link #getMaxPeers()}.
279          * <p>
280          * Two-sided Ranging will be supported if an Access Point supports IEEE 802.11mc, also
281          * known as two-sided RTT, and this is specified in the {@link ResponderConfig} builder.
282          * If not supported, one-sided RTT will be performed with no correction for the AP packet
283          * turnaround time.
284          *
285          * @param responders Information representing the set of access points to be ranged
286          * @return The builder to facilitate chaining
287          *         {@code builder.setXXX(..).setXXX(..)}.
288          */
289         @NonNull
addResponders(@onNull List<ResponderConfig> responders)290         public Builder addResponders(@NonNull List<ResponderConfig> responders) {
291             if (responders == null) {
292                 throw new IllegalArgumentException("Null list of Responders");
293             }
294             for (ResponderConfig responder : responders) {
295                 addResponder(responder);
296             }
297             return this;
298         }
299 
300         /**
301          * Add the non-802.11mc capable device specified by the {@link ScanResult} to the list of
302          * devices with which to measure range. The total number of peers added to a request cannot
303          * exceed the limit specified by {@link #getMaxPeers()}.
304          * <p>
305          * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc,
306          * and instead an alternate protocol called one-sided RTT will be used with lower
307          * accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access Point)s) are
308          * not 802.11mc capable.
309          * <p>
310          * One-sided RTT does not subtract the RTT turnaround time at the Access Point, which can
311          * add hundreds of meters to the estimate. With experimentation it is possible to use this
312          * information to make a statistical estimate of the range by taking multiple measurements
313          * to several Access Points and normalizing the result. For some applications this can be
314          * used to improve range estimates based on Receive Signal Strength Indication (RSSI), but
315          * will not be as accurate as IEEE 802.11mc (two-sided RTT).
316          * <p>
317          * Note: one-sided RTT should only be used if you are very familiar with statistical
318          * estimation techniques.
319          *
320          * @param apInfo Information about an Access Point (AP) obtained in a Scan Result
321          * @return The builder to facilitate chaining
322          *         {@code builder.setXXX(..).setXXX(..)}.
323          */
324         @NonNull
addNon80211mcCapableAccessPoint(@onNull ScanResult apInfo)325         public Builder addNon80211mcCapableAccessPoint(@NonNull ScanResult apInfo) {
326             if (apInfo == null) {
327                 throw new IllegalArgumentException("Null ScanResult!");
328             }
329             if (apInfo.is80211mcResponder()) {
330                 throw new IllegalArgumentException("AP supports the 802.11mc protocol.");
331             }
332             return addResponder(ResponderConfig.fromScanResult(apInfo));
333         }
334 
335         /**
336          * Add the non-802.11mc capable devices specified by the {@link ScanResult} to the list of
337          * devices with which to measure range. The total number of peers added to a request cannot
338          * exceed the limit specified by {@link #getMaxPeers()}.
339          * <p>
340          * Accurate ranging cannot be supported if the Access Point does not support IEEE 802.11mc,
341          * and instead an alternate protocol called one-sided RTT will be used with lower
342          * accuracy. Use {@link ScanResult#is80211mcResponder()} to verify the Access Point)s) are
343          * not 802.11mc capable.
344          * <p>
345          * One-sided RTT does not subtract the RTT turnaround time at the Access Point, which can
346          * add hundreds of meters to the estimate. With experimentation it is possible to use this
347          * information to make a statistical estimate of the range by taking multiple measurements
348          * to several Access Points and normalizing the result. For some applications this can be
349          * used to improve range estimates based on Receive Signal Strength Indication (RSSI), but
350          * will not be as accurate as IEEE 802.11mc (two-sided RTT).
351          * <p>
352          * Note: one-sided RTT should only be used if you are very familiar with statistical
353          * estimation techniques.
354          *
355          * @param apInfos Information about Access Points (APs) obtained in a Scan Result.
356          * @return The builder to facilitate chaining
357          *         {@code builder.setXXX(..).setXXX(..)}.
358          */
359         @NonNull
addNon80211mcCapableAccessPoints(@onNull List<ScanResult> apInfos)360         public Builder addNon80211mcCapableAccessPoints(@NonNull List<ScanResult> apInfos) {
361             if (apInfos == null) {
362                 throw new IllegalArgumentException("Null list of ScanResults!");
363             }
364             for (ScanResult scanResult : apInfos) {
365                 if (scanResult.is80211mcResponder()) {
366                     throw new IllegalArgumentException(
367                             "At least one AP supports the 802.11mc protocol.");
368                 }
369                 addAccessPoint(scanResult);
370             }
371             return this;
372         }
373 
374         /**
375          * Add the device specified by the {@code peerMacAddress} to the list of devices with
376          * which to measure range.
377          * <p>
378          * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi
379          * Aware device may obtain its MAC address using the {@link IdentityChangedListener}
380          * provided to
381          * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}.
382          * <p>
383          * Note: in order to use this API the device must support Wi-Fi Aware
384          * {@link android.net.wifi.aware}. The peer device which is being ranged to must be
385          * configured to publish a service (with any name) with:
386          * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}.
387          * <li>Ranging enabled
388          * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}.
389          *
390          * @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
391          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
392          */
addWifiAwarePeer(@onNull MacAddress peerMacAddress)393         public Builder addWifiAwarePeer(@NonNull MacAddress peerMacAddress) {
394             if (peerMacAddress == null) {
395                 throw new IllegalArgumentException("Null peer MAC address");
396             }
397             return addResponder(
398                     ResponderConfig.fromWifiAwarePeerMacAddressWithDefaults(peerMacAddress));
399         }
400 
401         /**
402          * Add a device specified by a {@link PeerHandle} to the list of devices with which to
403          * measure range.
404          * <p>
405          * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g.
406          * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}.
407          * <p>
408          * Note: in order to use this API the device must support Wi-Fi Aware
409          * {@link android.net.wifi.aware}. The requesting device can be either publisher or
410          * subscriber in a discovery session. For both requesting device and peer device ranging
411          * must be enabled on the discovery session:
412          * <li>{@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)} for
413          * publisher.</li>
414          * <li>Either {@link android.net.wifi.aware.SubscribeConfig.Builder#setMinDistanceMm(int)}
415          * or {@link android.net.wifi.aware.SubscribeConfig.Builder#setMaxDistanceMm(int)} must be
416          * set to enable ranging on subscriber </li>
417          *
418          * @param peerHandle The peer handler of the peer Wi-Fi Aware device.
419          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
420          */
addWifiAwarePeer(@onNull PeerHandle peerHandle)421         public Builder addWifiAwarePeer(@NonNull PeerHandle peerHandle) {
422             if (peerHandle == null) {
423                 throw new IllegalArgumentException("Null peer handler (identifier)");
424             }
425 
426             return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle));
427         }
428 
429 
430         /**
431          * Build {@link RangingRequest} given the current configurations made on the
432          * builder.
433          */
build()434         public RangingRequest build() {
435             return new RangingRequest(mRttPeers, mRttBurstSize);
436         }
437     }
438 
439     @Override
equals(@ullable Object o)440     public boolean equals(@Nullable Object o) {
441         if (this == o) {
442             return true;
443         }
444 
445         if (!(o instanceof RangingRequest)) {
446             return false;
447         }
448 
449         RangingRequest lhs = (RangingRequest) o;
450 
451         return mRttPeers.size() == lhs.mRttPeers.size()
452                 && mRttPeers.containsAll(lhs.mRttPeers)
453                 && mRttBurstSize == lhs.mRttBurstSize;
454     }
455 
456     @Override
hashCode()457     public int hashCode() {
458         return Objects.hash(mRttPeers, mRttBurstSize);
459     }
460 }
461