• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.app.compat.CompatChanges;
26 import android.compat.annotation.ChangeId;
27 import android.compat.annotation.EnabledAfter;
28 import android.net.MacAddress;
29 import android.net.wifi.util.Environment;
30 import android.net.wifi.util.HexEncoding;
31 import android.os.Build;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.text.TextUtils;
35 import android.util.Log;
36 import android.util.SparseIntArray;
37 
38 import androidx.annotation.Keep;
39 import androidx.annotation.RequiresApi;
40 import androidx.annotation.VisibleForTesting;
41 
42 import com.android.internal.util.Preconditions;
43 import com.android.modules.utils.build.SdkLevel;
44 import com.android.wifi.flags.Flags;
45 
46 import java.lang.annotation.Retention;
47 import java.lang.annotation.RetentionPolicy;
48 import java.nio.charset.StandardCharsets;
49 import java.util.ArrayList;
50 import java.util.HashSet;
51 import java.util.List;
52 import java.util.Objects;
53 import java.util.Set;
54 import java.util.stream.Collectors;
55 import java.util.stream.IntStream;
56 
57 /**
58  * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
59  *
60  * <p>This is input for the framework provided by a client app, i.e. it exposes knobs to instruct
61  * the framework how it should configure a hotspot.
62  *
63  * <p>System apps can use this to configure a tethered hotspot or local-only hotspot.
64  *
65  * <p>Instances of this class are immutable.
66  */
67 public final class SoftApConfiguration implements Parcelable {
68 
69     private static final String TAG = "SoftApConfiguration";
70 
71     @VisibleForTesting
72     static final int PSK_MIN_LEN = 8;
73 
74     @VisibleForTesting
75     static final int PSK_MAX_LEN = 63;
76 
77     /**
78      * 2GHz band.
79      */
80     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
81     public static final int BAND_2GHZ = 1 << 0;
82 
83     /**
84      * 5GHz band.
85      */
86     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
87     public static final int BAND_5GHZ = 1 << 1;
88 
89     /**
90      * 6GHz band.
91      */
92     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
93     public static final int BAND_6GHZ = 1 << 2;
94 
95     /**
96      * 60GHz band.
97      */
98     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
99     public static final int BAND_60GHZ = 1 << 3;
100 
101     /**
102      * Device is allowed to choose the optimal band (2GHz, 5GHz, 6GHz) based on device capability,
103      * operating country code and current radio conditions.
104      * @hide
105      *
106      * @deprecated This is no longer supported. The value is fixed at
107      * (BAND_2GHZ | BAND_5GHZ | BAND_6GHZ) even if a new band is supported in the future, for
108      * instance {@code BAND_60GHZ}. The bands are a bit mask - use any combination of
109      * {@code BAND_}, for instance {@code BAND_2GHZ | BAND_5GHZ}.
110      */
111     @SystemApi
112     public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
113 
114     /**
115      * A default value used to configure shut down timeout setting to default value.
116      * See {@link Builder#setShutdownTimeoutMillis(long)} or
117      * {@link Builder#setBridgedModeOpportunisticShutdownTimeoutMillis(long)} for details.
118      *
119      * @hide
120      */
121     @SystemApi
122     public static final long DEFAULT_TIMEOUT = -1;
123 
124     /** @hide */
125     @Retention(RetentionPolicy.SOURCE)
126     @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = {
127             BAND_2GHZ,
128             BAND_5GHZ,
129             BAND_6GHZ,
130             BAND_60GHZ,
131     })
132     public @interface BandType {}
133 
134     /**
135      * All of the supported band types.
136      * @hide
137      */
138     public static int[] BAND_TYPES = {BAND_2GHZ, BAND_5GHZ, BAND_6GHZ, BAND_60GHZ};
139 
isBandValid(@andType int band)140     private static boolean isBandValid(@BandType int band) {
141         int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ;
142         return ((band != 0) && ((band & ~bandAny) == 0));
143     }
144 
145     private static final int MIN_CH_2G_BAND = 1;
146     private static final int MAX_CH_2G_BAND = 14;
147     private static final int MIN_CH_5G_BAND = 34;
148     private static final int MAX_CH_5G_BAND = 196;
149     private static final int MIN_CH_6G_BAND = 1;
150     private static final int MAX_CH_6G_BAND = 253;
151     private static final int MIN_CH_60G_BAND = 1;
152     private static final int MAX_CH_60G_BAND = 6;
153 
154     /**
155      * Requires to configure MAC randomization setting to None when configuring BSSID.
156      */
157     @ChangeId
158     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
159     private static final long FORCE_MUTUAL_EXCLUSIVE_BSSID_MAC_RAMDONIZATION_SETTING = 215656264L;
160 
161     /**
162      * Removes zero support on
163      * {@link android.net.wifi.SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}.
164      *
165      * @hide
166      */
167     @ChangeId
168     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
169     public static final long REMOVE_ZERO_FOR_TIMEOUT_SETTING = 213289672L;
170 
isChannelBandPairValid(int channel, @BandType int band)171     private static boolean isChannelBandPairValid(int channel, @BandType int band) {
172         switch (band) {
173             case BAND_2GHZ:
174                 if (channel < MIN_CH_2G_BAND || channel >  MAX_CH_2G_BAND) {
175                     return false;
176                 }
177                 break;
178 
179             case BAND_5GHZ:
180                 if (channel < MIN_CH_5G_BAND || channel >  MAX_CH_5G_BAND) {
181                     return false;
182                 }
183                 break;
184 
185             case BAND_6GHZ:
186                 if (channel < MIN_CH_6G_BAND || channel >  MAX_CH_6G_BAND) {
187                     return false;
188                 }
189                 break;
190 
191             case BAND_60GHZ:
192                 if (channel < MIN_CH_60G_BAND || channel >  MAX_CH_60G_BAND) {
193                     return false;
194                 }
195                 break;
196 
197             default:
198                 return false;
199         }
200         return true;
201     }
202 
203     /**
204      * SSID for the AP, or null for a framework-determined SSID.
205      */
206     private final @Nullable WifiSsid mWifiSsid;
207 
208     /**
209      * BSSID for the AP, or null to use a framework-determined BSSID.
210      */
211     private final @Nullable MacAddress mBssid;
212 
213     /**
214      * Vendor elements for the AP, structured as dd+len+elements
215      */
216     private final @NonNull List<ScanResult.InformationElement> mVendorElements;
217 
218     /**
219      * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
220      * the security type.
221      */
222     private final @Nullable String mPassphrase;
223 
224     /**
225      * This is a network that does not broadcast its SSID, so an
226      * SSID-specific probe request must be used for scans.
227      */
228     private final boolean mHiddenSsid;
229 
230     /**
231      * The operating channels of the dual APs.
232      *
233      * The SparseIntArray that consists the band and the channel of matching the band.
234      */
235     @NonNull
236     private final SparseIntArray mChannels;
237 
238     /**
239      * The set of allowed channels in 2.4GHz band to select from using ACS (Automatic Channel
240      * Selection) algorithm.
241      *
242      * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}.
243      * Otherwise, this set will be ignored.
244      *
245      * If the set is empty, then all channels in 2.4GHz band are allowed.
246      */
247     private final @NonNull Set<Integer> mAllowedAcsChannels2g;
248 
249     /**
250      * The set of allowed channels in 5GHz band to select from using ACS (Automatic Channel
251      * Selection) algorithm.
252      *
253      * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}.
254      * Otherwise, this set will be ignored.
255      *
256      * If the set is empty, then all channels in 5GHz are allowed.
257      */
258     private final @NonNull Set<Integer> mAllowedAcsChannels5g;
259 
260     /**
261      * The set of allowed channels in 6GHz band to select from using ACS (Automatic Channel
262      * Selection) algorithm.
263      *
264      * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}.
265      * Otherwise, this set will be ignored.
266      *
267      * If the set is empty, then all channels in 6GHz are allowed.
268      */
269     private final @NonNull Set<Integer> mAllowedAcsChannels6g;
270 
271     /**
272      * The maximum channel bandwidth for SoftAp operation
273      *
274      * Default value is SoftApInfo#CHANNEL_WIDTH_AUTO which means the channel bandwidth
275      * is to be selected by the chip based on device capabilities.
276      * <p>
277      *
278      * Valid values: {@link SoftApInfo#CHANNEL_WIDTH_AUTO},
279      * {@link SoftApInfo#CHANNEL_WIDTH_20MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_40MHZ},
280      * {@link SoftApInfo#CHANNEL_WIDTH_80MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_160MHZ},
281      * {@link SoftApInfo#CHANNEL_WIDTH_320MHZ}
282      *
283      */
284     private final @WifiAnnotations.Bandwidth int mMaxChannelBandwidth;
285 
286     /**
287      * The maximim allowed number of clients that can associate to the AP.
288      */
289     private final int mMaxNumberOfClients;
290 
291     /**
292      * The operating security type of the AP.
293      * One of the following security types:
294      * {@link #SECURITY_TYPE_OPEN},
295      * {@link #SECURITY_TYPE_WPA2_PSK},
296      * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
297      * {@link #SECURITY_TYPE_WPA3_SAE},
298      * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
299      * {@link #SECURITY_TYPE_WPA3_OWE}
300      */
301     private final @SecurityType int mSecurityType;
302 
303     /**
304      * The flag to indicate client need to authorize by user
305      * when client is connecting to AP.
306      */
307     private final boolean mClientControlByUser;
308 
309     /**
310      * The list of blocked client that can't associate to the AP.
311      */
312     private final List<MacAddress> mBlockedClientList;
313 
314     /**
315      * The list of allowed client that can associate to the AP.
316      */
317     private final List<MacAddress> mAllowedClientList;
318 
319     /**
320      * Whether auto shutdown of soft AP is enabled or not.
321      */
322     private final boolean mAutoShutdownEnabled;
323 
324     /**
325      * Delay in milliseconds before shutting down soft AP when
326      * there are no connected devices.
327      */
328     private final long mShutdownTimeoutMillis;
329 
330     /** @hide */
331     @Retention(RetentionPolicy.SOURCE)
332     @IntDef(prefix = {"RANDOMIZATION_"}, value = {
333             RANDOMIZATION_NONE,
334             RANDOMIZATION_PERSISTENT,
335             RANDOMIZATION_NON_PERSISTENT})
336     public @interface MacRandomizationSetting {}
337 
338     /**
339      * Use the factory MAC address as the BSSID of the AP.
340      *
341      * @hide
342      */
343     @SystemApi
344     public static final int RANDOMIZATION_NONE = 0;
345 
346     /**
347      * Generate a persistent randomized MAC address as the BSSID of the AP.
348      * The MAC address is persisted per SSID - i.e. as long as the SSID of the AP doesn't change
349      * then it will have a persistent MAC address (which is initially random and is not the factory
350      * MAC address).
351      *
352      * @hide
353      */
354     @SystemApi
355     public static final int RANDOMIZATION_PERSISTENT = 1;
356 
357     /**
358      * Generate a randomized MAC address as the BSSID of the AP. The MAC address is not persisted
359      * - it is re-generated every time the AP is re-enabled.
360      * @hide
361      */
362     @SystemApi
363     public static final int RANDOMIZATION_NON_PERSISTENT = 2;
364 
365     /**
366      * Level of MAC randomization for the AP BSSID.
367      */
368     @MacRandomizationSetting
369     private int mMacRandomizationSetting;
370 
371 
372     /**
373      * Whether opportunistic shutdown of an instance in bridged AP is enabled or not.
374      */
375     private boolean mBridgedModeOpportunisticShutdownEnabled;
376 
377     /**
378      * Whether 802.11ax AP is enabled or not.
379      */
380     private boolean mIeee80211axEnabled;
381 
382     /**
383      * Whether 802.11be AP is enabled or not.
384      */
385     private boolean mIeee80211beEnabled;
386 
387     /**
388      * Whether the current configuration is configured by user or not.
389      */
390     private boolean mIsUserConfiguration;
391 
392     /**
393      * Randomized MAC address to use with this configuration when MAC randomization setting
394      * is {@link #RANDOMIZATION_PERSISTENT}.
395      */
396     private final @Nullable MacAddress mPersistentRandomizedMacAddress;
397 
398     /**
399      * Delay in milliseconds before shutting down an instance in bridged AP.
400      */
401     private final long mBridgedModeOpportunisticShutdownTimeoutMillis;
402 
403     /** List of {@link OuiKeyedData} providing vendor-specific configuration data. */
404     private @NonNull List<OuiKeyedData> mVendorData;
405 
406     /**
407      * Whether connected clients can communicate with each other or not.
408      */
409     private boolean mIsClientIsolationEnabled;
410 
411     /**
412      * THe definition of security type OPEN.
413      */
414     public static final int SECURITY_TYPE_OPEN = 0;
415 
416     /**
417      * The definition of security type WPA2-PSK.
418      */
419     public static final int SECURITY_TYPE_WPA2_PSK = 1;
420 
421     /**
422      * The definition of security type WPA3-SAE Transition mode.
423      */
424     public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
425 
426     /**
427      * The definition of security type WPA3-SAE.
428      */
429     public static final int SECURITY_TYPE_WPA3_SAE = 3;
430 
431     /**
432      * The definition of security type WPA3-OWE Transition.
433      */
434     public static final int SECURITY_TYPE_WPA3_OWE_TRANSITION = 4;
435 
436     /**
437      * The definition of security type WPA3-OWE.
438      */
439     public static final int SECURITY_TYPE_WPA3_OWE = 5;
440 
441     /** @hide */
442     @Retention(RetentionPolicy.SOURCE)
443     @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
444         SECURITY_TYPE_OPEN,
445         SECURITY_TYPE_WPA2_PSK,
446         SECURITY_TYPE_WPA3_SAE_TRANSITION,
447         SECURITY_TYPE_WPA3_SAE,
448         SECURITY_TYPE_WPA3_OWE_TRANSITION,
449         SECURITY_TYPE_WPA3_OWE,
450     })
451     public @interface SecurityType {}
452 
453     /** Private constructor for Builder and Parcelable implementation. */
SoftApConfiguration( @ullable WifiSsid ssid, @Nullable MacAddress bssid, @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels, @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled, long shutdownTimeoutMillis, boolean clientControlByUser, @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList, int macRandomizationSetting, boolean bridgedModeOpportunisticShutdownEnabled, boolean ieee80211axEnabled, boolean ieee80211beEnabled, boolean isUserConfiguration, long bridgedModeOpportunisticShutdownTimeoutMillis, @NonNull List<ScanResult.InformationElement> vendorElements, @Nullable MacAddress persistentRandomizedMacAddress, @NonNull Set<Integer> allowedAcsChannels24g, @NonNull Set<Integer> allowedAcsChannels5g, @NonNull Set<Integer> allowedAcsChannels6g, @WifiAnnotations.Bandwidth int maxChannelBandwidth, @Nullable List<OuiKeyedData> vendorData, boolean isClientIsolationEnabled)454     private SoftApConfiguration(
455             @Nullable WifiSsid ssid,
456             @Nullable MacAddress bssid,
457             @Nullable String passphrase,
458             boolean hiddenSsid,
459             @NonNull SparseIntArray channels,
460             @SecurityType int securityType,
461             int maxNumberOfClients,
462             boolean shutdownTimeoutEnabled,
463             long shutdownTimeoutMillis,
464             boolean clientControlByUser,
465             @NonNull List<MacAddress> blockedList,
466             @NonNull List<MacAddress> allowedList,
467             int macRandomizationSetting,
468             boolean bridgedModeOpportunisticShutdownEnabled,
469             boolean ieee80211axEnabled,
470             boolean ieee80211beEnabled,
471             boolean isUserConfiguration,
472             long bridgedModeOpportunisticShutdownTimeoutMillis,
473             @NonNull List<ScanResult.InformationElement> vendorElements,
474             @Nullable MacAddress persistentRandomizedMacAddress,
475             @NonNull Set<Integer> allowedAcsChannels24g,
476             @NonNull Set<Integer> allowedAcsChannels5g,
477             @NonNull Set<Integer> allowedAcsChannels6g,
478             @WifiAnnotations.Bandwidth int maxChannelBandwidth,
479             @Nullable List<OuiKeyedData> vendorData,
480             boolean isClientIsolationEnabled) {
481         mWifiSsid = ssid;
482         mBssid = bssid;
483         mPassphrase = passphrase;
484         mHiddenSsid = hiddenSsid;
485         if (channels.size() != 0) {
486             mChannels = channels.clone();
487         } else {
488             mChannels = new SparseIntArray(1);
489             mChannels.put(BAND_2GHZ, 0);
490         }
491         mSecurityType = securityType;
492         mMaxNumberOfClients = maxNumberOfClients;
493         mAutoShutdownEnabled = shutdownTimeoutEnabled;
494         mShutdownTimeoutMillis = shutdownTimeoutMillis;
495         mClientControlByUser = clientControlByUser;
496         mBlockedClientList = new ArrayList<>(blockedList);
497         mAllowedClientList = new ArrayList<>(allowedList);
498         mMacRandomizationSetting = macRandomizationSetting;
499         mBridgedModeOpportunisticShutdownEnabled = bridgedModeOpportunisticShutdownEnabled;
500         mIeee80211axEnabled = ieee80211axEnabled;
501         mIeee80211beEnabled = ieee80211beEnabled;
502         mIsUserConfiguration = isUserConfiguration;
503         mBridgedModeOpportunisticShutdownTimeoutMillis =
504                 bridgedModeOpportunisticShutdownTimeoutMillis;
505         mVendorElements = new ArrayList<>(vendorElements);
506         mPersistentRandomizedMacAddress = persistentRandomizedMacAddress;
507         mAllowedAcsChannels2g = new HashSet<>(allowedAcsChannels24g);
508         mAllowedAcsChannels5g = new HashSet<>(allowedAcsChannels5g);
509         mAllowedAcsChannels6g = new HashSet<>(allowedAcsChannels6g);
510         mMaxChannelBandwidth = maxChannelBandwidth;
511         mVendorData = new ArrayList<>(vendorData);
512         mIsClientIsolationEnabled = isClientIsolationEnabled;
513     }
514 
515     @Override
equals(Object otherObj)516     public boolean equals(Object otherObj) {
517         if (this == otherObj) {
518             return true;
519         }
520         if (!(otherObj instanceof SoftApConfiguration)) {
521             return false;
522         }
523         SoftApConfiguration other = (SoftApConfiguration) otherObj;
524         return Objects.equals(mWifiSsid, other.mWifiSsid)
525                 && Objects.equals(mBssid, other.mBssid)
526                 && Objects.equals(mPassphrase, other.mPassphrase)
527                 && mHiddenSsid == other.mHiddenSsid
528                 && mChannels.toString().equals(other.mChannels.toString())
529                 && mSecurityType == other.mSecurityType
530                 && mMaxNumberOfClients == other.mMaxNumberOfClients
531                 && mAutoShutdownEnabled == other.mAutoShutdownEnabled
532                 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
533                 && mClientControlByUser == other.mClientControlByUser
534                 && Objects.equals(mBlockedClientList, other.mBlockedClientList)
535                 && Objects.equals(mAllowedClientList, other.mAllowedClientList)
536                 && mMacRandomizationSetting == other.mMacRandomizationSetting
537                 && mBridgedModeOpportunisticShutdownEnabled
538                         == other.mBridgedModeOpportunisticShutdownEnabled
539                 && mIeee80211axEnabled == other.mIeee80211axEnabled
540                 && mIeee80211beEnabled == other.mIeee80211beEnabled
541                 && mIsUserConfiguration == other.mIsUserConfiguration
542                 && mBridgedModeOpportunisticShutdownTimeoutMillis
543                         == other.mBridgedModeOpportunisticShutdownTimeoutMillis
544                 && Objects.equals(mVendorElements, other.mVendorElements)
545                 && Objects.equals(
546                         mPersistentRandomizedMacAddress, other.mPersistentRandomizedMacAddress)
547                 && Objects.equals(mAllowedAcsChannels2g, other.mAllowedAcsChannels2g)
548                 && Objects.equals(mAllowedAcsChannels5g, other.mAllowedAcsChannels5g)
549                 && Objects.equals(mAllowedAcsChannels6g, other.mAllowedAcsChannels6g)
550                 && mMaxChannelBandwidth == other.mMaxChannelBandwidth
551                 && Objects.equals(mVendorData, other.mVendorData)
552                 && mIsClientIsolationEnabled == other.mIsClientIsolationEnabled;
553     }
554 
555     @Override
hashCode()556     public int hashCode() {
557         return Objects.hash(
558                 mWifiSsid,
559                 mBssid,
560                 mPassphrase,
561                 mHiddenSsid,
562                 mChannels.toString(),
563                 mSecurityType,
564                 mMaxNumberOfClients,
565                 mAutoShutdownEnabled,
566                 mShutdownTimeoutMillis,
567                 mClientControlByUser,
568                 mBlockedClientList,
569                 mAllowedClientList,
570                 mMacRandomizationSetting,
571                 mBridgedModeOpportunisticShutdownEnabled,
572                 mIeee80211axEnabled,
573                 mIeee80211beEnabled,
574                 mIsUserConfiguration,
575                 mBridgedModeOpportunisticShutdownTimeoutMillis,
576                 mVendorElements,
577                 mPersistentRandomizedMacAddress,
578                 mAllowedAcsChannels2g,
579                 mAllowedAcsChannels5g,
580                 mAllowedAcsChannels6g,
581                 mMaxChannelBandwidth,
582                 mVendorData,
583                 mIsClientIsolationEnabled);
584     }
585 
586     @Override
toString()587     public String toString() {
588         StringBuilder sbuf = new StringBuilder();
589         sbuf.append("ssid = ").append(mWifiSsid == null ? null : mWifiSsid.toString());
590         if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString());
591         sbuf.append(" \n Passphrase = ").append(
592                 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
593         sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid);
594         sbuf.append(" \n Channels = ").append(mChannels);
595         sbuf.append(" \n SecurityType = ").append(getSecurityType());
596         sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients);
597         sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled);
598         sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis);
599         sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser);
600         sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList);
601         sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList);
602         sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting);
603         sbuf.append(" \n BridgedModeInstanceOpportunisticEnabled = ")
604                 .append(mBridgedModeOpportunisticShutdownEnabled);
605         sbuf.append(" \n BridgedModeOpportunisticShutdownTimeoutMillis = ")
606                 .append(mBridgedModeOpportunisticShutdownTimeoutMillis);
607         sbuf.append(" \n Ieee80211axEnabled = ").append(mIeee80211axEnabled);
608         sbuf.append(" \n Ieee80211beEnabled = ").append(mIeee80211beEnabled);
609         sbuf.append(" \n isUserConfiguration = ").append(mIsUserConfiguration);
610         sbuf.append(" \n vendorElements = ").append(mVendorElements);
611         sbuf.append(" \n mPersistentRandomizedMacAddress = ")
612                 .append(mPersistentRandomizedMacAddress);
613         sbuf.append(" \n mAllowedAcsChannels2g = ").append(mAllowedAcsChannels2g);
614         sbuf.append(" \n mAllowedAcsChannels5g = ").append(mAllowedAcsChannels5g);
615         sbuf.append(" \n mAllowedAcsChannels6g = ").append(mAllowedAcsChannels6g);
616         sbuf.append(" \n mMaxChannelBandwidth = ").append(mMaxChannelBandwidth);
617         sbuf.append(" \n mVendorData = ").append(mVendorData);
618         sbuf.append(" \n mIsClientIsolationEnabled = ").append(mIsClientIsolationEnabled);
619         return sbuf.toString();
620     }
621 
622     @Override
writeToParcel(@onNull Parcel dest, int flags)623     public void writeToParcel(@NonNull Parcel dest, int flags) {
624         dest.writeParcelable(mWifiSsid, 0);
625         dest.writeParcelable(mBssid, flags);
626         dest.writeString(mPassphrase);
627         dest.writeBoolean(mHiddenSsid);
628         writeSparseIntArray(dest, mChannels);
629         dest.writeInt(mSecurityType);
630         dest.writeInt(mMaxNumberOfClients);
631         dest.writeBoolean(mAutoShutdownEnabled);
632         dest.writeLong(mShutdownTimeoutMillis);
633         dest.writeBoolean(mClientControlByUser);
634         dest.writeTypedList(mBlockedClientList);
635         dest.writeTypedList(mAllowedClientList);
636         dest.writeInt(mMacRandomizationSetting);
637         dest.writeBoolean(mBridgedModeOpportunisticShutdownEnabled);
638         dest.writeBoolean(mIeee80211axEnabled);
639         dest.writeBoolean(mIeee80211beEnabled);
640         dest.writeBoolean(mIsUserConfiguration);
641         dest.writeLong(mBridgedModeOpportunisticShutdownTimeoutMillis);
642         dest.writeTypedList(mVendorElements);
643         dest.writeParcelable(mPersistentRandomizedMacAddress, flags);
644         writeHashSetInt(dest, mAllowedAcsChannels2g);
645         writeHashSetInt(dest, mAllowedAcsChannels5g);
646         writeHashSetInt(dest, mAllowedAcsChannels6g);
647         dest.writeInt(mMaxChannelBandwidth);
648         dest.writeList(mVendorData);
649         dest.writeBoolean(mIsClientIsolationEnabled);
650     }
651 
652     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
writeSparseIntArray(@onNull Parcel dest, @Nullable SparseIntArray val)653     private static void writeSparseIntArray(@NonNull Parcel dest,
654             @Nullable SparseIntArray val) {
655         if (val == null) {
656             dest.writeInt(-1);
657             return;
658         }
659         int n = val.size();
660         dest.writeInt(n);
661         int i = 0;
662         while (i < n) {
663             dest.writeInt(val.keyAt(i));
664             dest.writeInt(val.valueAt(i));
665             i++;
666         }
667     }
668 
669     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
670     @NonNull
readSparseIntArray(@onNull Parcel in)671     private static SparseIntArray readSparseIntArray(@NonNull Parcel in) {
672         int n = in.readInt();
673         if (n < 0) {
674             return new SparseIntArray();
675         }
676         SparseIntArray sa = new SparseIntArray(n);
677         while (n > 0) {
678             int key = in.readInt();
679             int value = in.readInt();
680             sa.append(key, value);
681             n--;
682         }
683         return sa;
684     }
685 
686     /* Write HashSet<Integer> into Parcel */
writeHashSetInt(@onNull Parcel dest, @NonNull Set<Integer> set)687     private static void writeHashSetInt(@NonNull Parcel dest, @NonNull Set<Integer> set) {
688         if (set.isEmpty()) {
689             dest.writeInt(-1);
690             return;
691         }
692 
693         dest.writeInt(set.size());
694         for (int val : set) {
695             dest.writeInt(val);
696         }
697     }
698 
699     /* Read HashSet<Integer> from Parcel */
700     @NonNull
readHashSetInt(@onNull Parcel in)701     private static Set<Integer> readHashSetInt(@NonNull Parcel in) {
702         Set<Integer> set = new HashSet<>();
703         int len = in.readInt();
704         if (len < 0) {
705             return set;
706         }
707 
708         for (int i = 0; i < len; i++) {
709             set.add(in.readInt());
710         }
711         return set;
712     }
713 
714     /* Read List<OuiKeyedData> from Parcel */
715     @NonNull
readOuiKeyedDataList(@onNull Parcel in)716     private static List<OuiKeyedData> readOuiKeyedDataList(@NonNull Parcel in) {
717         List<OuiKeyedData> dataList = new ArrayList<>();
718         if (SdkLevel.isAtLeastT()) {
719             in.readList(dataList, OuiKeyedData.class.getClassLoader(), OuiKeyedData.class);
720         } else {
721             in.readList(dataList, OuiKeyedData.class.getClassLoader());
722         }
723         return dataList;
724     }
725 
726     @Override
describeContents()727     public int describeContents() {
728         return 0;
729     }
730 
731     @NonNull
732     public static final Creator<SoftApConfiguration> CREATOR =
733             new Creator<SoftApConfiguration>() {
734                 @Override
735                 public SoftApConfiguration createFromParcel(Parcel in) {
736                     return new SoftApConfiguration(
737                             in.readParcelable(WifiSsid.class.getClassLoader()),
738                             in.readParcelable(MacAddress.class.getClassLoader()),
739                             in.readString(),
740                             in.readBoolean(),
741                             readSparseIntArray(in),
742                             in.readInt(),
743                             in.readInt(),
744                             in.readBoolean(),
745                             in.readLong(),
746                             in.readBoolean(),
747                             in.createTypedArrayList(MacAddress.CREATOR),
748                             in.createTypedArrayList(MacAddress.CREATOR),
749                             in.readInt(),
750                             in.readBoolean(),
751                             in.readBoolean(),
752                             in.readBoolean(),
753                             in.readBoolean(),
754                             in.readLong(),
755                             in.createTypedArrayList(ScanResult.InformationElement.CREATOR),
756                             in.readParcelable(MacAddress.class.getClassLoader()),
757                             readHashSetInt(in),
758                             readHashSetInt(in),
759                             readHashSetInt(in),
760                             in.readInt(),
761                             readOuiKeyedDataList(in),
762                             in.readBoolean());
763                 }
764 
765                 @Override
766                 public SoftApConfiguration[] newArray(int size) {
767                     return new SoftApConfiguration[size];
768                 }
769             };
770 
771     /**
772      * Return the UTF-8 String set to be the SSID for the AP. If the SSID cannot be decoded as
773      * UTF-8, then this will return {@link WifiManager#UNKNOWN_SSID}.
774      *
775      * @deprecated Use {@link #getWifiSsid()} instead.
776      */
777     @Nullable
778     @Deprecated
getSsid()779     public String getSsid() {
780         if (mWifiSsid == null) {
781             return null;
782         }
783         CharSequence utf8Text = mWifiSsid.getUtf8Text();
784         return utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID;
785     }
786 
787     /**
788      * Return WifiSsid set to be the SSID for the AP.
789      */
790     @Nullable
getWifiSsid()791     public WifiSsid getWifiSsid() {
792         return mWifiSsid;
793     }
794 
795     /**
796      * Return VendorElements for the AP.
797      * @hide
798      */
799     @NonNull
800     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
801     @SystemApi
getVendorElements()802     public List<ScanResult.InformationElement> getVendorElements() {
803         if (!SdkLevel.isAtLeastT()) {
804             throw new UnsupportedOperationException();
805         }
806         return getVendorElementsInternal();
807     }
808 
809     /**
810      * @see #getVendorElements()
811      * @hide
812      */
getVendorElementsInternal()813     public List<ScanResult.InformationElement> getVendorElementsInternal() {
814         return new ArrayList<>(mVendorElements);
815     }
816 
817     /**
818      * Returns MAC address set to be BSSID for the AP.
819      */
820     @Nullable
getBssid()821     public MacAddress getBssid() {
822         return mBssid;
823     }
824 
825     /**
826      * Returns String set to be passphrase for current AP.
827      */
828     @Nullable
getPassphrase()829     public String getPassphrase() {
830         return mPassphrase;
831     }
832 
833     /**
834      * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
835      * not (false: broadcasts its SSID) for the AP.
836      */
isHiddenSsid()837     public boolean isHiddenSsid() {
838         return mHiddenSsid;
839     }
840 
841     /**
842      * Returns band type set to be the band for the AP.
843      *
844      * One or combination of {@code BAND_}, for instance
845      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
846      *
847      * Note: Returns the lowest band when more than one band is set.
848      * Use {@link #getChannels()} to get dual bands setting.
849      *
850      * See also {@link Builder#setBand(int)}.
851      *
852      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
853      * @hide
854      */
855     @Deprecated
856     @SystemApi
getBand()857     public @BandType int getBand() {
858         return mChannels.keyAt(0);
859     }
860 
861     /**
862      * Returns a sorted array in ascending order that consists of the configured band types
863      * for the APs.
864      *
865      * The band type is one or combination of {@code BAND_}, for instance
866      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
867      *
868      * Note: return array may only include one band when current setting is single AP mode.
869      * See also {@link Builder#setBands(int[])}.
870      *
871      * @hide
872      */
873     @Keep
getBands()874     public @NonNull int[] getBands() {
875         int[] bands = new int[mChannels.size()];
876         for (int i = 0; i < bands.length; i++) {
877             bands[i] = mChannels.keyAt(i);
878         }
879         return bands;
880     }
881 
882     /**
883      * Returns Integer set to be the channel for the AP.
884      *
885      * Note: Returns the channel which associated to the lowest band if more than one channel
886      * is set. Use {@link Builder#getChannels()} to get dual channel setting.
887      * See also {@link Builder#setChannel(int, int)}.
888      *
889      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
890      * @hide
891      */
892     @Deprecated
893     @SystemApi
getChannel()894     public int getChannel() {
895         return mChannels.valueAt(0);
896     }
897 
898 
899     /**
900      * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of
901      * the configured bands and channels for the AP(s).
902      *
903      * The returned channel value is Wi-Fi channel numbering.
904      * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
905      * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
906      *
907      * Note: return array may only include one channel when current setting is single AP mode.
908      * See also {@link Builder#setChannels(SparseIntArray)}.
909      */
910     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
911     @RequiresApi(Build.VERSION_CODES.S)
getChannels()912     public @NonNull SparseIntArray getChannels() {
913         if (!SdkLevel.isAtLeastS()) {
914             throw new UnsupportedOperationException();
915         }
916         return mChannels.clone();
917     }
918 
919     /**
920      * Get security type params which depends on which security passphrase to set.
921      *
922      * @return One of:
923      * {@link #SECURITY_TYPE_OPEN},
924      * {@link #SECURITY_TYPE_WPA2_PSK},
925      * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
926      * {@link #SECURITY_TYPE_WPA3_SAE},
927      * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
928      * {@link #SECURITY_TYPE_WPA3_OWE}
929      */
getSecurityType()930     public @SecurityType int getSecurityType() {
931         return mSecurityType;
932     }
933 
934     /**
935      * Returns the maximum number of clients that can associate to the AP.
936      * See also {@link Builder#setMaxNumberOfClients(int)}.
937      *
938      * @hide
939      */
940     @SystemApi
getMaxNumberOfClients()941     public int getMaxNumberOfClients() {
942         return mMaxNumberOfClients;
943     }
944 
945     /**
946      * Returns whether auto shutdown is enabled or not.
947      * The Soft AP will shutdown when there are no devices associated to it for
948      * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}.
949      *
950      * @hide
951      */
952     @SystemApi
isAutoShutdownEnabled()953     public boolean isAutoShutdownEnabled() {
954         return mAutoShutdownEnabled;
955     }
956 
957     /**
958      * Returns the shutdown timeout in milliseconds.
959      * The Soft AP will shutdown when there are no devices associated to it for
960      * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}.
961      *
962      * @hide
963      */
964     @SystemApi
getShutdownTimeoutMillis()965     public long getShutdownTimeoutMillis() {
966         if (!CompatChanges.isChangeEnabled(
967                 REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) {
968             // For legacy application, return 0 when setting is DEFAULT_TIMEOUT.
969             return 0;
970         }
971         return mShutdownTimeoutMillis;
972     }
973 
974     /**
975      * Returns a flag indicating whether clients need to be pre-approved by the user.
976      * (true: authorization required) or not (false: not required).
977      * See also {@link Builder#setClientControlByUserEnabled(Boolean)}.
978      *
979      * @return true when client isolation is enable.
980      *
981      * @hide
982      */
983     @SystemApi
isClientControlByUserEnabled()984     public boolean isClientControlByUserEnabled() {
985         return mClientControlByUser;
986     }
987 
988     /**
989      * Returns List of clients which aren't allowed to associate to the AP.
990      *
991      * Clients are configured using {@link Builder#setBlockedClientList(List)}
992      *
993      * @hide
994      */
995     @NonNull
996     @SystemApi
getBlockedClientList()997     public List<MacAddress> getBlockedClientList() {
998         return mBlockedClientList;
999     }
1000 
1001     /**
1002      * List of clients which are allowed to associate to the AP.
1003      * Clients are configured using {@link Builder#setAllowedClientList(List)}
1004      *
1005      * @hide
1006      */
1007     @NonNull
1008     @SystemApi
getAllowedClientList()1009     public List<MacAddress> getAllowedClientList() {
1010         return mAllowedClientList;
1011     }
1012 
1013     /**
1014      * Returns the level of MAC randomization for the AP BSSID.
1015      * See also {@link Builder#setMacRandomizationSetting(int)}.
1016      *
1017      * @hide
1018      */
1019     @RequiresApi(Build.VERSION_CODES.S)
1020     @SystemApi
1021     @MacRandomizationSetting
getMacRandomizationSetting()1022     public int getMacRandomizationSetting() {
1023         if (!SdkLevel.isAtLeastS()) {
1024             throw new UnsupportedOperationException();
1025         }
1026         return getMacRandomizationSettingInternal();
1027     }
1028 
1029     /**
1030      * @hide
1031      */
1032     @MacRandomizationSetting
getMacRandomizationSettingInternal()1033     public int getMacRandomizationSettingInternal() {
1034         return mMacRandomizationSetting;
1035     }
1036 
1037     /**
1038      * Returns whether opportunistic shutdown of an instance in bridged AP is enabled or not.
1039      *
1040      * See also {@link Builder#setBridgedModeOpportunisticShutdownEnabled(boolean}}
1041      * @hide
1042      */
1043     @RequiresApi(Build.VERSION_CODES.S)
1044     @SystemApi
isBridgedModeOpportunisticShutdownEnabled()1045     public boolean isBridgedModeOpportunisticShutdownEnabled() {
1046         if (!SdkLevel.isAtLeastS()) {
1047             throw new UnsupportedOperationException();
1048         }
1049         return isBridgedModeOpportunisticShutdownEnabledInternal();
1050     }
1051 
1052     /**
1053      * @see #isBridgedModeOpportunisticShutdownEnabled()
1054      * @hide
1055      */
isBridgedModeOpportunisticShutdownEnabledInternal()1056     public boolean isBridgedModeOpportunisticShutdownEnabledInternal() {
1057         return mBridgedModeOpportunisticShutdownEnabled;
1058     }
1059 
1060     /**
1061      * @see #isIeee80211axEnabled()
1062      * @hide
1063      */
isIeee80211axEnabledInternal()1064     public boolean isIeee80211axEnabledInternal() {
1065         return mIeee80211axEnabled;
1066     }
1067 
1068     /**
1069      * Returns whether or not 802.11ax is enabled on the SoftAP.
1070      * This is an indication that if the device support 802.11ax AP then to enable or disable
1071      * that feature. If the device does not support 802.11ax AP then this flag is ignored.
1072      * See also {@link Builder#setIeee80211axEnabled(boolean}}
1073      * @hide
1074      */
1075     @RequiresApi(Build.VERSION_CODES.S)
1076     @SystemApi
isIeee80211axEnabled()1077     public boolean isIeee80211axEnabled() {
1078         if (!SdkLevel.isAtLeastS()) {
1079             throw new UnsupportedOperationException();
1080         }
1081         return isIeee80211axEnabledInternal();
1082     }
1083 
1084     /**
1085      * Returns whether or not the Soft AP is configured to enable 802.11be.
1086      * This is an indication that if the device support 802.11be AP then to enable or disable
1087      * that feature. If the device does not support 802.11be AP then this flag is ignored.
1088      * See also {@link Builder#setIeee80211beEnabled(boolean}}
1089      * @hide
1090      */
1091     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1092     @SystemApi
isIeee80211beEnabled()1093     public boolean isIeee80211beEnabled() {
1094         if (!SdkLevel.isAtLeastT()) {
1095             throw new UnsupportedOperationException();
1096         }
1097         return mIeee80211beEnabled;
1098     }
1099 
1100     /**
1101      * Returns the allowed channels for ACS in a selected band.
1102      *
1103      * If an empty array is returned, then all channels in that band are allowed
1104      * The channels are configured using {@link Builder#setAllowedAcsChannels(int, int[])}
1105      *
1106      * @param band one of the following band types:
1107      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1108      *
1109      * @return array of the allowed channels for ACS in that band
1110      *
1111      * @hide
1112      */
1113     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1114     @NonNull
1115     @SystemApi
getAllowedAcsChannels(@andType int band)1116     public int[] getAllowedAcsChannels(@BandType int band) {
1117         if (!SdkLevel.isAtLeastT()) {
1118             throw new UnsupportedOperationException();
1119         }
1120         switch(band) {
1121             case BAND_2GHZ:
1122                 return mAllowedAcsChannels2g.stream().mapToInt(Integer::intValue).toArray();
1123             case BAND_5GHZ:
1124                 return mAllowedAcsChannels5g.stream().mapToInt(Integer::intValue).toArray();
1125             case BAND_6GHZ:
1126                 return mAllowedAcsChannels6g.stream().mapToInt(Integer::intValue).toArray();
1127             default:
1128                 throw new IllegalArgumentException("getAllowedAcsChannels: Invalid band: " + band);
1129         }
1130     }
1131 
1132     /**
1133      * Returns configured maximum channel bandwidth for the SoftAp connection.
1134      *
1135      * If not configured, it will return {@link SoftApInfo#CHANNEL_WIDTH_AUTO}
1136      *
1137      * @hide
1138      */
1139     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1140     @SystemApi
getMaxChannelBandwidth()1141     public @WifiAnnotations.Bandwidth int getMaxChannelBandwidth() {
1142         if (!SdkLevel.isAtLeastT()) {
1143             throw new UnsupportedOperationException();
1144         }
1145         return mMaxChannelBandwidth;
1146     }
1147 
1148     /**
1149      * Returns whether or not the {@link SoftApConfiguration} was configured by the user
1150      * (as opposed to the default system configuration).
1151      * <p>
1152      * The {@link SoftApConfiguration} is considered user edited once the
1153      * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} is called
1154      * - whether or not that configuration is the same as the default system configuration!
1155      *
1156      * @hide
1157      */
1158     @RequiresApi(Build.VERSION_CODES.S)
1159     @SystemApi
isUserConfiguration()1160     public boolean isUserConfiguration() {
1161         if (!SdkLevel.isAtLeastS()) {
1162             throw new UnsupportedOperationException();
1163         }
1164         return isUserConfigurationInternal();
1165     }
1166 
1167     /**
1168      * Returns the randomized MAC address to be used by this configuration.
1169      *
1170      * The Soft AP may be configured to use a persistent randomized MAC address with
1171      * {@link Builder#setMacRandomizationSetting(int)}. This method returns the persistent
1172      * randomized MAC address which will be used for the Soft AP controlled by this configuration.
1173      *
1174      * @hide
1175      */
1176     @SystemApi
getPersistentRandomizedMacAddress()1177     public @NonNull MacAddress getPersistentRandomizedMacAddress() {
1178         return mPersistentRandomizedMacAddress;
1179     }
1180 
1181     /**
1182      * @hide
1183      */
isUserConfigurationInternal()1184     public boolean isUserConfigurationInternal() {
1185         return mIsUserConfiguration;
1186     }
1187 
1188     /**
1189      * Returns the bridged mode opportunistic shutdown timeout in milliseconds.
1190      * An instance in bridged AP will shutdown when there is no device associated to it for
1191      * the timeout duration. See also
1192      * {@link Builder#setBridgedModeOpportunisticShutdownTimeoutMillis(long)}.
1193      *
1194      * @hide
1195      */
1196     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1197     @SystemApi
getBridgedModeOpportunisticShutdownTimeoutMillis()1198     public long getBridgedModeOpportunisticShutdownTimeoutMillis() {
1199         if (!SdkLevel.isAtLeastT()) {
1200             throw new UnsupportedOperationException();
1201         }
1202         return mBridgedModeOpportunisticShutdownTimeoutMillis;
1203     }
1204 
1205 
1206     /**
1207      * @hide
1208      */
getBridgedModeOpportunisticShutdownTimeoutMillisInternal()1209     public long getBridgedModeOpportunisticShutdownTimeoutMillisInternal() {
1210         return mBridgedModeOpportunisticShutdownTimeoutMillis;
1211     }
1212 
1213     /**
1214      * Return the vendor-provided configuration data, if it exists. See also {@link
1215      * Builder#setVendorData(List)}
1216      *
1217      * @return Vendor configuration data, or empty list if it does not exist.
1218      * @hide
1219      */
1220     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
1221     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
1222     @NonNull
1223     @SystemApi
getVendorData()1224     public List<OuiKeyedData> getVendorData() {
1225         if (!SdkLevel.isAtLeastV()) {
1226             throw new UnsupportedOperationException();
1227         }
1228         return mVendorData;
1229     }
1230 
1231     /**
1232      * Returns whether client isolation is enabled or not.
1233      *
1234      * Client isolation is used to disallow a connected Soft AP
1235      * client to communicate with other connected clients.
1236      *
1237      * @hide
1238      */
1239     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
1240     @FlaggedApi(Flags.FLAG_AP_ISOLATE)
1241     @SystemApi
isClientIsolationEnabled()1242     public boolean isClientIsolationEnabled() {
1243         if (!Environment.isSdkAtLeastB()) {
1244             throw new UnsupportedOperationException();
1245         }
1246         return mIsClientIsolationEnabled;
1247     }
1248 
1249     /**
1250      * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}.
1251      * Note that SoftApConfiguration may contain configuration which is cannot be represented
1252      * by the legacy WifiConfiguration, in such cases a null will be returned.
1253      *
1254      * To maintain legacy behavior, the SSID of the WifiConfiguration will be the UTF-8
1255      * representation of the SSID without double quotes, as opposed to the double-quoted UTF-8
1256      * format documented in {@link WifiConfiguration#SSID}. If the SSID cannot be decoded as UTF-8,
1257      * then the SSID of the WifiConfiguration will be {@link WifiManager#UNKNOWN_SSID}.
1258      *
1259      * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports
1260      * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li>
1261      *
1262      * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports
1263      * NONE, WPA2_PSK, so conversion is limited to these security type.</li>
1264      * @hide
1265      */
1266     @Nullable
1267     @SystemApi
toWifiConfiguration()1268     public WifiConfiguration toWifiConfiguration() {
1269         WifiConfiguration wifiConfig = new WifiConfiguration();
1270         CharSequence utf8Text = mWifiSsid != null ? mWifiSsid.getUtf8Text() : null;
1271         wifiConfig.SSID = utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID;
1272         wifiConfig.preSharedKey = mPassphrase;
1273         wifiConfig.hiddenSSID = mHiddenSsid;
1274         wifiConfig.apChannel = getChannel();
1275         switch (mSecurityType) {
1276             case SECURITY_TYPE_OPEN:
1277                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1278                 break;
1279             case SECURITY_TYPE_WPA2_PSK:
1280             case SECURITY_TYPE_WPA3_SAE_TRANSITION:
1281                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
1282                 break;
1283             default:
1284                 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType);
1285                 return null;
1286         }
1287 
1288         switch (getBand()) {
1289             case BAND_2GHZ:
1290                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_2GHZ;
1291                 break;
1292             case BAND_5GHZ:
1293                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_5GHZ;
1294                 break;
1295             case BAND_2GHZ | BAND_5GHZ:
1296                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
1297                 break;
1298             case BAND_ANY:
1299                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
1300                 break;
1301             default:
1302                 Log.e(TAG, "Convert fail, unsupported band setting :" + getBand());
1303                 return null;
1304         }
1305         return wifiConfig;
1306     }
1307 
1308     /**
1309      * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
1310      * Soft AP.
1311      *
1312      * All fields are optional. By default, SSID and BSSID are automatically chosen by the
1313      * framework, and an open network is created.
1314      */
1315     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
1316     public static final class Builder {
1317         private WifiSsid mWifiSsid;
1318         private MacAddress mBssid;
1319         private String mPassphrase;
1320         private boolean mHiddenSsid;
1321         private SparseIntArray mChannels;
1322         private int mMaxNumberOfClients;
1323         private int mSecurityType;
1324         private boolean mAutoShutdownEnabled;
1325         private long mShutdownTimeoutMillis;
1326         private boolean mClientControlByUser;
1327         private List<MacAddress> mBlockedClientList;
1328         private List<MacAddress> mAllowedClientList;
1329         private int mMacRandomizationSetting;
1330         private boolean mBridgedModeOpportunisticShutdownEnabled;
1331         private boolean mIeee80211axEnabled;
1332         private boolean mIeee80211beEnabled;
1333         private boolean mIsUserConfiguration;
1334         private long mBridgedModeOpportunisticShutdownTimeoutMillis;
1335         private List<ScanResult.InformationElement> mVendorElements;
1336         private MacAddress mPersistentRandomizedMacAddress;
1337         private Set<Integer> mAllowedAcsChannels2g;
1338         private Set<Integer> mAllowedAcsChannels5g;
1339         private Set<Integer> mAllowedAcsChannels6g;
1340         private @WifiAnnotations.Bandwidth int mMaxChannelBandwidth;
1341         private @Nullable List<OuiKeyedData> mVendorData;
1342         private boolean mIsClientIsolationEnabled;
1343 
1344         /**
1345          * Constructs a Builder with default values (see {@link Builder}).
1346          */
Builder()1347         public Builder() {
1348             mWifiSsid = null;
1349             mBssid = null;
1350             mPassphrase = null;
1351             mHiddenSsid = false;
1352             mChannels = new SparseIntArray(1);
1353             mChannels.put(BAND_2GHZ, 0);
1354             mMaxNumberOfClients = 0;
1355             mSecurityType = SECURITY_TYPE_OPEN;
1356             mAutoShutdownEnabled = true; // enabled by default.
1357             mShutdownTimeoutMillis = DEFAULT_TIMEOUT;
1358             mClientControlByUser = false;
1359             mBlockedClientList = new ArrayList<>();
1360             mAllowedClientList = new ArrayList<>();
1361             if (SdkLevel.isAtLeastT()) {
1362                 mMacRandomizationSetting = RANDOMIZATION_NON_PERSISTENT;
1363             } else {
1364                 mMacRandomizationSetting = RANDOMIZATION_PERSISTENT;
1365             }
1366             mBridgedModeOpportunisticShutdownEnabled = true;
1367             mIeee80211axEnabled = true;
1368             mIeee80211beEnabled = true;
1369             mIsUserConfiguration = true;
1370             mBridgedModeOpportunisticShutdownTimeoutMillis = DEFAULT_TIMEOUT;
1371             mVendorElements = new ArrayList<>();
1372             mPersistentRandomizedMacAddress = null;
1373             mAllowedAcsChannels2g = new HashSet<>();
1374             mAllowedAcsChannels5g = new HashSet<>();
1375             mAllowedAcsChannels6g = new HashSet<>();
1376             mMaxChannelBandwidth = SoftApInfo.CHANNEL_WIDTH_AUTO;
1377             mVendorData = new ArrayList<>();
1378             mIsClientIsolationEnabled = false;
1379         }
1380 
1381         /**
1382          * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
1383          *
1384          * @hide
1385          */
1386         @SystemApi
Builder(@onNull SoftApConfiguration other)1387         public Builder(@NonNull SoftApConfiguration other) {
1388             if (other == null) {
1389                 Log.e(TAG, "Cannot provide a null SoftApConfiguration");
1390                 return;
1391             }
1392 
1393             mWifiSsid = other.mWifiSsid;
1394             mBssid = other.mBssid;
1395             mPassphrase = other.mPassphrase;
1396             mHiddenSsid = other.mHiddenSsid;
1397             mChannels = other.mChannels.clone();
1398             mMaxNumberOfClients = other.mMaxNumberOfClients;
1399             mSecurityType = other.mSecurityType;
1400             mAutoShutdownEnabled = other.mAutoShutdownEnabled;
1401             mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
1402             mClientControlByUser = other.mClientControlByUser;
1403             mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
1404             mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
1405             mMacRandomizationSetting = other.mMacRandomizationSetting;
1406             mBridgedModeOpportunisticShutdownEnabled =
1407                     other.mBridgedModeOpportunisticShutdownEnabled;
1408             mIeee80211axEnabled = other.mIeee80211axEnabled;
1409             mIeee80211beEnabled = other.mIeee80211beEnabled;
1410             mIsUserConfiguration = other.mIsUserConfiguration;
1411             mBridgedModeOpportunisticShutdownTimeoutMillis =
1412                     other.mBridgedModeOpportunisticShutdownTimeoutMillis;
1413             mVendorElements = new ArrayList<>(other.mVendorElements);
1414             mPersistentRandomizedMacAddress = other.mPersistentRandomizedMacAddress;
1415             mAllowedAcsChannels2g = new HashSet<>(other.mAllowedAcsChannels2g);
1416             mAllowedAcsChannels5g = new HashSet<>(other.mAllowedAcsChannels5g);
1417             mAllowedAcsChannels6g = new HashSet<>(other.mAllowedAcsChannels6g);
1418             mMaxChannelBandwidth = other.mMaxChannelBandwidth;
1419             if (SdkLevel.isAtLeastS() && mBssid != null) {
1420                 // Auto set correct MAC randomization setting for the legacy SoftApConfiguration
1421                 // to avoid the exception happen when framework (system server) copy
1422                 // SoftApConfiguration.
1423                 mMacRandomizationSetting = RANDOMIZATION_NONE;
1424             }
1425             mVendorData = new ArrayList<>(other.mVendorData);
1426             mIsClientIsolationEnabled = other.mIsClientIsolationEnabled;
1427         }
1428 
1429        /**
1430          * Builds the {@link SoftApConfiguration} without any check.
1431          *
1432          * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
1433          *
1434          * @hide
1435          */
1436         @VisibleForTesting
1437         @NonNull
buildWithoutCheck()1438         public SoftApConfiguration buildWithoutCheck() {
1439             return new SoftApConfiguration(
1440                     mWifiSsid,
1441                     mBssid,
1442                     mPassphrase,
1443                     mHiddenSsid,
1444                     mChannels,
1445                     mSecurityType,
1446                     mMaxNumberOfClients,
1447                     mAutoShutdownEnabled,
1448                     mShutdownTimeoutMillis,
1449                     mClientControlByUser,
1450                     mBlockedClientList,
1451                     mAllowedClientList,
1452                     mMacRandomizationSetting,
1453                     mBridgedModeOpportunisticShutdownEnabled,
1454                     mIeee80211axEnabled,
1455                     mIeee80211beEnabled,
1456                     mIsUserConfiguration,
1457                     mBridgedModeOpportunisticShutdownTimeoutMillis,
1458                     mVendorElements,
1459                     mPersistentRandomizedMacAddress,
1460                     mAllowedAcsChannels2g,
1461                     mAllowedAcsChannels5g,
1462                     mAllowedAcsChannels6g,
1463                     mMaxChannelBandwidth,
1464                     mVendorData,
1465                     mIsClientIsolationEnabled);
1466         }
1467 
1468         /**
1469          * Builds the {@link SoftApConfiguration}.
1470          *
1471          * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
1472          */
1473         @NonNull
build()1474         public SoftApConfiguration build() {
1475             for (MacAddress client : mAllowedClientList) {
1476                 if (mBlockedClientList.contains(client)) {
1477                     throw new IllegalArgumentException("A MacAddress exist in both client list");
1478                 }
1479             }
1480 
1481             // mMacRandomizationSetting supported from S.
1482             if (SdkLevel.isAtLeastS() && CompatChanges.isChangeEnabled(
1483                     FORCE_MUTUAL_EXCLUSIVE_BSSID_MAC_RAMDONIZATION_SETTING)
1484                     && mBssid != null && mMacRandomizationSetting != RANDOMIZATION_NONE) {
1485                 throw new IllegalArgumentException("A BSSID had configured but MAC randomization"
1486                         + " setting is not NONE");
1487             }
1488 
1489             if (!CompatChanges.isChangeEnabled(
1490                     REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) {
1491                 mShutdownTimeoutMillis = 0; // Use 0 for legacy app.
1492             }
1493 
1494             if (SdkLevel.isAtLeastB() && !mIeee80211axEnabled) {
1495                 // Force 11BE to false since 11ax has dependency with 11AX.
1496                 mIeee80211beEnabled = false;
1497             }
1498             return new SoftApConfiguration(
1499                     mWifiSsid,
1500                     mBssid,
1501                     mPassphrase,
1502                     mHiddenSsid,
1503                     mChannels,
1504                     mSecurityType,
1505                     mMaxNumberOfClients,
1506                     mAutoShutdownEnabled,
1507                     mShutdownTimeoutMillis,
1508                     mClientControlByUser,
1509                     mBlockedClientList,
1510                     mAllowedClientList,
1511                     mMacRandomizationSetting,
1512                     mBridgedModeOpportunisticShutdownEnabled,
1513                     mIeee80211axEnabled,
1514                     mIeee80211beEnabled,
1515                     mIsUserConfiguration,
1516                     mBridgedModeOpportunisticShutdownTimeoutMillis,
1517                     mVendorElements,
1518                     mPersistentRandomizedMacAddress,
1519                     mAllowedAcsChannels2g,
1520                     mAllowedAcsChannels5g,
1521                     mAllowedAcsChannels6g,
1522                     mMaxChannelBandwidth,
1523                     mVendorData,
1524                     mIsClientIsolationEnabled);
1525         }
1526 
1527         /**
1528          * Specifies a UTF-8 SSID for the AP.
1529          * <p>
1530          * Null SSID only support when configure a local-only hotspot.
1531          * <p>
1532          * <li>If not set, defaults to null.</li>
1533          *
1534          * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
1535          *             chosen by the framework.
1536          * @return Builder for chaining.
1537          * @throws IllegalArgumentException when the SSID is empty, not unicode, or if the byte
1538          *                                  representation is longer than 32 bytes.
1539          *
1540          * @deprecated Use {@link #setWifiSsid(WifiSsid)} instead.
1541          *
1542          * @hide
1543          */
1544         @NonNull
1545         @Deprecated
1546         @SystemApi
setSsid(@ullable String ssid)1547         public Builder setSsid(@Nullable String ssid) {
1548             if (ssid == null) {
1549                 mWifiSsid = null;
1550                 return this;
1551             }
1552 
1553             Preconditions.checkStringNotEmpty(ssid);
1554             Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
1555             mWifiSsid = WifiSsid.fromUtf8Text(ssid);
1556             return this;
1557         }
1558 
1559         /**
1560          * Specifies an SSID for the AP in the form of WifiSsid.
1561          * <p>
1562          * Null SSID only support when configure a local-only hotspot.
1563          * <p>
1564          * <li>If not set, defaults to null.</li>
1565          *
1566          * @param wifiSsid SSID, or null ot have the SSID automatically chosen by the framework.
1567          * @return Builder for chaining.
1568          *
1569          * @hide
1570          */
1571         @NonNull
1572         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1573         @SystemApi
setWifiSsid(@ullable WifiSsid wifiSsid)1574         public Builder setWifiSsid(@Nullable WifiSsid wifiSsid) {
1575             if (!SdkLevel.isAtLeastT()) {
1576                 throw new UnsupportedOperationException();
1577             }
1578             mWifiSsid = wifiSsid;
1579             return this;
1580         }
1581 
1582         /**
1583          * Specify vendor-specific information elements for the (Soft) AP to transmit in its beacons
1584          * and probe responses. Method also validates the structure and throws
1585          * IllegalArgumentException in cases when ID of IE is not 0xDD (221) or incoming list
1586          * contain duplicate elements.
1587          *
1588          * @param vendorElements VendorElements
1589          * @return Builder for chaining.
1590          *
1591          * @hide
1592          */
1593         @NonNull
1594         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1595         @SystemApi
setVendorElements( @onNull List<ScanResult.InformationElement> vendorElements)1596         public Builder setVendorElements(
1597                 @NonNull List<ScanResult.InformationElement> vendorElements) {
1598             if (!SdkLevel.isAtLeastT()) {
1599                 throw new UnsupportedOperationException();
1600             }
1601             for (ScanResult.InformationElement e : vendorElements) {
1602                 if (e.id != ScanResult.InformationElement.EID_VSA) {
1603                     throw new IllegalArgumentException("received InformationElement which is not "
1604                             + "related to VendorElements. VendorElement block should start with "
1605                             + HexEncoding.encodeToString(
1606                                     new byte[]{ (byte) ScanResult.InformationElement.EID_VSA }));
1607                 }
1608             }
1609             final HashSet<ScanResult.InformationElement> set = new HashSet<>(vendorElements);
1610             if (set.size() < vendorElements.size()) {
1611                 throw new IllegalArgumentException("vendor elements array contain duplicates. "
1612                         + "Please avoid passing duplicated and keep structure clean.");
1613             }
1614             mVendorElements = new ArrayList<>(vendorElements);
1615             return this;
1616         }
1617 
1618         /**
1619          * Specifies a BSSID for the AP.
1620          * <p>
1621          * <li>If not set, defaults to null.</li>
1622          *
1623          * When this method is called, the caller needs to configure MAC randomization settings to
1624          * {@link #RANDOMIZATION_NONE}. See {@link #setMacRandomizationSetting(int)} for details.
1625          *
1626          * If multiple bands are requested via {@link #setBands(int[])} or
1627          * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework
1628          * only sends down 1 MAC address.
1629          *
1630          * An example (but different implementation may perform a different mapping):
1631          * <li>MAC address 1: copy value of MAC address,
1632          * and set byte 1 = (0xFF - BSSID[1])</li>
1633          * <li>MAC address 2: copy value of MAC address,
1634          * and set byte 2 = (0xFF - BSSID[2])</li>
1635          *
1636          * Example BSSID argument: e2:38:60:c4:0e:b7
1637          * Derived MAC address 1: e2:c7:60:c4:0e:b7
1638          * Derived MAC address 2: e2:38:9f:c4:0e:b7
1639          *
1640          * <p>
1641          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1642          * {@link SoftApCapability#areFeaturesSupported(long)}
1643          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
1644          * whether or not this feature is supported.
1645          *
1646          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
1647          *              responsible for avoiding collisions.
1648          * @return Builder for chaining.
1649          * @throws IllegalArgumentException when the given BSSID is the all-zero
1650          *                                  , multicast or broadcast MAC address.
1651          *
1652          * @hide
1653          */
1654         @NonNull
1655         @SystemApi
setBssid(@ullable MacAddress bssid)1656         public Builder setBssid(@Nullable MacAddress bssid) {
1657             if (bssid != null) {
1658                 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
1659                 if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) {
1660                     throw new IllegalArgumentException("bssid doesn't support "
1661                             + "multicast or broadcast mac address");
1662                 }
1663             }
1664             mBssid = bssid;
1665             return this;
1666         }
1667 
1668         /**
1669          * Specifies that this AP should use specific security type with the given ASCII passphrase.
1670          *
1671          * @param securityType One of the following security types:
1672          * {@link #SECURITY_TYPE_OPEN},
1673          * {@link #SECURITY_TYPE_WPA2_PSK},
1674          * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
1675          * {@link #SECURITY_TYPE_WPA3_SAE},
1676          * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
1677          * {@link #SECURITY_TYPE_WPA3_OWE}.
1678          * @param passphrase The passphrase to use for sepcific {@code securityType} configuration
1679          * or null with {@link #SECURITY_TYPE_OPEN}, {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
1680          * and {@link #SECURITY_TYPE_WPA3_OWE}.
1681          *
1682          * @return Builder for chaining.
1683          * @throws IllegalArgumentException when the passphrase is non-null for
1684          *             - {@link #SECURITY_TYPE_OPEN}
1685          *             - {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION}
1686          *             - {@link #SECURITY_TYPE_WPA3_OWE}
1687          * @throws IllegalArgumentException when the passphrase is empty for
1688          *             - {@link #SECURITY_TYPE_WPA2_PSK},
1689          *             - {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
1690          *             - {@link #SECURITY_TYPE_WPA3_SAE},
1691          * @throws IllegalArgumentException before {@link android.os.Build.VERSION_CODES#TIRAMISU})
1692          *         when the passphrase is not between 8 and 63 bytes (inclusive) for
1693          *             - {@link #SECURITY_TYPE_WPA2_PSK}
1694          *             - {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}
1695          *
1696          * @hide
1697          */
1698         @NonNull
1699         @SystemApi
setPassphrase(@ullable String passphrase, @SecurityType int securityType)1700         public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
1701             if (!SdkLevel.isAtLeastT()
1702                     && (securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION
1703                             || securityType == SECURITY_TYPE_WPA3_OWE)) {
1704                 throw new UnsupportedOperationException();
1705             }
1706             if (securityType == SECURITY_TYPE_OPEN
1707                     || securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION
1708                     || securityType == SECURITY_TYPE_WPA3_OWE) {
1709                 if (passphrase != null) {
1710                     throw new IllegalArgumentException(
1711                             "passphrase should be null when security type is open");
1712                 }
1713             } else {
1714                 Preconditions.checkStringNotEmpty(passphrase);
1715                 if (!SdkLevel.isAtLeastT() && (securityType == SECURITY_TYPE_WPA2_PSK
1716                         || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION)) {
1717                     int passphraseByteLength = 0;
1718                     if (!TextUtils.isEmpty(passphrase)) {
1719                         passphraseByteLength = passphrase.getBytes(StandardCharsets.UTF_8).length;
1720                     }
1721                     if (passphraseByteLength < PSK_MIN_LEN || passphraseByteLength > PSK_MAX_LEN) {
1722                         throw new IllegalArgumentException(
1723                                 "Passphrase length must be at least " + PSK_MIN_LEN
1724                                         + " and no more than " + PSK_MAX_LEN
1725                                         + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
1726                     }
1727                 }
1728             }
1729             mSecurityType = securityType;
1730             mPassphrase = passphrase;
1731             return this;
1732         }
1733 
1734         /**
1735          * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
1736          * not (broadcasts its SSID).
1737          * <p>
1738          * <li>If not set, defaults to false (i.e not a hidden network).</li>
1739          *
1740          * @param hiddenSsid true for a hidden SSID, false otherwise.
1741          * @return Builder for chaining.
1742          *
1743          * @hide
1744          */
1745         @NonNull
1746         @SystemApi
setHiddenSsid(boolean hiddenSsid)1747         public Builder setHiddenSsid(boolean hiddenSsid) {
1748             mHiddenSsid = hiddenSsid;
1749             return this;
1750         }
1751 
1752         /**
1753          * Specifies the band for the AP.
1754          * <p>
1755          * <li>If not set, defaults to {@link #BAND_2GHZ}.</li>
1756          *
1757          * @param band One or combination of the following band type:
1758          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1759          * @return Builder for chaining.
1760          * @throws IllegalArgumentException when an invalid band type is provided.
1761          *
1762          * @hide
1763          */
1764         @NonNull
1765         @SystemApi
setBand(@andType int band)1766         public Builder setBand(@BandType int band) {
1767             if (!isBandValid(band)) {
1768                 throw new IllegalArgumentException("Invalid band type: " + band);
1769             }
1770             mChannels = new SparseIntArray(1);
1771             mChannels.put(band, 0);
1772             return this;
1773         }
1774 
1775         /**
1776          * Specifies the bands for the APs.
1777          * If more than 1 band is set, this will bring up concurrent APs.
1778          * on the requested bands (if possible).
1779          * <p>
1780          *
1781          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1782          * whether or not concurrent APs are supported.
1783          *
1784          * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1785          * when multiple bands are configured. Otherwise,
1786          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1787          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1788          *
1789          * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error
1790          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1791          *
1792          * @param bands Array of the {@link #BandType}.
1793          * @return Builder for chaining.
1794          * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
1795          *                                  is provided.
1796          *
1797          * @hide
1798          */
1799         @RequiresApi(Build.VERSION_CODES.S)
1800         @NonNull
1801         @SystemApi
setBands(@onNull int[] bands)1802         public Builder setBands(@NonNull int[] bands) {
1803             if (!SdkLevel.isAtLeastS()) {
1804                 throw new UnsupportedOperationException();
1805             }
1806             if (bands.length == 0 || bands.length > 2) {
1807                 throw new IllegalArgumentException("Unsupported number of bands("
1808                         + bands.length + ") configured");
1809             }
1810             SparseIntArray channels = new SparseIntArray(bands.length);
1811             for (int val : bands) {
1812                 if (!isBandValid(val)) {
1813                     throw new IllegalArgumentException("Invalid band type: " + val);
1814                 }
1815                 channels.put(val, 0);
1816             }
1817             mChannels = channels;
1818             return this;
1819         }
1820 
1821 
1822         /**
1823          * Specifies the channel and associated band for the AP.
1824          *
1825          * The channel which AP resides on. Valid channels are country dependent.
1826          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
1827          * valid channels.
1828          *
1829          * <p>
1830          * If not set, the default for the channel is the special value 0 which has the
1831          * framework auto-select a valid channel from the band configured with
1832          * {@link #setBand(int)}.
1833          *
1834          * The channel auto selection will be offloaded to driver when
1835          * {@link SoftApCapability#areFeaturesSupported(long)}
1836          * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1837          * return true. The driver will auto select the best channel (e.g. best performance)
1838          * based on environment interference. Check {@link SoftApCapability} for more detail.
1839          *
1840          * The API contains (band, channel) input since the 6GHz band uses the same channel
1841          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1842          * uniquely identify individual channels.
1843          *
1844          * <p>
1845          * @param channel operating channel of the AP.
1846          * @param band containing this channel.
1847          * @return Builder for chaining.
1848          * @throws IllegalArgumentException when the invalid channel or band type is configured.
1849          *
1850          * @hide
1851          */
1852         @NonNull
1853         @SystemApi
setChannel(int channel, @BandType int band)1854         public Builder setChannel(int channel, @BandType int band) {
1855             if (!isChannelBandPairValid(channel, band)) {
1856                 throw new IllegalArgumentException("Invalid channel(" + channel
1857                         + ") & band (" + band + ") configured");
1858             }
1859             mChannels = new SparseIntArray(1);
1860             mChannels.put(band, channel);
1861             return this;
1862         }
1863 
1864         /**
1865          * Specifies the channels and associated bands for the APs.
1866          * <p>
1867          * The API contains (band, channel) input since the 6GHz band uses the same channel
1868          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1869          * uniquely identify individual channels.
1870          * <p>
1871          * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
1872          * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
1873          * <p>
1874          * Using the special value 0 which has the framework auto-select a valid channel
1875          * from the band configured.
1876          * When more than 1 channel/band is set, this will bring up concurrent APs on the requested
1877          * channels and bands (if possible).
1878          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1879          * whether concurrent APs are supported.
1880          * If not set, the default value is {@link #BAND_2GHZ} with the special channel value 0
1881          * which has the framework auto-select from {@link #BAND_2GHZ}.
1882          *
1883          * <p>
1884          * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of
1885          *                 {@code BAND_} and corresponding channel.
1886          * @return Builder for chaining.
1887          * @throws IllegalArgumentException when more than 2 channels are set or the invalid
1888          *                                  channel or band type is configured.
1889          */
1890         @RequiresApi(Build.VERSION_CODES.S)
1891         @NonNull
setChannels(@onNull SparseIntArray channels)1892         public Builder setChannels(@NonNull SparseIntArray channels) {
1893             if (!SdkLevel.isAtLeastS()) {
1894                 throw new UnsupportedOperationException();
1895             }
1896             if (channels.size() == 0 || channels.size() > 2) {
1897                 throw new IllegalArgumentException("Unsupported number of channels("
1898                         + channels.size() + ") configured");
1899             }
1900             for (int i = 0; i < channels.size(); i++) {
1901                 int channel = channels.valueAt(i);
1902                 int band = channels.keyAt(i);
1903                 if (channel == 0) {
1904                     if (!isBandValid(band)) {
1905                         throw new IllegalArgumentException("Invalid band type: " + band);
1906                     }
1907                 } else {
1908                     if (!isChannelBandPairValid(channel, band)) {
1909                         throw new IllegalArgumentException("Invalid channel(" + channel
1910                                 + ") & band (" + band + ") configured");
1911                     }
1912                 }
1913             }
1914             mChannels = channels.clone();
1915             return this;
1916         }
1917 
1918 
1919         /**
1920          * Specifies the maximum number of clients that can associate to the AP.
1921          *
1922          * The maximum number of clients (STAs) which can associate to the AP.
1923          * The AP will reject association from any clients above this number.
1924          * Specify a value of 0 to have the framework automatically use the maximum number
1925          * which the device can support (based on hardware and carrier constraints).
1926          * <p>
1927          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1928          * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients
1929          * which the device supports (based on hardware and carrier constraints).
1930          *
1931          * <p>
1932          * <li>If not set, defaults to 0.</li>
1933          *
1934          * This method requires HAL support. If the method is used to set a
1935          * non-zero {@code maxNumberOfClients} value then
1936          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1937          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1938          *
1939          * <p>
1940          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1941          * {@link SoftApCapability#areFeaturesSupported(long)}
1942          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
1943          * or not this feature is supported.
1944          *
1945          * @param maxNumberOfClients maximum client number of the AP.
1946          * @return Builder for chaining.
1947          *
1948          * @hide
1949          */
1950         @NonNull
1951         @SystemApi
setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)1952         public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) {
1953             if (maxNumberOfClients < 0) {
1954                 throw new IllegalArgumentException("maxNumberOfClients should be not negative");
1955             }
1956             mMaxNumberOfClients = maxNumberOfClients;
1957             return this;
1958         }
1959 
1960         /**
1961          * Specifies whether auto shutdown is enabled or not.
1962          * The Soft AP will shut down when there are no devices connected to it for
1963          * the timeout duration.
1964          *
1965          * <p>
1966          * <li>If not set, defaults to true</li>
1967          *
1968          * @param enable true to enable, false to disable.
1969          * @return Builder for chaining.
1970          *
1971          * @see #setShutdownTimeoutMillis(long)
1972          *
1973          * @hide
1974          */
1975         @NonNull
1976         @SystemApi
setAutoShutdownEnabled(boolean enable)1977         public Builder setAutoShutdownEnabled(boolean enable) {
1978             mAutoShutdownEnabled = enable;
1979             return this;
1980         }
1981 
1982         /**
1983          * Specifies the shutdown timeout in milliseconds.
1984          * The Soft AP will shut down when there are no devices connected to it for
1985          * the timeout duration.
1986          *
1987          * Specify a value of {@link #DEFAULT_TIMEOUT} to have the framework automatically use
1988          * default timeout setting which defined in
1989          * {@link R.integer.config_wifi_framework_soft_ap_timeout_delay}
1990          *
1991          * <p>
1992          * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li>
1993          * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is
1994          * set to true</li>
1995          *
1996          * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid
1997          *                      except {@link #DEFAULT_TIMEOUT}.
1998          * @return Builder for chaining.
1999          *
2000          * @see #setAutoShutdownEnabled(boolean)
2001          *
2002          * @hide
2003          */
2004         @NonNull
2005         @SystemApi
setShutdownTimeoutMillis(@ntRangefrom = -1) long timeoutMillis)2006         public Builder setShutdownTimeoutMillis(@IntRange(from = -1) long timeoutMillis) {
2007             if (CompatChanges.isChangeEnabled(
2008                     REMOVE_ZERO_FOR_TIMEOUT_SETTING) && timeoutMillis < 1) {
2009                 if (timeoutMillis != DEFAULT_TIMEOUT) {
2010                     throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis);
2011                 }
2012             } else if (timeoutMillis < 0) {
2013                 throw new IllegalArgumentException("Invalid timeout value from legacy app: "
2014                         + timeoutMillis);
2015             }
2016             mShutdownTimeoutMillis = timeoutMillis;
2017             return this;
2018         }
2019 
2020         /**
2021          * Configure the Soft AP to require manual user control of client association.
2022          * If disabled (the default) then any client which isn't in the blocked list
2023          * {@link #getBlockedClientList()} can associate to this Soft AP using the
2024          * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier,
2025          * or user limited - using {@link #setMaxNumberOfClients(int)}).
2026          *
2027          * If manual user control is enabled then clients will be accepted, rejected, or require
2028          * a user approval based on the configuration provided by
2029          * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
2030          *
2031          * <p>
2032          * This method requires HAL support. HAL support can be determined using
2033          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2034          * {@link SoftApCapability#areFeaturesSupported(long)}
2035          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
2036          *
2037          * <p>
2038          * If the method is called on a device without HAL support then starting the soft AP
2039          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
2040          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
2041          *
2042          * <p>
2043          * <li>If not set, defaults to false (i.e The authoriztion is not required).</li>
2044          *
2045          * @param enabled true for enabling the control by user, false otherwise.
2046          * @return Builder for chaining.
2047          *
2048          * @hide
2049          */
2050         @NonNull
2051         @SystemApi
setClientControlByUserEnabled(boolean enabled)2052         public Builder setClientControlByUserEnabled(boolean enabled) {
2053             mClientControlByUser = enabled;
2054             return this;
2055         }
2056 
2057         /**
2058          * Configures the set of channel numbers in the specified band that are allowed
2059          * to be selected by the Automatic Channel Selection (ACS) algorithm.
2060          * <p>
2061          *
2062          * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}.
2063          * Otherwise, these sets will be ignored.
2064          * <p>
2065          *
2066          * @param band one of the following band types:
2067          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
2068          *
2069          * @param channels that are allowed to be used by ACS algorithm in this band. If it is
2070          * configured to an empty array or not configured, then all channels within that band
2071          * will be allowed.
2072          * <p>
2073          *
2074          * @return Builder for chaining.
2075          *
2076          * @hide
2077          */
2078         @NonNull
2079         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2080         @SystemApi
setAllowedAcsChannels(@andType int band, @NonNull int[] channels)2081         public Builder setAllowedAcsChannels(@BandType int band, @NonNull int[] channels) {
2082             if (!SdkLevel.isAtLeastT()) {
2083                 throw new UnsupportedOperationException();
2084             }
2085 
2086             if (channels == null) {
2087                 throw new IllegalArgumentException(
2088                         "Passing a null object to setAllowedAcsChannels");
2089             }
2090 
2091             if ((band != BAND_2GHZ) && (band != BAND_5GHZ) && (band != BAND_6GHZ)) {
2092                 throw new IllegalArgumentException(
2093                         "Passing an invalid band to setAllowedAcsChannels");
2094             }
2095 
2096             for (int channel : channels) {
2097                 if (!isChannelBandPairValid(channel, band)) {
2098                     throw new IllegalArgumentException(
2099                             "Invalid channel to setAllowedAcsChannels: band: " + band
2100                             + "channel: " + channel);
2101                 }
2102             }
2103 
2104             HashSet<Integer> set = IntStream.of(channels).boxed()
2105                     .collect(Collectors.toCollection(HashSet::new));
2106             switch(band) {
2107                 case BAND_2GHZ:
2108                     mAllowedAcsChannels2g = set;
2109                     break;
2110                 case BAND_5GHZ:
2111                     mAllowedAcsChannels5g = set;
2112                     break;
2113                 case BAND_6GHZ:
2114                     mAllowedAcsChannels6g = set;
2115                     break;
2116             }
2117 
2118             return this;
2119         }
2120 
2121         /**
2122          * Sets maximum channel bandwidth for the SoftAp Connection
2123          *
2124          * If not set, the SoftAp connection will seek the maximum channel bandwidth achievable on
2125          * the device. However, in some cases the caller will need to put a cap on the channel
2126          * bandwidth through this API.
2127          *
2128          * @param maxChannelBandwidth one of {@link SoftApInfo#CHANNEL_WIDTH_AUTO},
2129          * {@link SoftApInfo#CHANNEL_WIDTH_20MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_40MHZ},
2130          * {@link SoftApInfo#CHANNEL_WIDTH_80MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_160MHZ},
2131          * or {@link SoftApInfo#CHANNEL_WIDTH_320MHZ}
2132          *
2133          * @return builder for chaining
2134          *
2135          * @hide
2136          */
2137         @NonNull
2138         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2139         @SystemApi
setMaxChannelBandwidth(@ifiAnnotations.Bandwidth int maxChannelBandwidth)2140         public Builder setMaxChannelBandwidth(@WifiAnnotations.Bandwidth int maxChannelBandwidth) {
2141             if (!SdkLevel.isAtLeastT()) {
2142                 throw new UnsupportedOperationException();
2143             }
2144 
2145             switch (maxChannelBandwidth) {
2146                 case SoftApInfo.CHANNEL_WIDTH_AUTO:
2147                 case SoftApInfo.CHANNEL_WIDTH_20MHZ:
2148                 case SoftApInfo.CHANNEL_WIDTH_40MHZ:
2149                 case SoftApInfo.CHANNEL_WIDTH_80MHZ:
2150                 case SoftApInfo.CHANNEL_WIDTH_160MHZ:
2151                 case SoftApInfo.CHANNEL_WIDTH_320MHZ:
2152                     mMaxChannelBandwidth = maxChannelBandwidth;
2153                     break;
2154                 default:
2155                     throw new IllegalArgumentException(
2156                             "Invalid channel bandwidth value("
2157                             + maxChannelBandwidth + ")  configured");
2158             }
2159             return this;
2160         }
2161 
2162         /**
2163          * This method together with {@link setClientControlByUserEnabled(boolean)} control client
2164          * connections to the AP. If client control by user is disabled using the above method then
2165          * this API has no effect and clients are allowed to associate to the AP (within limit of
2166          * max number of clients).
2167          *
2168          * If client control by user is enabled then this API configures the list of clients
2169          * which are explicitly allowed. These are auto-accepted.
2170          *
2171          * All other clients which attempt to associate, whose MAC addresses are on neither list,
2172          * are:
2173          * <ul>
2174          * <li>Rejected</li>
2175          * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
2176          * is issued (which allows the user to add them to the allowed client list if desired).<li>
2177          * </ul>
2178          *
2179          * @param allowedClientList list of clients which are allowed to associate to the AP
2180          *                          without user pre-approval.
2181          * @return Builder for chaining.
2182          *
2183          * @hide
2184          */
2185         @NonNull
2186         @SystemApi
setAllowedClientList(@onNull List<MacAddress> allowedClientList)2187         public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
2188             mAllowedClientList = new ArrayList<>(allowedClientList);
2189             return this;
2190         }
2191 
2192         /**
2193          * This API configures the list of clients which are blocked and cannot associate
2194          * to the Soft AP.
2195          *
2196          * <p>
2197          * This method requires HAL support. HAL support can be determined using
2198          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2199          * {@link SoftApCapability#areFeaturesSupported(long)}
2200          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
2201          *
2202          * <p>
2203          * If the method is called on a device without HAL support then starting the soft AP
2204          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
2205          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
2206          *
2207          * @param blockedClientList list of clients which are not allowed to associate to the AP.
2208          * @return Builder for chaining.
2209          *
2210          * @hide
2211          */
2212         @NonNull
2213         @SystemApi
setBlockedClientList(@onNull List<MacAddress> blockedClientList)2214         public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
2215             mBlockedClientList = new ArrayList<>(blockedClientList);
2216             return this;
2217         }
2218 
2219         /**
2220          * Specifies the level of MAC randomization for the AP BSSID.
2221          * The Soft AP BSSID will be randomized only if the BSSID isn't set
2222          * {@link #setBssid(MacAddress)} and this method is either uncalled
2223          * or called with {@link #RANDOMIZATION_PERSISTENT} or
2224          * {@link #RANDOMIZATION_NON_PERSISTENT}. When this method is called with
2225          * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_NON_PERSISTENT}, the caller
2226          * the caller must not call {@link #setBssid(MacAddress)}.
2227          *
2228          * <p>
2229          * <li>If not set, defaults to {@link #RANDOMIZATION_NON_PERSISTENT}</li>
2230          *
2231          * <p>
2232          * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT} or
2233          * {@link #RANDOMIZATION_NON_PERSISTENT}.
2234          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2235          * {@link SoftApCapability#areFeaturesSupported(long)}
2236          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
2237          * whether or not this feature is supported.
2238          *
2239          * @param macRandomizationSetting One of the following setting:
2240          * {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_PERSISTENT} or
2241          * {@link #RANDOMIZATION_NON_PERSISTENT}.
2242          * @return Builder for chaining.
2243          *
2244          * @see #setBssid(MacAddress)
2245          *
2246          * @hide
2247          */
2248         @RequiresApi(Build.VERSION_CODES.S)
2249         @NonNull
2250         @SystemApi
setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)2251         public Builder setMacRandomizationSetting(
2252                 @MacRandomizationSetting int macRandomizationSetting) {
2253             if (!SdkLevel.isAtLeastS()) {
2254                 throw new UnsupportedOperationException();
2255             }
2256             mMacRandomizationSetting = macRandomizationSetting;
2257             return this;
2258         }
2259 
2260 
2261         /**
2262          * Specifies whether or not opportunistic shut down of an AP instance in bridged mode
2263          * is enabled.
2264          *
2265          * <p>
2266          * If enabled, the framework will shutdown one of the AP instances if it is idle for
2267          * the timeout duration - meaning there are no devices connected to it.
2268          * If both AP instances are idle for the timeout duration then the framework will
2269          * shut down the AP instance operating on the higher frequency. For instance,
2270          * if the AP instances operate at 2.4GHz and 5GHz and are both idle for the
2271          * timeout duration then the 5GHz AP instance will be shut down.
2272          * <p>
2273          *
2274          * Note: the opportunistic timeout only applies to one AP instance of the bridge AP.
2275          * If one of the AP instances has already been disabled for any reason, including due to
2276          * an opportunistic timeout or hardware issues or coexistence issues,
2277          * then the opportunistic timeout is no longer active.
2278          *
2279          * <p>
2280          * The shutdown timer specified by {@link #setShutdownTimeoutMillis(long)} controls the
2281          * overall shutdown of the bridged AP and is still in use independently of the opportunistic
2282          * timer controlled by this AP.
2283          *
2284          * <p>
2285          * <li>If not set, defaults to true</li>
2286          *
2287          * @param enable true to enable, false to disable.
2288          * @return Builder for chaining.
2289          *
2290          * @hide
2291          */
2292         @RequiresApi(Build.VERSION_CODES.S)
2293         @NonNull
2294         @SystemApi
setBridgedModeOpportunisticShutdownEnabled(boolean enable)2295         public Builder setBridgedModeOpportunisticShutdownEnabled(boolean enable) {
2296             if (!SdkLevel.isAtLeastS()) {
2297                 throw new UnsupportedOperationException();
2298             }
2299             mBridgedModeOpportunisticShutdownEnabled = enable;
2300             return this;
2301         }
2302 
2303         /**
2304          * Specifies whether or not to enable 802.11ax on the Soft AP.
2305          *
2306          * <p>
2307          * Note: Only relevant when the device supports 802.11ax on the Soft AP.
2308          * If enabled on devices that do not support 802.11ax then ignored.
2309          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2310          * {@link SoftApCapability#areFeaturesSupported(long)}
2311          * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX} to determine
2312          * whether or not 802.11ax is supported on the Soft AP.
2313          * <p>
2314          * <li>If not set, defaults to true - which will be ignored on devices
2315          * which do not support 802.11ax</li>
2316          *
2317          * @param enable true to enable, false to disable.
2318          * @return Builder for chaining.
2319          *
2320          * @hide
2321          */
2322         @RequiresApi(Build.VERSION_CODES.S)
2323         @NonNull
2324         @SystemApi
setIeee80211axEnabled(boolean enable)2325         public Builder setIeee80211axEnabled(boolean enable) {
2326             if (!SdkLevel.isAtLeastS()) {
2327                 throw new UnsupportedOperationException();
2328             }
2329             mIeee80211axEnabled = enable;
2330             return this;
2331         }
2332 
2333         /**
2334          * Specifies whether or not to enable 802.11be on the Soft AP.
2335          *
2336          * <p>
2337          * Note: Only relevant when the device supports 802.11be on the Soft AP.
2338          * If enabled on devices that do not support 802.11be then ignored.
2339          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2340          * {@link SoftApCapability#areFeaturesSupported(long)}
2341          * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE} to determine
2342          * whether or not 802.11be is supported on the Soft AP.
2343          * <p>
2344          * <li>If not set, defaults to true - which will be ignored on devices
2345          * which do not support 802.11be</li>
2346          *
2347          * @param enable true to enable, false to disable.
2348          * @return Builder for chaining.
2349          *
2350          * @hide
2351          */
2352         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2353         @NonNull
2354         @SystemApi
setIeee80211beEnabled(boolean enable)2355         public Builder setIeee80211beEnabled(boolean enable) {
2356             if (!SdkLevel.isAtLeastT()) {
2357                 throw new UnsupportedOperationException();
2358             }
2359             mIeee80211beEnabled = enable;
2360             return this;
2361         }
2362 
2363         /**
2364          * Specifies whether or not the configuration is configured by user.
2365          *
2366          * @param isUserConfigured true to user configuration, false otherwise.
2367          * @return Builder for chaining.
2368          *
2369          * @hide
2370          */
2371         @NonNull
setUserConfiguration(boolean isUserConfigured)2372         public Builder setUserConfiguration(boolean isUserConfigured) {
2373             mIsUserConfiguration = isUserConfigured;
2374             return this;
2375         }
2376 
2377         /**
2378          * Specifies bridged mode opportunistic shutdown timeout in milliseconds.
2379          * An instance of bridged Soft AP will shut down when there is no device connected to it
2380          * for this timeout duration.
2381          *
2382          * Specify a value of {@link DEFAULT_TIMEOUT} to have the framework automatically use
2383          * default timeout setting defined by
2384          * {@link
2385          * R.integer.config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond}
2386          *
2387          * <p>
2388          * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li>
2389          * <li>The shut down timeout will apply when
2390          * {@link #setBridgedModeOpportunisticShutdownEnabled(boolean)} is set to true</li>
2391          *
2392          * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid
2393          *                      except {@link #DEFAULT_TIMEOUT}.
2394          * @return Builder for chaining.
2395          *
2396          * @see #setBridgedModeOpportunisticShutdownEnabled(boolean)
2397          *
2398          * @hide
2399          */
2400         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2401         @NonNull
2402         @SystemApi
setBridgedModeOpportunisticShutdownTimeoutMillis( @ntRangefrom = -1) long timeoutMillis)2403         public Builder setBridgedModeOpportunisticShutdownTimeoutMillis(
2404                 @IntRange(from = -1) long timeoutMillis) {
2405             if (!SdkLevel.isAtLeastT()) {
2406                 throw new UnsupportedOperationException();
2407             }
2408             if (timeoutMillis < 1 && timeoutMillis != DEFAULT_TIMEOUT) {
2409                 throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis);
2410             }
2411             mBridgedModeOpportunisticShutdownTimeoutMillis = timeoutMillis;
2412             return this;
2413         }
2414 
2415         /**
2416          * @param mac persistent randomized MacAddress generated by the frameworks.
2417          * @hide
2418          */
2419         @NonNull
setRandomizedMacAddress(@onNull MacAddress mac)2420         public Builder setRandomizedMacAddress(@NonNull MacAddress mac) {
2421             if (mac == null) {
2422                 throw new IllegalArgumentException("setRandomizedMacAddress received"
2423                         + " null MacAddress.");
2424             }
2425             mPersistentRandomizedMacAddress = mac;
2426             return this;
2427         }
2428 
2429         /**
2430          * Set additional vendor-provided configuration data.
2431          *
2432          * @param vendorData List of {@link OuiKeyedData} containing the vendor-provided
2433          *     configuration data. Note that multiple elements with the same OUI are allowed.
2434          * @return Builder for chaining.
2435          *
2436          * @hide
2437          */
2438         @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
2439         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2440         @NonNull
2441         @SystemApi
setVendorData(@onNull List<OuiKeyedData> vendorData)2442         public Builder setVendorData(@NonNull List<OuiKeyedData> vendorData) {
2443             if (!SdkLevel.isAtLeastV()) {
2444                 throw new UnsupportedOperationException();
2445             }
2446             if (vendorData == null) {
2447                 throw new IllegalArgumentException("setVendorData received a null value");
2448             }
2449             mVendorData = vendorData;
2450             return this;
2451         }
2452 
2453         /**
2454          * Specifies whether or not client isolation is enabled.
2455          *
2456          * Client isolation can be used to disallow a connected Soft AP
2457          * client to communicate with other connected clients.
2458          *
2459          * @param isClientIsolationEnabled true when enabling client isolation.
2460          * @return Builder for chaining.
2461          *
2462          * @hide
2463          */
2464         @FlaggedApi(Flags.FLAG_AP_ISOLATE)
2465         @RequiresApi(Build.VERSION_CODES.BAKLAVA)
2466         @NonNull
2467         @SystemApi
setClientIsolationEnabled(boolean isClientIsolationEnabled)2468         public Builder setClientIsolationEnabled(boolean isClientIsolationEnabled) {
2469             if (!Environment.isSdkAtLeastB()) {
2470                 throw new UnsupportedOperationException();
2471             }
2472             mIsClientIsolationEnabled = isClientIsolationEnabled;
2473             return this;
2474         }
2475     }
2476 }
2477