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.StringJoiner; 36 37 /** 38 * Defines the ranging request to other devices. The ranging request is built using 39 * {@link RangingRequest.Builder}. 40 * A ranging request is executed using 41 * {@link WifiRttManager#startRanging(RangingRequest, java.util.concurrent.Executor, RangingResultCallback)}. 42 * <p> 43 * The ranging request is a batch request - specifying a set of devices (specified using 44 * {@link RangingRequest.Builder#addAccessPoint(ScanResult)} and 45 * {@link RangingRequest.Builder#addAccessPoints(List)}). 46 */ 47 public final class RangingRequest implements Parcelable { 48 private static final int MAX_PEERS = 10; 49 50 /** 51 * Returns the maximum number of peers to range which can be specified in a single {@code 52 * RangingRequest}. The limit applies no matter how the peers are added to the request, e.g. 53 * through {@link RangingRequest.Builder#addAccessPoint(ScanResult)} or 54 * {@link RangingRequest.Builder#addAccessPoints(List)}. 55 * 56 * @return Maximum number of peers. 57 */ getMaxPeers()58 public static int getMaxPeers() { 59 return MAX_PEERS; 60 } 61 62 /** @hide */ 63 public final List<ResponderConfig> mRttPeers; 64 65 /** @hide */ RangingRequest(List<ResponderConfig> rttPeers)66 private RangingRequest(List<ResponderConfig> rttPeers) { 67 mRttPeers = rttPeers; 68 } 69 70 @Override describeContents()71 public int describeContents() { 72 return 0; 73 } 74 75 @Override writeToParcel(Parcel dest, int flags)76 public void writeToParcel(Parcel dest, int flags) { 77 dest.writeList(mRttPeers); 78 } 79 80 public static final @android.annotation.NonNull Creator<RangingRequest> CREATOR = new Creator<RangingRequest>() { 81 @Override 82 public RangingRequest[] newArray(int size) { 83 return new RangingRequest[size]; 84 } 85 86 @Override 87 public RangingRequest createFromParcel(Parcel in) { 88 return new RangingRequest(in.readArrayList(null)); 89 } 90 }; 91 92 /** @hide */ 93 @Override toString()94 public String toString() { 95 StringJoiner sj = new StringJoiner(", ", "RangingRequest: mRttPeers=[", "]"); 96 for (ResponderConfig rc : mRttPeers) { 97 sj.add(rc.toString()); 98 } 99 return sj.toString(); 100 } 101 102 /** @hide */ enforceValidity(boolean awareSupported)103 public void enforceValidity(boolean awareSupported) { 104 if (mRttPeers.size() > MAX_PEERS) { 105 throw new IllegalArgumentException( 106 "Ranging to too many peers requested. Use getMaxPeers() API to get limit."); 107 } 108 109 for (ResponderConfig peer: mRttPeers) { 110 if (!peer.isValid(awareSupported)) { 111 throw new IllegalArgumentException("Invalid Responder specification"); 112 } 113 } 114 } 115 116 /** 117 * Builder class used to construct {@link RangingRequest} objects. 118 */ 119 public static final class Builder { 120 private List<ResponderConfig> mRttPeers = new ArrayList<>(); 121 122 /** 123 * Add the device specified by the {@link ScanResult} to the list of devices with 124 * which to measure range. The total number of peers added to a request cannot exceed the 125 * limit specified by {@link #getMaxPeers()}. 126 * <p> 127 * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use 128 * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If 129 * not supported the result status will be 130 * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}. 131 * 132 * @param apInfo Information of an Access Point (AP) obtained in a Scan Result. 133 * @return The builder to facilitate chaining 134 * {@code builder.setXXX(..).setXXX(..)}. 135 */ addAccessPoint(@onNull ScanResult apInfo)136 public Builder addAccessPoint(@NonNull ScanResult apInfo) { 137 if (apInfo == null) { 138 throw new IllegalArgumentException("Null ScanResult!"); 139 } 140 return addResponder(ResponderConfig.fromScanResult(apInfo)); 141 } 142 143 /** 144 * Add the devices specified by the {@link ScanResult}s to the list of devices with 145 * which to measure range. The total number of peers added to a request cannot exceed the 146 * limit specified by {@link #getMaxPeers()}. 147 * <p> 148 * Ranging may not be supported if the Access Point does not support IEEE 802.11mc. Use 149 * {@link ScanResult#is80211mcResponder()} to verify the Access Point's capabilities. If 150 * not supported the result status will be 151 * {@link RangingResult#STATUS_RESPONDER_DOES_NOT_SUPPORT_IEEE80211MC}. 152 * 153 * @param apInfos Information of an Access Points (APs) obtained in a Scan Result. 154 * @return The builder to facilitate chaining 155 * {@code builder.setXXX(..).setXXX(..)}. 156 */ addAccessPoints(@onNull List<ScanResult> apInfos)157 public Builder addAccessPoints(@NonNull List<ScanResult> apInfos) { 158 if (apInfos == null) { 159 throw new IllegalArgumentException("Null list of ScanResults!"); 160 } 161 for (ScanResult scanResult : apInfos) { 162 addAccessPoint(scanResult); 163 } 164 return this; 165 } 166 167 /** 168 * Add the device specified by the {@code peerMacAddress} to the list of devices with 169 * which to measure range. 170 * <p> 171 * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi 172 * Aware device may obtain its MAC address using the {@link IdentityChangedListener} 173 * provided to 174 * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}. 175 * <p> 176 * Note: in order to use this API the device must support Wi-Fi Aware 177 * {@link android.net.wifi.aware}. The peer device which is being ranged to must be 178 * configured to publish a service (with any name) with: 179 * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}. 180 * <li>Ranging enabled 181 * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}. 182 * 183 * @param peerMacAddress The MAC address of the Wi-Fi Aware peer. 184 * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. 185 */ addWifiAwarePeer(@onNull MacAddress peerMacAddress)186 public Builder addWifiAwarePeer(@NonNull MacAddress peerMacAddress) { 187 if (peerMacAddress == null) { 188 throw new IllegalArgumentException("Null peer MAC address"); 189 } 190 return addResponder( 191 ResponderConfig.fromWifiAwarePeerMacAddressWithDefaults(peerMacAddress)); 192 } 193 194 /** 195 * Add a device specified by a {@link PeerHandle} to the list of devices with which to 196 * measure range. 197 * <p> 198 * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g. 199 * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}. 200 * <p> 201 * Note: in order to use this API the device must support Wi-Fi Aware 202 * {@link android.net.wifi.aware}. The peer device which is being ranged to must be 203 * configured to publish a service (with any name) with: 204 * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}. 205 * <li>Ranging enabled 206 * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}. 207 * 208 * @param peerHandle The peer handler of the peer Wi-Fi Aware device. 209 * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. 210 */ addWifiAwarePeer(@onNull PeerHandle peerHandle)211 public Builder addWifiAwarePeer(@NonNull PeerHandle peerHandle) { 212 if (peerHandle == null) { 213 throw new IllegalArgumentException("Null peer handler (identifier)"); 214 } 215 216 return addResponder(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle)); 217 } 218 219 /** 220 * Add the Responder device specified by the {@link ResponderConfig} to the list of devices 221 * with which to measure range. The total number of peers added to the request cannot exceed 222 * the limit specified by {@link #getMaxPeers()}. 223 * 224 * @param responder Information on the RTT Responder. 225 * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}. 226 * 227 * @hide 228 */ 229 @SystemApi addResponder(@onNull ResponderConfig responder)230 public Builder addResponder(@NonNull ResponderConfig responder) { 231 if (responder == null) { 232 throw new IllegalArgumentException("Null Responder!"); 233 } 234 235 mRttPeers.add(responder); 236 return this; 237 } 238 239 /** 240 * Build {@link RangingRequest} given the current configurations made on the 241 * builder. 242 */ build()243 public RangingRequest build() { 244 return new RangingRequest(mRttPeers); 245 } 246 } 247 248 @Override equals(@ullable Object o)249 public boolean equals(@Nullable Object o) { 250 if (this == o) { 251 return true; 252 } 253 254 if (!(o instanceof RangingRequest)) { 255 return false; 256 } 257 258 RangingRequest lhs = (RangingRequest) o; 259 260 return mRttPeers.size() == lhs.mRttPeers.size() && mRttPeers.containsAll(lhs.mRttPeers); 261 } 262 263 @Override hashCode()264 public int hashCode() { 265 return mRttPeers.hashCode(); 266 } 267 } 268