• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION;
20 
21 import static com.android.ranging.flags.Flags.FLAG_RANGING_RTT_ENABLED;
22 
23 import android.annotation.FlaggedApi;
24 import android.annotation.IntDef;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SystemApi;
29 import android.net.wifi.OuiKeyedData;
30 import android.net.wifi.ParcelUtil;
31 import android.net.wifi.ScanResult;
32 import android.net.wifi.WifiScanner;
33 import android.net.wifi.util.HexEncoding;
34 import android.os.Build;
35 import android.os.Parcel;
36 import android.os.Parcelable;
37 
38 import androidx.annotation.RequiresApi;
39 
40 import com.android.modules.utils.build.SdkLevel;
41 import com.android.wifi.flags.Flags;
42 
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.RetentionPolicy;
45 import java.nio.charset.StandardCharsets;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.List;
49 import java.util.Objects;
50 
51 /**
52  * Defines the configuration of an Aware publish session. Built using
53  * {@link PublishConfig.Builder}. A publish session is created using
54  * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
55  * android.os.Handler)} or updated using
56  * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
57  */
58 public final class PublishConfig implements Parcelable {
59     /** @hide */
60     @IntDef({
61             PUBLISH_TYPE_UNSOLICITED, PUBLISH_TYPE_SOLICITED })
62     @Retention(RetentionPolicy.SOURCE)
63     public @interface PublishTypes {
64     }
65 
66     /**
67      * Defines an unsolicited publish session - a publish session where the publisher is
68      * advertising itself by broadcasting on-the-air. An unsolicited publish session is paired
69      * with a passive subscribe session {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}.
70      * Configuration is done using {@link PublishConfig.Builder#setPublishType(int)}.
71      */
72     public static final int PUBLISH_TYPE_UNSOLICITED = 0;
73 
74     /**
75      * Defines a solicited publish session - a publish session which is silent, waiting for a
76      * matching active subscribe session - and responding to it in unicast. A
77      * solicited publish session is paired with an active subscribe session
78      * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Configuration is done using
79      * {@link PublishConfig.Builder#setPublishType(int)}.
80      */
81     public static final int PUBLISH_TYPE_SOLICITED = 1;
82 
83     /** @hide */
84     public final byte[] mServiceName;
85 
86     /** @hide */
87     public final byte[] mServiceSpecificInfo;
88 
89     /** @hide */
90     public final byte[] mMatchFilter;
91 
92     /** @hide */
93     public final int mPublishType;
94 
95     /** @hide */
96     public final int mTtlSec;
97 
98     /** @hide */
99     public final boolean mEnableTerminateNotification;
100 
101     /** @hide */
102     public final boolean mEnableRanging;
103 
104     private final boolean mEnableInstantMode;
105 
106     private final int mBand;
107 
108     private final WifiAwareDataPathSecurityConfig mSecurityConfig;
109 
110     private final AwarePairingConfig mPairingConfig;
111 
112     private final boolean mIsSuspendable;
113 
114     private final List<OuiKeyedData> mVendorData;
115 
116     /** @hide */
117     public final boolean mEnablePeriodicRangingResults;
118 
119     /** @hide */
PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter, int publishType, int ttlSec, boolean enableTerminateNotification, boolean enableRanging, boolean enableInstantMode, @WifiScanner.WifiBand int band, WifiAwareDataPathSecurityConfig securityConfig, AwarePairingConfig pairingConfig, boolean isSuspendable, @NonNull List<OuiKeyedData> vendorData, boolean enablePeriodicRangingResults)120     public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
121             int publishType, int ttlSec, boolean enableTerminateNotification,
122             boolean enableRanging, boolean enableInstantMode, @WifiScanner.WifiBand int
123             band, WifiAwareDataPathSecurityConfig securityConfig,
124             AwarePairingConfig pairingConfig, boolean isSuspendable,
125             @NonNull List<OuiKeyedData> vendorData, boolean enablePeriodicRangingResults) {
126         mServiceName = serviceName;
127         mServiceSpecificInfo = serviceSpecificInfo;
128         mMatchFilter = matchFilter;
129         mPublishType = publishType;
130         mTtlSec = ttlSec;
131         mEnableTerminateNotification = enableTerminateNotification;
132         mEnableRanging = enableRanging;
133         mEnableInstantMode = enableInstantMode;
134         mBand = band;
135         mSecurityConfig = securityConfig;
136         mPairingConfig = pairingConfig;
137         mIsSuspendable = isSuspendable;
138         mVendorData = vendorData;
139         mEnablePeriodicRangingResults = enablePeriodicRangingResults;
140     }
141 
142     @Override
toString()143     public String toString() {
144         return "PublishConfig [mServiceName='" + (mServiceName == null ? "<null>" : String.valueOf(
145                 HexEncoding.encode(mServiceName))) + ", mServiceName.length=" + (
146                 mServiceName == null ? 0 : mServiceName.length) + ", mServiceSpecificInfo='" + (
147                 (mServiceSpecificInfo == null) ? "<null>" : String.valueOf(
148                         HexEncoding.encode(mServiceSpecificInfo)))
149                 + ", mServiceSpecificInfo.length=" + (mServiceSpecificInfo == null ? 0
150                 : mServiceSpecificInfo.length) + ", mMatchFilter="
151                 + (new TlvBufferUtils.TlvIterable(0, 1, mMatchFilter)).toString()
152                 + ", mMatchFilter.length=" + (mMatchFilter == null ? 0 : mMatchFilter.length)
153                 + ", mPublishType=" + mPublishType + ", mTtlSec=" + mTtlSec
154                 + ", mEnableTerminateNotification=" + mEnableTerminateNotification
155                 + ", mEnableRanging=" + mEnableRanging + "]"
156                 + ", mEnableInstantMode=" + mEnableInstantMode
157                 + ", mBand=" + mBand
158                 + ", mSecurityConfig" + mSecurityConfig
159                 + ", mPairingConfig" + mPairingConfig
160                 + ", mIsSuspendable=" + mIsSuspendable
161                 + ", mVendorData=" + mVendorData + "]"
162                 + ", mEnablePeriodicRangingResults=" + mEnablePeriodicRangingResults;
163     }
164 
165     @Override
describeContents()166     public int describeContents() {
167         return 0;
168     }
169 
170     @Override
writeToParcel(Parcel dest, int flags)171     public void writeToParcel(Parcel dest, int flags) {
172         dest.writeByteArray(mServiceName);
173         dest.writeByteArray(mServiceSpecificInfo);
174         dest.writeByteArray(mMatchFilter);
175         dest.writeInt(mPublishType);
176         dest.writeInt(mTtlSec);
177         dest.writeInt(mEnableTerminateNotification ? 1 : 0);
178         dest.writeInt(mEnableRanging ? 1 : 0);
179         dest.writeBoolean(mEnableInstantMode);
180         dest.writeInt(mBand);
181         dest.writeParcelable(mSecurityConfig, flags);
182         dest.writeParcelable(mPairingConfig, flags);
183         dest.writeBoolean(mIsSuspendable);
184         dest.writeList(mVendorData);
185         dest.writeBoolean(mEnablePeriodicRangingResults);
186     }
187 
188     @NonNull
189     public static final Creator<PublishConfig> CREATOR = new Creator<>() {
190         @Override
191         public PublishConfig[] newArray(int size) {
192             return new PublishConfig[size];
193         }
194 
195         @Override
196         public PublishConfig createFromParcel(Parcel in) {
197             byte[] serviceName = in.createByteArray();
198             byte[] ssi = in.createByteArray();
199             byte[] matchFilter = in.createByteArray();
200             int publishType = in.readInt();
201             int ttlSec = in.readInt();
202             boolean enableTerminateNotification = in.readInt() != 0;
203             boolean enableRanging = in.readInt() != 0;
204             boolean enableInstantMode = in.readBoolean();
205             int band = in.readInt();
206             WifiAwareDataPathSecurityConfig securityConfig = in
207                     .readParcelable(WifiAwareDataPathSecurityConfig.class.getClassLoader());
208             AwarePairingConfig pairingConfig = in
209                     .readParcelable(AwarePairingConfig.class.getClassLoader());
210             boolean isSuspendable = in.readBoolean();
211             List<OuiKeyedData> vendorData = ParcelUtil.readOuiKeyedDataList(in);
212             boolean enablePeriodicRangingResults = in.readBoolean();
213 
214             return new PublishConfig(serviceName, ssi, matchFilter, publishType, ttlSec,
215                     enableTerminateNotification, enableRanging, enableInstantMode,
216                     band, securityConfig, pairingConfig, isSuspendable, vendorData,
217                     enablePeriodicRangingResults);
218         }
219     };
220 
221     @Override
equals(Object o)222     public boolean equals(Object o) {
223         if (this == o) {
224             return true;
225         }
226 
227         if (!(o instanceof PublishConfig)) {
228             return false;
229         }
230 
231         PublishConfig lhs = (PublishConfig) o;
232 
233         return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
234                 lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
235                 && mPublishType == lhs.mPublishType
236                 && mTtlSec == lhs.mTtlSec
237                 && mEnableTerminateNotification == lhs.mEnableTerminateNotification
238                 && mEnableRanging == lhs.mEnableRanging
239                 && mEnablePeriodicRangingResults == lhs.mEnablePeriodicRangingResults
240                 && mEnableInstantMode == lhs.mEnableInstantMode
241                 && mBand == lhs.mBand
242                 && mIsSuspendable == lhs.mIsSuspendable
243                 && Objects.equals(mSecurityConfig, lhs.mSecurityConfig)
244                 && Objects.equals(mPairingConfig, lhs.mPairingConfig)
245                 && Objects.equals(mVendorData, lhs.mVendorData);
246     }
247 
248     @Override
hashCode()249     public int hashCode() {
250         return Objects.hash(Arrays.hashCode(mServiceName), Arrays.hashCode(mServiceSpecificInfo),
251                 Arrays.hashCode(mMatchFilter), mPublishType, mTtlSec, mEnableTerminateNotification,
252                 mEnableRanging, mEnableInstantMode, mBand, mSecurityConfig, mPairingConfig,
253                 mIsSuspendable, mVendorData, mEnablePeriodicRangingResults);
254     }
255 
256     /**
257      * Verifies that the contents of the PublishConfig are valid. Otherwise
258      * throws an IllegalArgumentException.
259      *
260      * @hide
261      */
assertValid(Characteristics characteristics, boolean rttSupported)262     public void assertValid(Characteristics characteristics, boolean rttSupported)
263             throws IllegalArgumentException {
264         WifiAwareUtils.validateServiceName(mServiceName);
265 
266         if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) {
267             throw new IllegalArgumentException(
268                     "Invalid txFilter configuration - LV fields do not match up to length");
269         }
270         if (mPublishType < PUBLISH_TYPE_UNSOLICITED || mPublishType > PUBLISH_TYPE_SOLICITED) {
271             throw new IllegalArgumentException("Invalid publishType - " + mPublishType);
272         }
273         if (mTtlSec < 0) {
274             throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
275         }
276         if (mSecurityConfig != null && !mSecurityConfig.isValid()) {
277             throw new IllegalArgumentException("WifiAwareDataPathSecurityConfig is invalid");
278         }
279 
280         if (characteristics != null) {
281             int maxServiceNameLength = characteristics.getMaxServiceNameLength();
282             if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) {
283                 throw new IllegalArgumentException(
284                         "Service name longer than supported by device characteristics");
285             }
286             int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength();
287             if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null
288                     && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) {
289                 throw new IllegalArgumentException(
290                         "Service specific info longer than supported by device characteristics");
291             }
292             int maxMatchFilterLength = characteristics.getMaxMatchFilterLength();
293             if (maxMatchFilterLength != 0 && mMatchFilter != null
294                     && mMatchFilter.length > maxMatchFilterLength) {
295                 throw new IllegalArgumentException(
296                         "Match filter longer than supported by device characteristics");
297             }
298             if (mEnableInstantMode) {
299                 if (SdkLevel.isAtLeastT()
300                         && characteristics.isInstantCommunicationModeSupported()) {
301                     // Valid to use instant communication mode
302                 } else {
303                     throw new IllegalArgumentException("instant mode is not supported");
304                 }
305             }
306             if (mIsSuspendable && !characteristics.isSuspensionSupported()) {
307                 throw new IllegalArgumentException("Aware Suspension is not supported");
308             }
309             if (mSecurityConfig != null && (characteristics.getSupportedCipherSuites()
310                     & mSecurityConfig.getCipherSuite()) == 0) {
311                 throw new IllegalArgumentException("Unsupported cipher suite");
312             }
313             if (mPairingConfig != null && !characteristics.isAwarePairingSupported()) {
314                 throw new IllegalArgumentException("Aware Pairing is not supported");
315             }
316             if (mPairingConfig != null && !mPairingConfig.assertValid(characteristics)) {
317                 throw new IllegalArgumentException("Unsupported pairing config");
318             }
319         }
320 
321         if (!rttSupported && mEnableRanging) {
322             throw new IllegalArgumentException("Ranging is not supported");
323         }
324 
325         if ((!rttSupported || !characteristics.isPeriodicRangingSupported())
326                 && mEnablePeriodicRangingResults) {
327             throw new IllegalArgumentException("Periodic Ranging is not supported");
328         }
329     }
330 
331     /**
332      * Check if instant communication mode is enabled for this publish session.
333      * @see Builder#setInstantCommunicationModeEnabled(boolean, int)
334      * @return true for enabled, false otherwise.
335      */
isInstantCommunicationModeEnabled()336     public boolean isInstantCommunicationModeEnabled() {
337         return mEnableInstantMode;
338     }
339 
340     /**
341      * Get the Wi-Fi band for instant communication mode for this publish session
342      *
343      * @see Builder#setInstantCommunicationModeEnabled(boolean, int)
344      * @return The Wi-Fi band. If instant communication mode is not enabled will return {@link
345      *     ScanResult#WIFI_BAND_24_GHZ} as default.
346      */
347     @WifiAwareManager.InstantModeBand
getInstantCommunicationBand()348     public int getInstantCommunicationBand() {
349         return mBand;
350     }
351 
352     /**
353      * Get the data-path security config for this publish session
354      * @see Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)
355      * @return A {@link WifiAwareDataPathSecurityConfig} specified in this config.
356      */
357     @Nullable
getSecurityConfig()358     public WifiAwareDataPathSecurityConfig getSecurityConfig() {
359         return mSecurityConfig;
360     }
361 
362     /**
363      * Get the Aware Pairing config for this publish session
364      * @see Builder#setPairingConfig(AwarePairingConfig)
365      * @return A {@link AwarePairingConfig} specified in this config.
366      */
367     @Nullable
getPairingConfig()368     public AwarePairingConfig getPairingConfig() {
369         return mPairingConfig;
370     }
371 
372     /**
373      * Check if suspension is supported for this publish session.
374      * @see Builder#setSuspendable(boolean)
375      * @return true for supported, false otherwise.
376      * @hide
377      */
378     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
379     @SystemApi
isSuspendable()380     public boolean isSuspendable() {
381         if (!SdkLevel.isAtLeastU()) {
382             throw new UnsupportedOperationException();
383         }
384         return mIsSuspendable;
385     }
386 
387     /**
388      * Return the vendor-provided configuration data, if it exists. See also {@link
389      * Builder#setVendorData(List)}
390      *
391      * @return Vendor configuration data, or empty list if it does not exist.
392      * @hide
393      */
394     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
395     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
396     @NonNull
397     @SystemApi
getVendorData()398     public List<OuiKeyedData> getVendorData() {
399         if (!SdkLevel.isAtLeastV()) {
400             throw new UnsupportedOperationException();
401         }
402         return mVendorData != null ? mVendorData : Collections.emptyList();
403     }
404 
405     /**
406      * Check if periodic ranging reporting is enabled for publish session
407      * @see Builder#setPeriodicRangingResultsEnabled(boolean)
408      * @return true for enabled, false otherwise.
409      * @hide
410      */
411     @FlaggedApi(FLAG_RANGING_RTT_ENABLED)
412     @SystemApi
isPeriodicRangingResultsEnabled()413     public boolean isPeriodicRangingResultsEnabled() {
414         return mEnablePeriodicRangingResults;
415     }
416 
417     /**
418      * Builder used to build {@link PublishConfig} objects.
419      */
420     public static final class Builder {
421         private byte[] mServiceName;
422         private byte[] mServiceSpecificInfo;
423         private byte[] mMatchFilter;
424         private int mPublishType = PUBLISH_TYPE_UNSOLICITED;
425         private int mTtlSec = 0;
426         private boolean mEnableTerminateNotification = true;
427         private boolean mEnableRanging = false;
428         private boolean mEnableInstantMode = false;
429         private int mBand = WifiScanner.WIFI_BAND_24_GHZ;
430         private WifiAwareDataPathSecurityConfig mSecurityConfig = null;
431         private AwarePairingConfig mPairingConfig = null;
432         private boolean mIsSuspendable = false;
433         private @NonNull List<OuiKeyedData> mVendorData = Collections.emptyList();
434         private boolean mEnablePeriodicRangingResults = false;
435 
436         /**
437          * Specify the service name of the publish session. The actual on-air
438          * value is a 6 byte hashed representation of this string.
439          * <p>
440          * The Service Name is a UTF-8 encoded string from 1 to 255 bytes in length.
441          * The only acceptable single-byte UTF-8 symbols for a Service Name are alphanumeric
442          * values (A-Z, a-z, 0-9), the hyphen ('-'), the period ('.') and the underscore ('_'). All
443          * valid multi-byte UTF-8 characters are acceptable in a Service Name.
444          * <p>
445          * Note: for compatibility with devices running Android 11 or older, avoid using
446          * underscore ('_') symbol as a single-byte UTF-8 service name.
447          * <p>
448          * Must be called - an empty ServiceName is not valid.
449          *
450          * @param serviceName The service name for the publish session.
451          *
452          * @return The builder to facilitate chaining
453          *         {@code builder.setXXX(..).setXXX(..)}.
454          */
setServiceName(@onNull String serviceName)455         public Builder setServiceName(@NonNull String serviceName) {
456             if (serviceName == null) {
457                 throw new IllegalArgumentException("Invalid service name - must be non-null");
458             }
459             mServiceName = serviceName.getBytes(StandardCharsets.UTF_8);
460             return this;
461         }
462 
463         /**
464          * Specify service specific information for the publish session. This is
465          * a free-form byte array available to the application to send
466          * additional information as part of the discovery operation - it
467          * will not be used to determine whether a publish/subscribe match
468          * occurs.
469          * <p>
470          *     Optional. Empty by default.
471          *
472          * @param serviceSpecificInfo A byte-array for the service-specific
473          *            information field.
474          *
475          * @return The builder to facilitate chaining
476          *         {@code builder.setXXX(..).setXXX(..)}.
477          */
setServiceSpecificInfo(@ullable byte[] serviceSpecificInfo)478         public Builder setServiceSpecificInfo(@Nullable byte[] serviceSpecificInfo) {
479             mServiceSpecificInfo = serviceSpecificInfo;
480             return this;
481         }
482 
483         /**
484          * The match filter for a publish session. Used to determine whether a service
485          * discovery occurred - in addition to relying on the service name.
486          * <p>
487          *     Optional. Empty by default.
488          *
489          * @param matchFilter A list of match filter entries (each of which is an arbitrary byte
490          *                    array).
491          *
492          * @return The builder to facilitate chaining
493          *         {@code builder.setXXX(..).setXXX(..)}.
494          */
setMatchFilter(@ullable List<byte[]> matchFilter)495         public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) {
496             mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut(
497                     matchFilter).getArray();
498             return this;
499         }
500 
501         /**
502          * Specify the type of the publish session: solicited (aka active - publish
503          * packets are transmitted over-the-air), or unsolicited (aka passive -
504          * no publish packets are transmitted, a match is made against an active
505          * subscribe session whose packets are transmitted over-the-air).
506          *
507          * @param publishType Publish session type:
508          *            {@link PublishConfig#PUBLISH_TYPE_SOLICITED} or
509          *            {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED} (the default).
510          *
511          * @return The builder to facilitate chaining
512          *         {@code builder.setXXX(..).setXXX(..)}.
513          */
setPublishType(@ublishTypes int publishType)514         public Builder setPublishType(@PublishTypes int publishType) {
515             if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) {
516                 throw new IllegalArgumentException("Invalid publishType - " + publishType);
517             }
518             mPublishType = publishType;
519             return this;
520         }
521 
522         /**
523          * Sets the time interval (in seconds) an unsolicited (
524          * {@link PublishConfig.Builder#setPublishType(int)}) publish session
525          * will be alive - broadcasting a packet. When the TTL is reached
526          * an event will be generated for
527          * {@link DiscoverySessionCallback#onSessionTerminated()} [unless
528          * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
529          * <p>
530          *     Optional. 0 by default - indicating the session doesn't terminate on its own.
531          *     Session will be terminated when {@link DiscoverySession#close()} is
532          *     called.
533          *
534          * @param ttlSec Lifetime of a publish session in seconds.
535          *
536          * @return The builder to facilitate chaining
537          *         {@code builder.setXXX(..).setXXX(..)}.
538          */
setTtlSec(int ttlSec)539         public Builder setTtlSec(int ttlSec) {
540             if (ttlSec < 0) {
541                 throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
542             }
543             mTtlSec = ttlSec;
544             return this;
545         }
546 
547         /**
548          * Configure whether a publish terminate notification
549          * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
550          * back to the callback.
551          *
552          * @param enable If true the terminate callback will be called when the
553          *            publish is terminated. Otherwise it will not be called.
554          *
555          * @return The builder to facilitate chaining
556          *         {@code builder.setXXX(..).setXXX(..)}.
557          */
setTerminateNotificationEnabled(boolean enable)558         public Builder setTerminateNotificationEnabled(boolean enable) {
559             mEnableTerminateNotification = enable;
560             return this;
561         }
562 
563         /**
564          * Configure whether the publish discovery session supports ranging and allows peers to
565          * measure distance to it. This API is used in conjunction with
566          * {@link SubscribeConfig.Builder#setMinDistanceMm(int)} and
567          * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)} to specify a minimum and/or
568          * maximum distance at which discovery will be triggered.
569          * <p>
570          * Optional. Disabled by default - i.e. any peer attempt to measure distance to this device
571          * will be refused and discovery will proceed without ranging constraints.
572          * <p>
573          * The device must support Wi-Fi RTT for this feature to be used. Feature support is checked
574          * as described in {@link android.net.wifi.rtt}.
575          *
576          * @param enable If true, ranging is supported on request of the peer.
577          *
578          * @return The builder to facilitate chaining
579          *         {@code builder.setXXX(..).setXXX(..)}.
580          */
setRangingEnabled(boolean enable)581         public Builder setRangingEnabled(boolean enable) {
582             mEnableRanging = enable;
583             return this;
584         }
585 
586         /**
587          * Configure whether periodic ranging results need to be notified to Publisher
588          * <p>
589          * Optional. Disabled by default - i.e. any ranging result will not be notified to
590          * the Publisher.
591          * <p>
592          * The device must support Periodic Ranging for this feature to be used.
593          * Feature support check is determined by
594          * {@link Characteristics#isPeriodicRangingSupported()}.
595          * <p>
596          * The ranging result will be notified to Publisher via
597          * {@link DiscoverySessionCallback#onRangingResultsReceived(RangingResults)}.
598          *
599          * @param enable If true, ranging result will be notified to Publisher.
600          *
601          * @return The builder to facilitate chaining
602          *         {@code builder.setXXX(..).setXXX(..)}.
603          * @hide
604          */
605         @FlaggedApi(FLAG_RANGING_RTT_ENABLED)
606         @SystemApi
607         @NonNull
setPeriodicRangingResultsEnabled(boolean enable)608         public Builder setPeriodicRangingResultsEnabled(boolean enable) {
609             mEnablePeriodicRangingResults = enable;
610             return this;
611         }
612 
613         /**
614          * Configure whether to enable and use instant communication for this publish session.
615          * Instant communication will speed up service discovery and any data-path set up as part of
616          * this session. Use {@link Characteristics#isInstantCommunicationModeSupported()} to check
617          * if the device supports this feature.
618          *
619          * <p>Note: due to increased power requirements of this mode - it will only remain enabled
620          * for 30 seconds from the time the discovery session is started.
621          *
622          * @param enabled true for enable instant communication mode, default is false.
623          * @param band When setting to {@link ScanResult#WIFI_BAND_5_GHZ}, device will try to enable
624          *     instant communication mode on 5Ghz, but may fall back to 2.4Ghz due to regulatory
625          *     requirements.
626          * @return the current {@link Builder} builder, enabling chaining of builder methods.
627          */
628         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
629         @NonNull
setInstantCommunicationModeEnabled( boolean enabled, @WifiAwareManager.InstantModeBand int band)630         public Builder setInstantCommunicationModeEnabled(
631                 boolean enabled, @WifiAwareManager.InstantModeBand int band) {
632             if (!SdkLevel.isAtLeastT()) {
633                 throw new UnsupportedOperationException();
634             }
635             if (band != ScanResult.WIFI_BAND_24_GHZ && band != ScanResult.WIFI_BAND_5_GHZ) {
636                 throw new IllegalArgumentException();
637             }
638             mBand = band;
639             mEnableInstantMode = enabled;
640             return this;
641         }
642 
643         /**
644          * Configure security config for the Wi-Fi Aware publish session. The security config set
645          * here must be the same as the one used to request Wi-Fi Aware data-path connection using
646          * {@link WifiAwareNetworkSpecifier.Builder#setDataPathSecurityConfig(WifiAwareDataPathSecurityConfig)}.
647          * This security config will create a security identifier (SCID) which contains a PMKID and
648          * transmitted in the publish message. The device which subscribe this session can get this
649          * info by {@link ServiceDiscoveryInfo#getScid()}
650          * This method is optional - if not called, then no security context identifier will be
651          * passed in the publish message, then no security context identifier will be provided in
652          * the {@link ServiceDiscoveryInfo} on the subscriber. Security can still be negotiated
653          * using out-of-band (OOB) mechanisms.
654          *
655          * @param securityConfig The (optional) security config to be used to create security
656          *                       context Identifier
657          * @return the current {@link Builder} builder, enabling chaining of builder methods.
658          */
659         @NonNull
setDataPathSecurityConfig( @onNull WifiAwareDataPathSecurityConfig securityConfig)660         public Builder setDataPathSecurityConfig(
661                 @NonNull WifiAwareDataPathSecurityConfig securityConfig) {
662             if (securityConfig == null) {
663                 throw new IllegalArgumentException("The WifiAwareDataPathSecurityConfig "
664                         + "should be non-null");
665             }
666             if (!securityConfig.isValid()) {
667                 throw new IllegalArgumentException("The WifiAwareDataPathSecurityConfig "
668                         + "is invalid");
669             }
670             mSecurityConfig = securityConfig;
671             return this;
672         }
673 
674         /**
675          * Set the {@link AwarePairingConfig} for this publish session, the peer can use this info
676          * to determine the config of the following bootstrapping, pairing setup/verification
677          * request.
678          * @see AwarePairingConfig
679          * @param config The pairing config set to the peer. Only valid when
680          * {@link Characteristics#isAwarePairingSupported()} is true.
681          * @return the current {@link Builder} builder, enabling chaining of builder methods.
682          */
683         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
setPairingConfig(@ullable AwarePairingConfig config)684         @NonNull public Builder setPairingConfig(@Nullable AwarePairingConfig config) {
685             if (!SdkLevel.isAtLeastU()) {
686                 throw new UnsupportedOperationException();
687             }
688             mPairingConfig = config;
689             return this;
690         }
691 
692         /**
693          * Specify whether to configure the publish discovery session to be suspendable. This API
694          * doesn't suspend the session, it allows it to be suspended and resumed in the future using
695          * {@link DiscoverySession#suspend()} and {@link DiscoverySession#resume()} respectively.
696          * <p>
697          * Optional. Not suspendable by default.
698          * <p>
699          * The device must support Wi-Fi Aware suspension for a publish session to be
700          * suspendable. Feature support check is determined by
701          * {@link Characteristics#isSuspensionSupported()}.
702          *
703          * @param isSuspendable If true, then this publish session can be suspended.
704          *
705          * @return the current {@link Builder} builder, enabling chaining of builder methods.
706          *
707          * @see DiscoverySession#suspend()
708          * @see DiscoverySession#resume()
709          * @hide
710          */
711         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
712         @RequiresPermission(value = MANAGE_WIFI_NETWORK_SELECTION)
713         @SystemApi
714         @NonNull
setSuspendable(boolean isSuspendable)715         public Builder setSuspendable(boolean isSuspendable) {
716             if (!SdkLevel.isAtLeastU()) {
717                 throw new UnsupportedOperationException();
718             }
719             mIsSuspendable = isSuspendable;
720             return this;
721         }
722 
723         /**
724          * Set additional vendor-provided configuration data.
725          *
726          * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided
727          *     configuration data. Note that multiple elements with the same OUI are allowed.
728          * @return Builder for chaining.
729          * @hide
730          */
731         @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
732         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
733         @NonNull
734         @SystemApi
setVendorData(@onNull List<OuiKeyedData> vendorData)735         public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) {
736             if (!SdkLevel.isAtLeastV()) {
737                 throw new UnsupportedOperationException();
738             }
739             if (vendorData == null) {
740                 throw new IllegalArgumentException("setVendorData received a null value");
741             }
742             mVendorData = vendorData;
743             return this;
744         }
745 
746         /**
747          * Build {@link PublishConfig} given the current requests made on the
748          * builder.
749          */
build()750         public PublishConfig build() {
751             return new PublishConfig(mServiceName, mServiceSpecificInfo, mMatchFilter, mPublishType,
752                     mTtlSec, mEnableTerminateNotification, mEnableRanging, mEnableInstantMode,
753                     mBand, mSecurityConfig, mPairingConfig, mIsSuspendable, mVendorData,
754                     mEnablePeriodicRangingResults);
755         }
756     }
757 }
758