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