• 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.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.compat.Compatibility;
25 import android.compat.annotation.ChangeId;
26 import android.compat.annotation.EnabledAfter;
27 import android.net.MacAddress;
28 import android.net.wifi.util.HexEncoding;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.util.SparseIntArray;
35 
36 import androidx.annotation.RequiresApi;
37 
38 import com.android.internal.util.Preconditions;
39 import com.android.modules.utils.build.SdkLevel;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 import java.nio.charset.StandardCharsets;
44 import java.util.ArrayList;
45 import java.util.HashSet;
46 import java.util.List;
47 import java.util.Objects;
48 import java.util.Set;
49 import java.util.stream.Collectors;
50 import java.util.stream.IntStream;
51 
52 /**
53  * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
54  *
55  * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
56  * framework how it should configure a hotspot.
57  *
58  * System apps can use this to configure a tethered hotspot using
59  * {@code WifiManager#startTetheredHotspot(SoftApConfiguration)} and
60  * {@code WifiManager#setSoftApConfiguration(SoftApConfiguration)}
61  * or local-only hotspot using
62  * {@code WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
63  * WifiManager.LocalOnlyHotspotCallback)}.
64  *
65  * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to
66  * create a new instance.
67  *
68  */
69 public final class SoftApConfiguration implements Parcelable {
70 
71     private static final String TAG = "SoftApConfiguration";
72 
73     /**
74      * 2GHz band.
75      * @hide
76      */
77     @SystemApi
78     public static final int BAND_2GHZ = 1 << 0;
79 
80     /**
81      * 5GHz band.
82      * @hide
83      */
84     @SystemApi
85     public static final int BAND_5GHZ = 1 << 1;
86 
87     /**
88      * 6GHz band.
89      * @hide
90      */
91     @SystemApi
92     public static final int BAND_6GHZ = 1 << 2;
93 
94     /**
95      * 60GHz band.
96      * @hide
97      */
98     @SystemApi
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     /**
404      * THe definition of security type OPEN.
405      */
406     public static final int SECURITY_TYPE_OPEN = 0;
407 
408     /**
409      * The definition of security type WPA2-PSK.
410      */
411     public static final int SECURITY_TYPE_WPA2_PSK = 1;
412 
413     /**
414      * The definition of security type WPA3-SAE Transition mode.
415      */
416     public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
417 
418     /**
419      * The definition of security type WPA3-SAE.
420      */
421     public static final int SECURITY_TYPE_WPA3_SAE = 3;
422 
423     /**
424      * The definition of security type WPA3-OWE Transition.
425      */
426     public static final int SECURITY_TYPE_WPA3_OWE_TRANSITION = 4;
427 
428     /**
429      * The definition of security type WPA3-OWE.
430      */
431     public static final int SECURITY_TYPE_WPA3_OWE = 5;
432 
433     /** @hide */
434     @Retention(RetentionPolicy.SOURCE)
435     @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
436         SECURITY_TYPE_OPEN,
437         SECURITY_TYPE_WPA2_PSK,
438         SECURITY_TYPE_WPA3_SAE_TRANSITION,
439         SECURITY_TYPE_WPA3_SAE,
440         SECURITY_TYPE_WPA3_OWE_TRANSITION,
441         SECURITY_TYPE_WPA3_OWE,
442     })
443     public @interface SecurityType {}
444 
445     /** 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)446     private SoftApConfiguration(@Nullable WifiSsid ssid, @Nullable MacAddress bssid,
447             @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels,
448             @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
449             long shutdownTimeoutMillis, boolean clientControlByUser,
450             @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList,
451             int macRandomizationSetting, boolean bridgedModeOpportunisticShutdownEnabled,
452             boolean ieee80211axEnabled, boolean ieee80211beEnabled, boolean isUserConfiguration,
453             long bridgedModeOpportunisticShutdownTimeoutMillis,
454             @NonNull List<ScanResult.InformationElement> vendorElements,
455             @Nullable MacAddress persistentRandomizedMacAddress,
456             @NonNull Set<Integer> allowedAcsChannels24g, @NonNull Set<Integer> allowedAcsChannels5g,
457             @NonNull Set<Integer> allowedAcsChannels6g,
458             @WifiAnnotations.Bandwidth int maxChannelBandwidth) {
459         mWifiSsid = ssid;
460         mBssid = bssid;
461         mPassphrase = passphrase;
462         mHiddenSsid = hiddenSsid;
463         if (channels.size() != 0) {
464             mChannels = channels.clone();
465         } else {
466             mChannels = new SparseIntArray(1);
467             mChannels.put(BAND_2GHZ, 0);
468         }
469         mSecurityType = securityType;
470         mMaxNumberOfClients = maxNumberOfClients;
471         mAutoShutdownEnabled = shutdownTimeoutEnabled;
472         mShutdownTimeoutMillis = shutdownTimeoutMillis;
473         mClientControlByUser = clientControlByUser;
474         mBlockedClientList = new ArrayList<>(blockedList);
475         mAllowedClientList = new ArrayList<>(allowedList);
476         mMacRandomizationSetting = macRandomizationSetting;
477         mBridgedModeOpportunisticShutdownEnabled = bridgedModeOpportunisticShutdownEnabled;
478         mIeee80211axEnabled = ieee80211axEnabled;
479         mIeee80211beEnabled = ieee80211beEnabled;
480         mIsUserConfiguration = isUserConfiguration;
481         mBridgedModeOpportunisticShutdownTimeoutMillis =
482                 bridgedModeOpportunisticShutdownTimeoutMillis;
483         mVendorElements = new ArrayList<>(vendorElements);
484         mPersistentRandomizedMacAddress = persistentRandomizedMacAddress;
485         mAllowedAcsChannels2g = new HashSet<>(allowedAcsChannels24g);
486         mAllowedAcsChannels5g = new HashSet<>(allowedAcsChannels5g);
487         mAllowedAcsChannels6g = new HashSet<>(allowedAcsChannels6g);
488         mMaxChannelBandwidth = maxChannelBandwidth;
489     }
490 
491     @Override
equals(Object otherObj)492     public boolean equals(Object otherObj) {
493         if (this == otherObj) {
494             return true;
495         }
496         if (!(otherObj instanceof SoftApConfiguration)) {
497             return false;
498         }
499         SoftApConfiguration other = (SoftApConfiguration) otherObj;
500         return Objects.equals(mWifiSsid, other.mWifiSsid)
501                 && Objects.equals(mBssid, other.mBssid)
502                 && Objects.equals(mPassphrase, other.mPassphrase)
503                 && mHiddenSsid == other.mHiddenSsid
504                 && mChannels.toString().equals(other.mChannels.toString())
505                 && mSecurityType == other.mSecurityType
506                 && mMaxNumberOfClients == other.mMaxNumberOfClients
507                 && mAutoShutdownEnabled == other.mAutoShutdownEnabled
508                 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
509                 && mClientControlByUser == other.mClientControlByUser
510                 && Objects.equals(mBlockedClientList, other.mBlockedClientList)
511                 && Objects.equals(mAllowedClientList, other.mAllowedClientList)
512                 && mMacRandomizationSetting == other.mMacRandomizationSetting
513                 && mBridgedModeOpportunisticShutdownEnabled
514                         == other.mBridgedModeOpportunisticShutdownEnabled
515                 && mIeee80211axEnabled == other.mIeee80211axEnabled
516                 && mIeee80211beEnabled == other.mIeee80211beEnabled
517                 && mIsUserConfiguration == other.mIsUserConfiguration
518                 && mBridgedModeOpportunisticShutdownTimeoutMillis
519                         == other.mBridgedModeOpportunisticShutdownTimeoutMillis
520                 && Objects.equals(mVendorElements, other.mVendorElements)
521                 && Objects.equals(mPersistentRandomizedMacAddress,
522                         other.mPersistentRandomizedMacAddress)
523                 && Objects.equals(mAllowedAcsChannels2g, other.mAllowedAcsChannels2g)
524                 && Objects.equals(mAllowedAcsChannels5g, other.mAllowedAcsChannels5g)
525                 && Objects.equals(mAllowedAcsChannels6g, other.mAllowedAcsChannels6g)
526                 && mMaxChannelBandwidth == other.mMaxChannelBandwidth;
527     }
528 
529     @Override
hashCode()530     public int hashCode() {
531         return Objects.hash(mWifiSsid, mBssid, mPassphrase, mHiddenSsid,
532                 mChannels.toString(), mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
533                 mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
534                 mAllowedClientList, mMacRandomizationSetting,
535                 mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled, mIeee80211beEnabled,
536                 mIsUserConfiguration, mBridgedModeOpportunisticShutdownTimeoutMillis,
537                 mVendorElements, mPersistentRandomizedMacAddress, mAllowedAcsChannels2g,
538                 mAllowedAcsChannels5g, mAllowedAcsChannels6g, mMaxChannelBandwidth);
539     }
540 
541     @Override
toString()542     public String toString() {
543         StringBuilder sbuf = new StringBuilder();
544         sbuf.append("ssid = ").append(mWifiSsid == null ? null : mWifiSsid.toString());
545         if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString());
546         sbuf.append(" \n Passphrase = ").append(
547                 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
548         sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid);
549         sbuf.append(" \n Channels = ").append(mChannels);
550         sbuf.append(" \n SecurityType = ").append(getSecurityType());
551         sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients);
552         sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled);
553         sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis);
554         sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser);
555         sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList);
556         sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList);
557         sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting);
558         sbuf.append(" \n BridgedModeInstanceOpportunisticEnabled = ")
559                 .append(mBridgedModeOpportunisticShutdownEnabled);
560         sbuf.append(" \n BridgedModeOpportunisticShutdownTimeoutMillis = ")
561                 .append(mBridgedModeOpportunisticShutdownTimeoutMillis);
562         sbuf.append(" \n Ieee80211axEnabled = ").append(mIeee80211axEnabled);
563         sbuf.append(" \n Ieee80211beEnabled = ").append(mIeee80211beEnabled);
564         sbuf.append(" \n isUserConfiguration = ").append(mIsUserConfiguration);
565         sbuf.append(" \n vendorElements = ").append(mVendorElements);
566         sbuf.append(" \n mPersistentRandomizedMacAddress = ")
567                 .append(mPersistentRandomizedMacAddress);
568         sbuf.append(" \n mAllowedAcsChannels2g = ").append(mAllowedAcsChannels2g);
569         sbuf.append(" \n mAllowedAcsChannels5g = ").append(mAllowedAcsChannels5g);
570         sbuf.append(" \n mAllowedAcsChannels6g = ").append(mAllowedAcsChannels6g);
571         sbuf.append(" \n mMaxChannelBandwidth = ").append(mMaxChannelBandwidth);
572         return sbuf.toString();
573     }
574 
575     @Override
writeToParcel(@onNull Parcel dest, int flags)576     public void writeToParcel(@NonNull Parcel dest, int flags) {
577         dest.writeParcelable(mWifiSsid, 0);
578         dest.writeParcelable(mBssid, flags);
579         dest.writeString(mPassphrase);
580         dest.writeBoolean(mHiddenSsid);
581         writeSparseIntArray(dest, mChannels);
582         dest.writeInt(mSecurityType);
583         dest.writeInt(mMaxNumberOfClients);
584         dest.writeBoolean(mAutoShutdownEnabled);
585         dest.writeLong(mShutdownTimeoutMillis);
586         dest.writeBoolean(mClientControlByUser);
587         dest.writeTypedList(mBlockedClientList);
588         dest.writeTypedList(mAllowedClientList);
589         dest.writeInt(mMacRandomizationSetting);
590         dest.writeBoolean(mBridgedModeOpportunisticShutdownEnabled);
591         dest.writeBoolean(mIeee80211axEnabled);
592         dest.writeBoolean(mIeee80211beEnabled);
593         dest.writeBoolean(mIsUserConfiguration);
594         dest.writeLong(mBridgedModeOpportunisticShutdownTimeoutMillis);
595         dest.writeTypedList(mVendorElements);
596         dest.writeParcelable(mPersistentRandomizedMacAddress, flags);
597         writeHashSetInt(dest, mAllowedAcsChannels2g);
598         writeHashSetInt(dest, mAllowedAcsChannels5g);
599         writeHashSetInt(dest, mAllowedAcsChannels6g);
600         dest.writeInt(mMaxChannelBandwidth);
601     }
602 
603     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
writeSparseIntArray(@onNull Parcel dest, @Nullable SparseIntArray val)604     private static void writeSparseIntArray(@NonNull Parcel dest,
605             @Nullable SparseIntArray val) {
606         if (val == null) {
607             dest.writeInt(-1);
608             return;
609         }
610         int n = val.size();
611         dest.writeInt(n);
612         int i = 0;
613         while (i < n) {
614             dest.writeInt(val.keyAt(i));
615             dest.writeInt(val.valueAt(i));
616             i++;
617         }
618     }
619 
620     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
621     @NonNull
readSparseIntArray(@onNull Parcel in)622     private static SparseIntArray readSparseIntArray(@NonNull Parcel in) {
623         int n = in.readInt();
624         if (n < 0) {
625             return new SparseIntArray();
626         }
627         SparseIntArray sa = new SparseIntArray(n);
628         while (n > 0) {
629             int key = in.readInt();
630             int value = in.readInt();
631             sa.append(key, value);
632             n--;
633         }
634         return sa;
635     }
636 
637     /* Write HashSet<Integer> into Parcel */
writeHashSetInt(@onNull Parcel dest, @NonNull Set<Integer> set)638     private static void writeHashSetInt(@NonNull Parcel dest, @NonNull Set<Integer> set) {
639         if (set.isEmpty()) {
640             dest.writeInt(-1);
641             return;
642         }
643 
644         dest.writeInt(set.size());
645         for (int val : set) {
646             dest.writeInt(val);
647         }
648     }
649 
650     /* Read HashSet<Integer> from Parcel */
651     @NonNull
readHashSetInt(@onNull Parcel in)652     private static Set<Integer> readHashSetInt(@NonNull Parcel in) {
653         Set<Integer> set = new HashSet<>();
654         int len = in.readInt();
655         if (len < 0) {
656             return set;
657         }
658 
659         for (int i = 0; i < len; i++) {
660             set.add(in.readInt());
661         }
662         return set;
663     }
664 
665     @Override
describeContents()666     public int describeContents() {
667         return 0;
668     }
669 
670     @NonNull
671     public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() {
672         @Override
673         public SoftApConfiguration createFromParcel(Parcel in) {
674             return new SoftApConfiguration(
675                     in.readParcelable(WifiSsid.class.getClassLoader()),
676                     in.readParcelable(MacAddress.class.getClassLoader()),
677                     in.readString(), in.readBoolean(), readSparseIntArray(in), in.readInt(),
678                     in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
679                     in.createTypedArrayList(MacAddress.CREATOR),
680                     in.createTypedArrayList(MacAddress.CREATOR), in.readInt(), in.readBoolean(),
681                     in.readBoolean(), in.readBoolean(), in.readBoolean(), in.readLong(),
682                     in.createTypedArrayList(ScanResult.InformationElement.CREATOR),
683                     in.readParcelable(MacAddress.class.getClassLoader()),
684                     readHashSetInt(in),
685                     readHashSetInt(in),
686                     readHashSetInt(in),
687                     in.readInt());
688         }
689 
690         @Override
691         public SoftApConfiguration[] newArray(int size) {
692             return new SoftApConfiguration[size];
693         }
694     };
695 
696     /**
697      * Return the UTF-8 String set to be the SSID for the AP. If the SSID cannot be decoded as
698      * UTF-8, then this will return {@link WifiManager#UNKNOWN_SSID}
699      * See also {@link Builder#setSsid(String)}.
700      *
701      * @deprecated Use {@link #getWifiSsid()} instead.
702      */
703     @Nullable
704     @Deprecated
getSsid()705     public String getSsid() {
706         if (mWifiSsid == null) {
707             return null;
708         }
709         CharSequence utf8Text = mWifiSsid.getUtf8Text();
710         return utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID;
711     }
712 
713     /**
714      * Return WifiSsid set to be the SSID for the AP.
715      * See also {@link Builder#setWifiSsid(WifiSsid)}.
716      */
717     @Nullable
getWifiSsid()718     public WifiSsid getWifiSsid() {
719         return mWifiSsid;
720     }
721 
722     /**
723      * Return VendorElements for the AP.
724      * @hide
725      */
726     @NonNull
727     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
728     @SystemApi
getVendorElements()729     public List<ScanResult.InformationElement> getVendorElements() {
730         if (!SdkLevel.isAtLeastT()) {
731             throw new UnsupportedOperationException();
732         }
733         return getVendorElementsInternal();
734     }
735 
736     /**
737      * @see #getVendorElements()
738      * @hide
739      */
getVendorElementsInternal()740     public List<ScanResult.InformationElement> getVendorElementsInternal() {
741         return new ArrayList<>(mVendorElements);
742     }
743 
744     /**
745      * Returns MAC address set to be BSSID for the AP.
746      * See also {@link Builder#setBssid(MacAddress)}.
747      */
748     @Nullable
getBssid()749     public MacAddress getBssid() {
750         return mBssid;
751     }
752 
753     /**
754      * Returns String set to be passphrase for current AP.
755      * See also {@link Builder#setPassphrase(String, int)}.
756      */
757     @Nullable
getPassphrase()758     public String getPassphrase() {
759         return mPassphrase;
760     }
761 
762     /**
763      * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
764      * not (false: broadcasts its SSID) for the AP.
765      * See also {@link Builder#setHiddenSsid(boolean)}.
766      */
isHiddenSsid()767     public boolean isHiddenSsid() {
768         return mHiddenSsid;
769     }
770 
771     /**
772      * Returns band type set to be the band for the AP.
773      *
774      * One or combination of {@code BAND_}, for instance
775      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
776      *
777      * Note: Returns the lowest band when more than one band is set.
778      * Use {@link #getChannels()} to get dual bands setting.
779      *
780      * See also {@link Builder#setBand(int)}.
781      *
782      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
783      * @hide
784      */
785     @Deprecated
786     @SystemApi
getBand()787     public @BandType int getBand() {
788         return mChannels.keyAt(0);
789     }
790 
791     /**
792      * Returns a sorted array in ascending order that consists of the configured band types
793      * for the APs.
794      *
795      * The band type is one or combination of {@code BAND_}, for instance
796      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
797      *
798      * Note: return array may only include one band when current setting is single AP mode.
799      * See also {@link Builder#setBands(int[])}.
800      *
801      * @hide
802      */
getBands()803     public @NonNull int[] getBands() {
804         int[] bands = new int[mChannels.size()];
805         for (int i = 0; i < bands.length; i++) {
806             bands[i] = mChannels.keyAt(i);
807         }
808         return bands;
809     }
810 
811     /**
812      * Returns Integer set to be the channel for the AP.
813      *
814      * Note: Returns the channel which associated to the lowest band if more than one channel
815      * is set. Use {@link Builder#getChannels()} to get dual channel setting.
816      * See also {@link Builder#setChannel(int, int)}.
817      *
818      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
819      * @hide
820      */
821     @Deprecated
822     @SystemApi
getChannel()823     public int getChannel() {
824         return mChannels.valueAt(0);
825     }
826 
827 
828     /**
829      * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of
830      * the configured bands and channels for the AP(s).
831      *
832      * The returned channel value is Wi-Fi channel numbering.
833      * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
834      * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
835      *
836      * Note: return array may only include one channel when current setting is single AP mode.
837      * See also {@link Builder#setChannels(SparseIntArray)}.
838      *
839      * @hide
840      */
841     @RequiresApi(Build.VERSION_CODES.S)
842     @SystemApi
getChannels()843     public @NonNull SparseIntArray getChannels() {
844         if (!SdkLevel.isAtLeastS()) {
845             throw new UnsupportedOperationException();
846         }
847         return mChannels.clone();
848     }
849 
850     /**
851      * Get security type params which depends on which security passphrase to set.
852      *
853      * @return One of:
854      * {@link #SECURITY_TYPE_OPEN},
855      * {@link #SECURITY_TYPE_WPA2_PSK},
856      * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
857      * {@link #SECURITY_TYPE_WPA3_SAE},
858      * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
859      * {@link #SECURITY_TYPE_WPA3_OWE}
860      */
getSecurityType()861     public @SecurityType int getSecurityType() {
862         return mSecurityType;
863     }
864 
865     /**
866      * Returns the maximum number of clients that can associate to the AP.
867      * See also {@link Builder#setMaxNumberOfClients(int)}.
868      *
869      * @hide
870      */
871     @SystemApi
getMaxNumberOfClients()872     public int getMaxNumberOfClients() {
873         return mMaxNumberOfClients;
874     }
875 
876     /**
877      * Returns whether auto shutdown is enabled or not.
878      * The Soft AP will shutdown when there are no devices associated to it for
879      * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}.
880      *
881      * @hide
882      */
883     @SystemApi
isAutoShutdownEnabled()884     public boolean isAutoShutdownEnabled() {
885         return mAutoShutdownEnabled;
886     }
887 
888     /**
889      * Returns the shutdown timeout in milliseconds.
890      * The Soft AP will shutdown when there are no devices associated to it for
891      * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}.
892      *
893      * @hide
894      */
895     @SystemApi
getShutdownTimeoutMillis()896     public long getShutdownTimeoutMillis() {
897         if (!Compatibility.isChangeEnabled(
898                 REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) {
899             // For legacy application, return 0 when setting is DEFAULT_TIMEOUT.
900             return 0;
901         }
902         return mShutdownTimeoutMillis;
903     }
904 
905     /**
906      * Returns a flag indicating whether clients need to be pre-approved by the user.
907      * (true: authorization required) or not (false: not required).
908      * See also {@link Builder#setClientControlByUserEnabled(Boolean)}.
909      *
910      * @hide
911      */
912     @SystemApi
isClientControlByUserEnabled()913     public boolean isClientControlByUserEnabled() {
914         return mClientControlByUser;
915     }
916 
917     /**
918      * Returns List of clients which aren't allowed to associate to the AP.
919      *
920      * Clients are configured using {@link Builder#setBlockedClientList(List)}
921      *
922      * @hide
923      */
924     @NonNull
925     @SystemApi
getBlockedClientList()926     public List<MacAddress> getBlockedClientList() {
927         return mBlockedClientList;
928     }
929 
930     /**
931      * List of clients which are allowed to associate to the AP.
932      * Clients are configured using {@link Builder#setAllowedClientList(List)}
933      *
934      * @hide
935      */
936     @NonNull
937     @SystemApi
getAllowedClientList()938     public List<MacAddress> getAllowedClientList() {
939         return mAllowedClientList;
940     }
941 
942     /**
943      * Returns the level of MAC randomization for the AP BSSID.
944      * See also {@link Builder#setMacRandomizationSetting(int)}.
945      *
946      * @hide
947      */
948     @RequiresApi(Build.VERSION_CODES.S)
949     @SystemApi
950     @MacRandomizationSetting
getMacRandomizationSetting()951     public int getMacRandomizationSetting() {
952         if (!SdkLevel.isAtLeastS()) {
953             throw new UnsupportedOperationException();
954         }
955         return getMacRandomizationSettingInternal();
956     }
957 
958     /**
959      * @hide
960      */
961     @MacRandomizationSetting
getMacRandomizationSettingInternal()962     public int getMacRandomizationSettingInternal() {
963         return mMacRandomizationSetting;
964     }
965 
966     /**
967      * Returns whether opportunistic shutdown of an instance in bridged AP is enabled or not.
968      *
969      * See also {@link Builder#setBridgedModeOpportunisticShutdownEnabled(boolean}}
970      * @hide
971      */
972     @RequiresApi(Build.VERSION_CODES.S)
973     @SystemApi
isBridgedModeOpportunisticShutdownEnabled()974     public boolean isBridgedModeOpportunisticShutdownEnabled() {
975         if (!SdkLevel.isAtLeastS()) {
976             throw new UnsupportedOperationException();
977         }
978         return isBridgedModeOpportunisticShutdownEnabledInternal();
979     }
980 
981     /**
982      * @see #isBridgedModeOpportunisticShutdownEnabled()
983      * @hide
984      */
isBridgedModeOpportunisticShutdownEnabledInternal()985     public boolean isBridgedModeOpportunisticShutdownEnabledInternal() {
986         return mBridgedModeOpportunisticShutdownEnabled;
987     }
988 
989     /**
990      * @see #isIeee80211axEnabled()
991      * @hide
992      */
isIeee80211axEnabledInternal()993     public boolean isIeee80211axEnabledInternal() {
994         return mIeee80211axEnabled;
995     }
996 
997     /**
998      * Returns whether or not 802.11ax is enabled on the SoftAP.
999      * This is an indication that if the device support 802.11ax AP then to enable or disable
1000      * that feature. If the device does not support 802.11ax AP then this flag is ignored.
1001      * See also {@link Builder#setIeee80211axEnabled(boolean}}
1002      * @hide
1003      */
1004     @RequiresApi(Build.VERSION_CODES.S)
1005     @SystemApi
isIeee80211axEnabled()1006     public boolean isIeee80211axEnabled() {
1007         if (!SdkLevel.isAtLeastS()) {
1008             throw new UnsupportedOperationException();
1009         }
1010         return isIeee80211axEnabledInternal();
1011     }
1012 
1013     /**
1014      * @see #isIeee80211beEnabled()
1015      * @hide
1016      */
isIeee80211beEnabledInternal()1017     public boolean isIeee80211beEnabledInternal() {
1018         return mIeee80211beEnabled;
1019     }
1020 
1021     /**
1022      * Returns whether or not the Soft AP is configured to enable 802.11be.
1023      * This is an indication that if the device support 802.11be AP then to enable or disable
1024      * that feature. If the device does not support 802.11be AP then this flag is ignored.
1025      * See also {@link Builder#setIeee80211beEnabled(boolean}}
1026      * @hide
1027      */
1028     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1029     @SystemApi
isIeee80211beEnabled()1030     public boolean isIeee80211beEnabled() {
1031         if (!SdkLevel.isAtLeastT()) {
1032             throw new UnsupportedOperationException();
1033         }
1034         return isIeee80211beEnabledInternal();
1035     }
1036 
1037     /**
1038      * Returns the allowed channels for ACS in a selected band.
1039      *
1040      * If an empty array is returned, then all channels in that band are allowed
1041      * The channels are configured using {@link Builder#setAllowedAcsChannels(int, int[])}
1042      *
1043      * @param band one of the following band types:
1044      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1045      *
1046      * @return array of the allowed channels for ACS in that band
1047      *
1048      * @hide
1049      */
1050     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1051     @NonNull
1052     @SystemApi
getAllowedAcsChannels(@andType int band)1053     public int[] getAllowedAcsChannels(@BandType int band) {
1054         if (!SdkLevel.isAtLeastT()) {
1055             throw new UnsupportedOperationException();
1056         }
1057         switch(band) {
1058             case BAND_2GHZ:
1059                 return mAllowedAcsChannels2g.stream().mapToInt(Integer::intValue).toArray();
1060             case BAND_5GHZ:
1061                 return mAllowedAcsChannels5g.stream().mapToInt(Integer::intValue).toArray();
1062             case BAND_6GHZ:
1063                 return mAllowedAcsChannels6g.stream().mapToInt(Integer::intValue).toArray();
1064             default:
1065                 throw new IllegalArgumentException("getAllowedAcsChannels: Invalid band: " + band);
1066         }
1067     }
1068 
1069     /**
1070      * Returns configured maximum channel bandwidth for the SoftAp connection.
1071      *
1072      * If not configured, it will return {@link SoftApInfo#CHANNEL_WIDTH_AUTO}
1073      *
1074      * @hide
1075      */
1076     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1077     @SystemApi
getMaxChannelBandwidth()1078     public @WifiAnnotations.Bandwidth int getMaxChannelBandwidth() {
1079         if (!SdkLevel.isAtLeastT()) {
1080             throw new UnsupportedOperationException();
1081         }
1082         return mMaxChannelBandwidth;
1083     }
1084 
1085     /**
1086      * Returns whether or not the {@link SoftApConfiguration} was configured by the user
1087      * (as opposed to the default system configuration).
1088      * <p>
1089      * The {@link SoftApConfiguration} is considered user edited once the
1090      * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} is called
1091      * - whether or not that configuration is the same as the default system configuration!
1092      *
1093      * @hide
1094      */
1095     @RequiresApi(Build.VERSION_CODES.S)
1096     @SystemApi
isUserConfiguration()1097     public boolean isUserConfiguration() {
1098         if (!SdkLevel.isAtLeastS()) {
1099             throw new UnsupportedOperationException();
1100         }
1101         return isUserConfigurationInternal();
1102     }
1103 
1104     /**
1105      * Returns the randomized MAC address to be used by this configuration.
1106      *
1107      * The Soft AP may be configured to use a persistent randomized MAC address with
1108      * {@link Builder#setMacRandomizationSetting(int)}. This method returns the persistent
1109      * randomized MAC address which will be used for the Soft AP controlled by this configuration.
1110      *
1111      * @hide
1112      */
1113     @SystemApi
getPersistentRandomizedMacAddress()1114     public @NonNull MacAddress getPersistentRandomizedMacAddress() {
1115         return mPersistentRandomizedMacAddress;
1116     }
1117 
1118     /**
1119      * @hide
1120      */
isUserConfigurationInternal()1121     public boolean isUserConfigurationInternal() {
1122         return mIsUserConfiguration;
1123     }
1124 
1125     /**
1126      * Returns the bridged mode opportunistic shutdown timeout in milliseconds.
1127      * An instance in bridged AP will shutdown when there is no device associated to it for
1128      * the timeout duration. See also
1129      * {@link Builder#setBridgedModeOpportunisticShutdownTimeoutMillis(long)}.
1130      *
1131      * @hide
1132      */
1133     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1134     @SystemApi
getBridgedModeOpportunisticShutdownTimeoutMillis()1135     public long getBridgedModeOpportunisticShutdownTimeoutMillis() {
1136         if (!SdkLevel.isAtLeastT()) {
1137             throw new UnsupportedOperationException();
1138         }
1139         return mBridgedModeOpportunisticShutdownTimeoutMillis;
1140     }
1141 
1142 
1143     /**
1144      * @hide
1145      */
getBridgedModeOpportunisticShutdownTimeoutMillisInternal()1146     public long getBridgedModeOpportunisticShutdownTimeoutMillisInternal() {
1147         return mBridgedModeOpportunisticShutdownTimeoutMillis;
1148     }
1149 
1150     /**
1151      * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}.
1152      * Note that SoftApConfiguration may contain configuration which is cannot be represented
1153      * by the legacy WifiConfiguration, in such cases a null will be returned.
1154      *
1155      * To maintain legacy behavior, the SSID of the WifiConfiguration will be the UTF-8
1156      * representation of the SSID without double quotes, as opposed to the double-quoted UTF-8
1157      * format documented in {@link WifiConfiguration#SSID}. If the SSID cannot be decoded as UTF-8,
1158      * then the SSID of the WifiConfiguration will be {@link WifiManager#UNKNOWN_SSID}.
1159      *
1160      * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports
1161      * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li>
1162      *
1163      * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports
1164      * NONE, WPA2_PSK, so conversion is limited to these security type.</li>
1165      * @hide
1166      */
1167     @Nullable
1168     @SystemApi
toWifiConfiguration()1169     public WifiConfiguration toWifiConfiguration() {
1170         WifiConfiguration wifiConfig = new WifiConfiguration();
1171         CharSequence utf8Text = mWifiSsid != null ? mWifiSsid.getUtf8Text() : null;
1172         wifiConfig.SSID = utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID;
1173         wifiConfig.preSharedKey = mPassphrase;
1174         wifiConfig.hiddenSSID = mHiddenSsid;
1175         wifiConfig.apChannel = getChannel();
1176         switch (mSecurityType) {
1177             case SECURITY_TYPE_OPEN:
1178                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
1179                 break;
1180             case SECURITY_TYPE_WPA2_PSK:
1181             case SECURITY_TYPE_WPA3_SAE_TRANSITION:
1182                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
1183                 break;
1184             default:
1185                 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType);
1186                 return null;
1187         }
1188 
1189         switch (getBand()) {
1190             case BAND_2GHZ:
1191                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_2GHZ;
1192                 break;
1193             case BAND_5GHZ:
1194                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_5GHZ;
1195                 break;
1196             case BAND_2GHZ | BAND_5GHZ:
1197                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
1198                 break;
1199             case BAND_ANY:
1200                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
1201                 break;
1202             default:
1203                 Log.e(TAG, "Convert fail, unsupported band setting :" + getBand());
1204                 return null;
1205         }
1206         return wifiConfig;
1207     }
1208 
1209     /**
1210      * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
1211      * Soft AP.
1212      *
1213      * All fields are optional. By default, SSID and BSSID are automatically chosen by the
1214      * framework, and an open network is created.
1215      *
1216      * @hide
1217      */
1218     @SystemApi
1219     public static final class Builder {
1220         private WifiSsid mWifiSsid;
1221         private MacAddress mBssid;
1222         private String mPassphrase;
1223         private boolean mHiddenSsid;
1224         private SparseIntArray mChannels;
1225         private int mMaxNumberOfClients;
1226         private int mSecurityType;
1227         private boolean mAutoShutdownEnabled;
1228         private long mShutdownTimeoutMillis;
1229         private boolean mClientControlByUser;
1230         private List<MacAddress> mBlockedClientList;
1231         private List<MacAddress> mAllowedClientList;
1232         private int mMacRandomizationSetting;
1233         private boolean mBridgedModeOpportunisticShutdownEnabled;
1234         private boolean mIeee80211axEnabled;
1235         private boolean mIeee80211beEnabled;
1236         private boolean mIsUserConfiguration;
1237         private long mBridgedModeOpportunisticShutdownTimeoutMillis;
1238         private List<ScanResult.InformationElement> mVendorElements;
1239         private MacAddress mPersistentRandomizedMacAddress;
1240         private Set<Integer> mAllowedAcsChannels2g;
1241         private Set<Integer> mAllowedAcsChannels5g;
1242         private Set<Integer> mAllowedAcsChannels6g;
1243         private @WifiAnnotations.Bandwidth int mMaxChannelBandwidth;
1244 
1245         /**
1246          * Constructs a Builder with default values (see {@link Builder}).
1247          */
Builder()1248         public Builder() {
1249             mWifiSsid = null;
1250             mBssid = null;
1251             mPassphrase = null;
1252             mHiddenSsid = false;
1253             mChannels = new SparseIntArray(1);
1254             mChannels.put(BAND_2GHZ, 0);
1255             mMaxNumberOfClients = 0;
1256             mSecurityType = SECURITY_TYPE_OPEN;
1257             mAutoShutdownEnabled = true; // enabled by default.
1258             mShutdownTimeoutMillis = DEFAULT_TIMEOUT;
1259             mClientControlByUser = false;
1260             mBlockedClientList = new ArrayList<>();
1261             mAllowedClientList = new ArrayList<>();
1262             if (SdkLevel.isAtLeastT()) {
1263                 mMacRandomizationSetting = RANDOMIZATION_NON_PERSISTENT;
1264             } else {
1265                 mMacRandomizationSetting = RANDOMIZATION_PERSISTENT;
1266             }
1267             mBridgedModeOpportunisticShutdownEnabled = true;
1268             mIeee80211axEnabled = true;
1269             mIeee80211beEnabled = true;
1270             mIsUserConfiguration = true;
1271             mBridgedModeOpportunisticShutdownTimeoutMillis = DEFAULT_TIMEOUT;
1272             mVendorElements = new ArrayList<>();
1273             mPersistentRandomizedMacAddress = null;
1274             mAllowedAcsChannels2g = new HashSet<>();
1275             mAllowedAcsChannels5g = new HashSet<>();
1276             mAllowedAcsChannels6g = new HashSet<>();
1277             mMaxChannelBandwidth = SoftApInfo.CHANNEL_WIDTH_AUTO;
1278         }
1279 
1280         /**
1281          * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
1282          */
Builder(@onNull SoftApConfiguration other)1283         public Builder(@NonNull SoftApConfiguration other) {
1284             Objects.requireNonNull(other);
1285 
1286             mWifiSsid = other.mWifiSsid;
1287             mBssid = other.mBssid;
1288             mPassphrase = other.mPassphrase;
1289             mHiddenSsid = other.mHiddenSsid;
1290             mChannels = other.mChannels.clone();
1291             mMaxNumberOfClients = other.mMaxNumberOfClients;
1292             mSecurityType = other.mSecurityType;
1293             mAutoShutdownEnabled = other.mAutoShutdownEnabled;
1294             mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
1295             mClientControlByUser = other.mClientControlByUser;
1296             mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
1297             mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
1298             mMacRandomizationSetting = other.mMacRandomizationSetting;
1299             mBridgedModeOpportunisticShutdownEnabled =
1300                     other.mBridgedModeOpportunisticShutdownEnabled;
1301             mIeee80211axEnabled = other.mIeee80211axEnabled;
1302             mIeee80211beEnabled = other.mIeee80211beEnabled;
1303             mIsUserConfiguration = other.mIsUserConfiguration;
1304             mBridgedModeOpportunisticShutdownTimeoutMillis =
1305                     other.mBridgedModeOpportunisticShutdownTimeoutMillis;
1306             mVendorElements = new ArrayList<>(other.mVendorElements);
1307             mPersistentRandomizedMacAddress = other.mPersistentRandomizedMacAddress;
1308             mAllowedAcsChannels2g = new HashSet<>(other.mAllowedAcsChannels2g);
1309             mAllowedAcsChannels5g = new HashSet<>(other.mAllowedAcsChannels5g);
1310             mAllowedAcsChannels6g = new HashSet<>(other.mAllowedAcsChannels6g);
1311             mMaxChannelBandwidth = other.mMaxChannelBandwidth;
1312             if (SdkLevel.isAtLeastS() && mBssid != null) {
1313                 // Auto set correct MAC randomization setting for the legacy SoftApConfiguration
1314                 // to avoid the exception happen when framework (system server) copy
1315                 // SoftApConfiguration.
1316                 mMacRandomizationSetting = RANDOMIZATION_NONE;
1317             }
1318         }
1319 
1320         /**
1321          * Builds the {@link SoftApConfiguration}.
1322          *
1323          * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
1324          */
1325         @NonNull
build()1326         public SoftApConfiguration build() {
1327             for (MacAddress client : mAllowedClientList) {
1328                 if (mBlockedClientList.contains(client)) {
1329                     throw new IllegalArgumentException("A MacAddress exist in both client list");
1330                 }
1331             }
1332 
1333             // mMacRandomizationSetting supported from S.
1334             if (SdkLevel.isAtLeastS() && Compatibility.isChangeEnabled(
1335                     FORCE_MUTUAL_EXCLUSIVE_BSSID_MAC_RAMDONIZATION_SETTING)
1336                     && mBssid != null && mMacRandomizationSetting != RANDOMIZATION_NONE) {
1337                 throw new IllegalArgumentException("A BSSID had configured but MAC randomization"
1338                         + " setting is not NONE");
1339             }
1340 
1341             if (!Compatibility.isChangeEnabled(
1342                     REMOVE_ZERO_FOR_TIMEOUT_SETTING) && mShutdownTimeoutMillis == DEFAULT_TIMEOUT) {
1343                 mShutdownTimeoutMillis = 0; // Use 0 for legacy app.
1344             }
1345             return new SoftApConfiguration(mWifiSsid, mBssid, mPassphrase,
1346                     mHiddenSsid, mChannels, mSecurityType, mMaxNumberOfClients,
1347                     mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
1348                     mBlockedClientList, mAllowedClientList, mMacRandomizationSetting,
1349                     mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled,
1350                     mIeee80211beEnabled, mIsUserConfiguration,
1351                     mBridgedModeOpportunisticShutdownTimeoutMillis, mVendorElements,
1352                     mPersistentRandomizedMacAddress, mAllowedAcsChannels2g, mAllowedAcsChannels5g,
1353                     mAllowedAcsChannels6g, mMaxChannelBandwidth);
1354         }
1355 
1356         /**
1357          * Specifies a UTF-8 SSID for the AP.
1358          * <p>
1359          * Null SSID only support when configure a local-only hotspot.
1360          * <p>
1361          * <li>If not set, defaults to null.</li>
1362          *
1363          * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
1364          *             chosen by the framework.
1365          * @return Builder for chaining.
1366          * @throws IllegalArgumentException when the SSID is empty, not unicode, or if the byte
1367          *                                  representation is longer than 32 bytes.
1368          *
1369          * @deprecated Use {@link #setWifiSsid(WifiSsid)} instead.
1370          */
1371         @NonNull
1372         @Deprecated
setSsid(@ullable String ssid)1373         public Builder setSsid(@Nullable String ssid) {
1374             if (ssid == null) {
1375                 mWifiSsid = null;
1376                 return this;
1377             }
1378 
1379             Preconditions.checkStringNotEmpty(ssid);
1380             Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
1381             mWifiSsid = WifiSsid.fromUtf8Text(ssid);
1382             return this;
1383         }
1384 
1385         /**
1386          * Specifies an SSID for the AP in the form of WifiSsid.
1387          * <p>
1388          * Null SSID only support when configure a local-only hotspot.
1389          * <p>
1390          * <li>If not set, defaults to null.</li>
1391          *
1392          * @param wifiSsid SSID, or null ot have the SSID automatically chosen by the framework.
1393          * @return Builder for chaining.
1394          */
1395         @NonNull
1396         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setWifiSsid(@ullable WifiSsid wifiSsid)1397         public Builder setWifiSsid(@Nullable WifiSsid wifiSsid) {
1398             if (!SdkLevel.isAtLeastT()) {
1399                 throw new UnsupportedOperationException();
1400             }
1401             mWifiSsid = wifiSsid;
1402             return this;
1403         }
1404 
1405         /**
1406          * Specify vendor-specific information elements for the (Soft) AP to transmit in its beacons
1407          * and probe responses. Method also validates the structure and throws
1408          * IllegalArgumentException in cases when ID of IE is not 0xDD (221) or incoming list
1409          * contain duplicate elements.
1410          *
1411          * @param vendorElements VendorElements
1412          * @return Builder for chaining.
1413          */
1414         @NonNull
1415         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setVendorElements( @onNull List<ScanResult.InformationElement> vendorElements)1416         public Builder setVendorElements(
1417                 @NonNull List<ScanResult.InformationElement> vendorElements) {
1418             if (!SdkLevel.isAtLeastT()) {
1419                 throw new UnsupportedOperationException();
1420             }
1421             for (ScanResult.InformationElement e : vendorElements) {
1422                 if (e.id != ScanResult.InformationElement.EID_VSA) {
1423                     throw new IllegalArgumentException("received InformationElement which is not "
1424                             + "related to VendorElements. VendorElement block should start with "
1425                             + HexEncoding.encodeToString(
1426                                     new byte[]{ (byte) ScanResult.InformationElement.EID_VSA }));
1427                 }
1428             }
1429             final HashSet<ScanResult.InformationElement> set = new HashSet<>(vendorElements);
1430             if (set.size() < vendorElements.size()) {
1431                 throw new IllegalArgumentException("vendor elements array contain duplicates. "
1432                         + "Please avoid passing duplicated and keep structure clean.");
1433             }
1434             mVendorElements = new ArrayList<>(vendorElements);
1435             return this;
1436         }
1437 
1438         /**
1439          * Specifies a BSSID for the AP.
1440          * <p>
1441          * <li>If not set, defaults to null.</li>
1442          *
1443          * When this method is called, the caller needs to configure MAC randomization settings to
1444          * {@link #RANDOMIZATION_NONE}. See {@link #setMacRandomizationSetting(int)} for details.
1445          *
1446          * If multiple bands are requested via {@link #setBands(int[])} or
1447          * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework
1448          * only sends down 1 MAC address.
1449          *
1450          * An example (but different implementation may perform a different mapping):
1451          * <li>MAC address 1: copy value of MAC address,
1452          * and set byte 1 = (0xFF - BSSID[1])</li>
1453          * <li>MAC address 2: copy value of MAC address,
1454          * and set byte 2 = (0xFF - BSSID[2])</li>
1455          *
1456          * Example BSSID argument: e2:38:60:c4:0e:b7
1457          * Derived MAC address 1: e2:c7:60:c4:0e:b7
1458          * Derived MAC address 2: e2:38:9f:c4:0e:b7
1459          *
1460          * <p>
1461          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1462          * {@link SoftApCapability#areFeaturesSupported(long)}
1463          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
1464          * whether or not this feature is supported.
1465          *
1466          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
1467          *              responsible for avoiding collisions.
1468          * @return Builder for chaining.
1469          * @throws IllegalArgumentException when the given BSSID is the all-zero
1470          *                                  , multicast or broadcast MAC address.
1471          */
1472         @NonNull
setBssid(@ullable MacAddress bssid)1473         public Builder setBssid(@Nullable MacAddress bssid) {
1474             if (bssid != null) {
1475                 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
1476                 if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) {
1477                     throw new IllegalArgumentException("bssid doesn't support "
1478                             + "multicast or broadcast mac address");
1479                 }
1480             }
1481             mBssid = bssid;
1482             return this;
1483         }
1484 
1485         /**
1486          * Specifies that this AP should use specific security type with the given ASCII passphrase.
1487          *
1488          * @param securityType One of the following security types:
1489          * {@link #SECURITY_TYPE_OPEN},
1490          * {@link #SECURITY_TYPE_WPA2_PSK},
1491          * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
1492          * {@link #SECURITY_TYPE_WPA3_SAE},
1493          * {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
1494          * {@link #SECURITY_TYPE_WPA3_OWE}.
1495          * @param passphrase The passphrase to use for sepcific {@code securityType} configuration
1496          * or null with {@link #SECURITY_TYPE_OPEN}, {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION},
1497          * and {@link #SECURITY_TYPE_WPA3_OWE}.
1498          *
1499          * @return Builder for chaining.
1500          * @throws IllegalArgumentException when the passphrase length is empty and
1501          *         {@code securityType} is any of the following:
1502          *         {@link #SECURITY_TYPE_WPA2_PSK} or {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION}
1503          *         or {@link #SECURITY_TYPE_WPA3_SAE},
1504          *         or non-null passphrase and {@code securityType} is
1505          *         {@link #SECURITY_TYPE_OPEN} or {@link #SECURITY_TYPE_WPA3_OWE_TRANSITION} or
1506          *         {@link #SECURITY_TYPE_WPA3_OWE}.
1507          */
1508         @NonNull
setPassphrase(@ullable String passphrase, @SecurityType int securityType)1509         public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
1510             if (!SdkLevel.isAtLeastT()
1511                     && (securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION
1512                             || securityType == SECURITY_TYPE_WPA3_OWE)) {
1513                 throw new UnsupportedOperationException();
1514             }
1515             if (securityType == SECURITY_TYPE_OPEN
1516                     || securityType == SECURITY_TYPE_WPA3_OWE_TRANSITION
1517                     || securityType == SECURITY_TYPE_WPA3_OWE) {
1518                 if (passphrase != null) {
1519                     throw new IllegalArgumentException(
1520                             "passphrase should be null when security type is open");
1521                 }
1522             } else {
1523                 Preconditions.checkStringNotEmpty(passphrase);
1524             }
1525             mSecurityType = securityType;
1526             mPassphrase = passphrase;
1527             return this;
1528         }
1529 
1530         /**
1531          * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
1532          * not (broadcasts its SSID).
1533          * <p>
1534          * <li>If not set, defaults to false (i.e not a hidden network).</li>
1535          *
1536          * @param hiddenSsid true for a hidden SSID, false otherwise.
1537          * @return Builder for chaining.
1538          */
1539         @NonNull
setHiddenSsid(boolean hiddenSsid)1540         public Builder setHiddenSsid(boolean hiddenSsid) {
1541             mHiddenSsid = hiddenSsid;
1542             return this;
1543         }
1544 
1545         /**
1546          * Specifies the band for the AP.
1547          * <p>
1548          * <li>If not set, defaults to {@link #BAND_2GHZ}.</li>
1549          *
1550          * @param band One or combination of the following band type:
1551          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1552          * @return Builder for chaining.
1553          * @throws IllegalArgumentException when an invalid band type is provided.
1554          */
1555         @NonNull
setBand(@andType int band)1556         public Builder setBand(@BandType int band) {
1557             if (!isBandValid(band)) {
1558                 throw new IllegalArgumentException("Invalid band type: " + band);
1559             }
1560             mChannels = new SparseIntArray(1);
1561             mChannels.put(band, 0);
1562             return this;
1563         }
1564 
1565         /**
1566          * Specifies the bands for the APs.
1567          * If more than 1 band is set, this will bring up concurrent APs.
1568          * on the requested bands (if possible).
1569          * <p>
1570          *
1571          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1572          * whether or not concurrent APs are supported.
1573          *
1574          * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1575          * when multiple bands are configured. Otherwise,
1576          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1577          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1578          *
1579          * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error
1580          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1581          *
1582          * @param bands Array of the {@link #BandType}.
1583          * @return Builder for chaining.
1584          * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
1585          *                                  is provided.
1586          */
1587         @RequiresApi(Build.VERSION_CODES.S)
1588         @NonNull
setBands(@onNull int[] bands)1589         public Builder setBands(@NonNull int[] bands) {
1590             if (!SdkLevel.isAtLeastS()) {
1591                 throw new UnsupportedOperationException();
1592             }
1593             if (bands.length == 0 || bands.length > 2) {
1594                 throw new IllegalArgumentException("Unsupported number of bands("
1595                         + bands.length + ") configured");
1596             }
1597             SparseIntArray channels = new SparseIntArray(bands.length);
1598             for (int val : bands) {
1599                 if (!isBandValid(val)) {
1600                     throw new IllegalArgumentException("Invalid band type: " + val);
1601                 }
1602                 channels.put(val, 0);
1603             }
1604             mChannels = channels;
1605             return this;
1606         }
1607 
1608 
1609         /**
1610          * Specifies the channel and associated band for the AP.
1611          *
1612          * The channel which AP resides on. Valid channels are country dependent.
1613          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
1614          * valid channels.
1615          *
1616          * <p>
1617          * If not set, the default for the channel is the special value 0 which has the
1618          * framework auto-select a valid channel from the band configured with
1619          * {@link #setBand(int)}.
1620          *
1621          * The channel auto selection will be offloaded to driver when
1622          * {@link SoftApCapability#areFeaturesSupported(long)}
1623          * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1624          * return true. The driver will auto select the best channel (e.g. best performance)
1625          * based on environment interference. Check {@link SoftApCapability} for more detail.
1626          *
1627          * The API contains (band, channel) input since the 6GHz band uses the same channel
1628          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1629          * uniquely identify individual channels.
1630          *
1631          * <p>
1632          * @param channel operating channel of the AP.
1633          * @param band containing this channel.
1634          * @return Builder for chaining.
1635          * @throws IllegalArgumentException when the invalid channel or band type is configured.
1636          */
1637         @NonNull
setChannel(int channel, @BandType int band)1638         public Builder setChannel(int channel, @BandType int band) {
1639             if (!isChannelBandPairValid(channel, band)) {
1640                 throw new IllegalArgumentException("Invalid channel(" + channel
1641                         + ") & band (" + band + ") configured");
1642             }
1643             mChannels = new SparseIntArray(1);
1644             mChannels.put(band, channel);
1645             return this;
1646         }
1647 
1648         /**
1649          * Specifies the channels and associated bands for the APs.
1650          *
1651          * When more than 1 channel is set, this will bring up concurrent APs on the requested
1652          * channels and bands (if possible).
1653          *
1654          * Valid channels are country dependent.
1655          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
1656          * valid channels in each band.
1657          *
1658          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1659          * whether or not concurrent APs are supported.
1660          *
1661          * <p>
1662          * If not set, the default for the channel is the special value 0 which has the framework
1663          * auto-select a valid channel from the band configured with {@link #setBands(int[])}.
1664          *
1665          * The channel auto selection will be offloaded to driver when
1666          * {@link SoftApCapability#areFeaturesSupported(long)}
1667          * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1668          * returns true. The driver will auto select the best channel (e.g. best performance)
1669          * based on environment interference. Check {@link SoftApCapability} for more detail.
1670          *
1671          * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1672          * when multiple bands are configured without specified channel value (i.e. channel is
1673          * the special value 0). Otherwise,
1674          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1675          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1676          *
1677          * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error
1678          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1679          *
1680          * The API contains (band, channel) input since the 6GHz band uses the same channel
1681          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1682          * uniquely identify individual channels.
1683          *
1684          * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
1685          * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
1686          *
1687          * <p>
1688          * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of
1689          *                 {@code BAND_} and corresponding channel.
1690          * @return Builder for chaining.
1691          * @throws IllegalArgumentException when more than 2 channels are set or the invalid
1692          *                                  channel or band type is configured.
1693          */
1694         @RequiresApi(Build.VERSION_CODES.S)
1695         @NonNull
setChannels(@onNull SparseIntArray channels)1696         public Builder setChannels(@NonNull SparseIntArray channels) {
1697             if (!SdkLevel.isAtLeastS()) {
1698                 throw new UnsupportedOperationException();
1699             }
1700             if (channels.size() == 0 || channels.size() > 2) {
1701                 throw new IllegalArgumentException("Unsupported number of channels("
1702                         + channels.size() + ") configured");
1703             }
1704             for (int i = 0; i < channels.size(); i++) {
1705                 int channel = channels.valueAt(i);
1706                 int band = channels.keyAt(i);
1707                 if (channel == 0) {
1708                     if (!isBandValid(band)) {
1709                         throw new IllegalArgumentException("Invalid band type: " + band);
1710                     }
1711                 } else {
1712                     if (!isChannelBandPairValid(channel, band)) {
1713                         throw new IllegalArgumentException("Invalid channel(" + channel
1714                                 + ") & band (" + band + ") configured");
1715                     }
1716                 }
1717             }
1718             mChannels = channels.clone();
1719             return this;
1720         }
1721 
1722 
1723         /**
1724          * Specifies the maximum number of clients that can associate to the AP.
1725          *
1726          * The maximum number of clients (STAs) which can associate to the AP.
1727          * The AP will reject association from any clients above this number.
1728          * Specify a value of 0 to have the framework automatically use the maximum number
1729          * which the device can support (based on hardware and carrier constraints).
1730          * <p>
1731          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1732          * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients
1733          * which the device supports (based on hardware and carrier constraints).
1734          *
1735          * <p>
1736          * <li>If not set, defaults to 0.</li>
1737          *
1738          * This method requires HAL support. If the method is used to set a
1739          * non-zero {@code maxNumberOfClients} value then
1740          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1741          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1742          *
1743          * <p>
1744          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1745          * {@link SoftApCapability#areFeaturesSupported(long)}
1746          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
1747          * or not this feature is supported.
1748          *
1749          * @param maxNumberOfClients maximum client number of the AP.
1750          * @return Builder for chaining.
1751          */
1752         @NonNull
setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)1753         public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) {
1754             if (maxNumberOfClients < 0) {
1755                 throw new IllegalArgumentException("maxNumberOfClients should be not negative");
1756             }
1757             mMaxNumberOfClients = maxNumberOfClients;
1758             return this;
1759         }
1760 
1761         /**
1762          * Specifies whether auto shutdown is enabled or not.
1763          * The Soft AP will shut down when there are no devices connected to it for
1764          * the timeout duration.
1765          *
1766          * <p>
1767          * <li>If not set, defaults to true</li>
1768          *
1769          * @param enable true to enable, false to disable.
1770          * @return Builder for chaining.
1771          *
1772          * @see #setShutdownTimeoutMillis(long)
1773          */
1774         @NonNull
setAutoShutdownEnabled(boolean enable)1775         public Builder setAutoShutdownEnabled(boolean enable) {
1776             mAutoShutdownEnabled = enable;
1777             return this;
1778         }
1779 
1780         /**
1781          * Specifies the shutdown timeout in milliseconds.
1782          * The Soft AP will shut down when there are no devices connected to it for
1783          * the timeout duration.
1784          *
1785          * Specify a value of {@link #DEFAULT_TIMEOUT} to have the framework automatically use
1786          * default timeout setting which defined in
1787          * {@link R.integer.config_wifi_framework_soft_ap_timeout_delay}
1788          *
1789          * <p>
1790          * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li>
1791          * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is
1792          * set to true</li>
1793          *
1794          * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid
1795          *                      except {@link #DEFAULT_TIMEOUT}.
1796          * @return Builder for chaining.
1797          *
1798          * @see #setAutoShutdownEnabled(boolean)
1799          */
1800         @NonNull
setShutdownTimeoutMillis(@ntRangefrom = -1) long timeoutMillis)1801         public Builder setShutdownTimeoutMillis(@IntRange(from = -1) long timeoutMillis) {
1802             if (Compatibility.isChangeEnabled(
1803                     REMOVE_ZERO_FOR_TIMEOUT_SETTING) && timeoutMillis < 1) {
1804                 if (timeoutMillis != DEFAULT_TIMEOUT) {
1805                     throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis);
1806                 }
1807             } else if (timeoutMillis < 0) {
1808                 throw new IllegalArgumentException("Invalid timeout value from legacy app: "
1809                         + timeoutMillis);
1810             }
1811             mShutdownTimeoutMillis = timeoutMillis;
1812             return this;
1813         }
1814 
1815         /**
1816          * Configure the Soft AP to require manual user control of client association.
1817          * If disabled (the default) then any client which isn't in the blocked list
1818          * {@link #getBlockedClientList()} can associate to this Soft AP using the
1819          * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier,
1820          * or user limited - using {@link #setMaxNumberOfClients(int)}).
1821          *
1822          * If manual user control is enabled then clients will be accepted, rejected, or require
1823          * a user approval based on the configuration provided by
1824          * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
1825          *
1826          * <p>
1827          * This method requires HAL support. HAL support can be determined using
1828          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1829          * {@link SoftApCapability#areFeaturesSupported(long)}
1830          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
1831          *
1832          * <p>
1833          * If the method is called on a device without HAL support then starting the soft AP
1834          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
1835          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1836          *
1837          * <p>
1838          * <li>If not set, defaults to false (i.e The authoriztion is not required).</li>
1839          *
1840          * @param enabled true for enabling the control by user, false otherwise.
1841          * @return Builder for chaining.
1842          */
1843         @NonNull
setClientControlByUserEnabled(boolean enabled)1844         public Builder setClientControlByUserEnabled(boolean enabled) {
1845             mClientControlByUser = enabled;
1846             return this;
1847         }
1848 
1849         /**
1850          * Configures the set of channel numbers in the specified band that are allowed
1851          * to be selected by the Automatic Channel Selection (ACS) algorithm.
1852          * <p>
1853          *
1854          * Requires the driver to support {@link SoftApCapability#SOFTAP_FEATURE_ACS_OFFLOAD}.
1855          * Otherwise, these sets will be ignored.
1856          * <p>
1857          *
1858          * @param band one of the following band types:
1859          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1860          *
1861          * @param channels that are allowed to be used by ACS algorithm in this band. If it is
1862          * configured to an empty array or not configured, then all channels within that band
1863          * will be allowed.
1864          * <p>
1865          *
1866          * @return Builder for chaining.
1867          */
1868         @NonNull
1869         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setAllowedAcsChannels(@andType int band, @NonNull int[] channels)1870         public Builder setAllowedAcsChannels(@BandType int band, @NonNull int[] channels) {
1871             if (!SdkLevel.isAtLeastT()) {
1872                 throw new UnsupportedOperationException();
1873             }
1874 
1875             if (channels == null) {
1876                 throw new IllegalArgumentException(
1877                         "Passing a null object to setAllowedAcsChannels");
1878             }
1879 
1880             if ((band != BAND_2GHZ) && (band != BAND_5GHZ) && (band != BAND_6GHZ)) {
1881                 throw new IllegalArgumentException(
1882                         "Passing an invalid band to setAllowedAcsChannels");
1883             }
1884 
1885             for (int channel : channels) {
1886                 if (!isChannelBandPairValid(channel, band)) {
1887                     throw new IllegalArgumentException(
1888                             "Invalid channel to setAllowedAcsChannels: band: " + band
1889                             + "channel: " + channel);
1890                 }
1891             }
1892 
1893             HashSet<Integer> set = IntStream.of(channels).boxed()
1894                     .collect(Collectors.toCollection(HashSet::new));
1895             switch(band) {
1896                 case BAND_2GHZ:
1897                     mAllowedAcsChannels2g = set;
1898                     break;
1899                 case BAND_5GHZ:
1900                     mAllowedAcsChannels5g = set;
1901                     break;
1902                 case BAND_6GHZ:
1903                     mAllowedAcsChannels6g = set;
1904                     break;
1905             }
1906 
1907             return this;
1908         }
1909 
1910         /**
1911          * Sets maximum channel bandwidth for the SoftAp Connection
1912          *
1913          * If not set, the SoftAp connection will seek the maximum channel bandwidth achievable on
1914          * the device. However, in some cases the caller will need to put a cap on the channel
1915          * bandwidth through this API.
1916          *
1917          * @param maxChannelBandwidth one of {@link SoftApInfo#CHANNEL_WIDTH_AUTO},
1918          * {@link SoftApInfo#CHANNEL_WIDTH_20MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_40MHZ},
1919          * {@link SoftApInfo#CHANNEL_WIDTH_80MHZ}, {@link SoftApInfo#CHANNEL_WIDTH_160MHZ},
1920          * or {@link SoftApInfo#CHANNEL_WIDTH_320MHZ}
1921          *
1922          * @return builder for chaining
1923          */
1924         @NonNull
1925         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setMaxChannelBandwidth(@ifiAnnotations.Bandwidth int maxChannelBandwidth)1926         public Builder setMaxChannelBandwidth(@WifiAnnotations.Bandwidth int maxChannelBandwidth) {
1927             if (!SdkLevel.isAtLeastT()) {
1928                 throw new UnsupportedOperationException();
1929             }
1930 
1931             switch (maxChannelBandwidth) {
1932                 case SoftApInfo.CHANNEL_WIDTH_AUTO:
1933                 case SoftApInfo.CHANNEL_WIDTH_20MHZ:
1934                 case SoftApInfo.CHANNEL_WIDTH_40MHZ:
1935                 case SoftApInfo.CHANNEL_WIDTH_80MHZ:
1936                 case SoftApInfo.CHANNEL_WIDTH_160MHZ:
1937                 case SoftApInfo.CHANNEL_WIDTH_320MHZ:
1938                     mMaxChannelBandwidth = maxChannelBandwidth;
1939                     break;
1940                 default:
1941                     throw new IllegalArgumentException(
1942                             "Invalid channel bandwidth value("
1943                             + maxChannelBandwidth + ")  configured");
1944             }
1945             return this;
1946         }
1947 
1948         /**
1949          * This method together with {@link setClientControlByUserEnabled(boolean)} control client
1950          * connections to the AP. If client control by user is disabled using the above method then
1951          * this API has no effect and clients are allowed to associate to the AP (within limit of
1952          * max number of clients).
1953          *
1954          * If client control by user is enabled then this API configures the list of clients
1955          * which are explicitly allowed. These are auto-accepted.
1956          *
1957          * All other clients which attempt to associate, whose MAC addresses are on neither list,
1958          * are:
1959          * <ul>
1960          * <li>Rejected</li>
1961          * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
1962          * is issued (which allows the user to add them to the allowed client list if desired).<li>
1963          * </ul>
1964          *
1965          * @param allowedClientList list of clients which are allowed to associate to the AP
1966          *                          without user pre-approval.
1967          * @return Builder for chaining.
1968          */
1969         @NonNull
setAllowedClientList(@onNull List<MacAddress> allowedClientList)1970         public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
1971             mAllowedClientList = new ArrayList<>(allowedClientList);
1972             return this;
1973         }
1974 
1975         /**
1976          * This API configures the list of clients which are blocked and cannot associate
1977          * to the Soft AP.
1978          *
1979          * <p>
1980          * This method requires HAL support. HAL support can be determined using
1981          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1982          * {@link SoftApCapability#areFeaturesSupported(long)}
1983          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
1984          *
1985          * <p>
1986          * If the method is called on a device without HAL support then starting the soft AP
1987          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
1988          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1989          *
1990          * @param blockedClientList list of clients which are not allowed to associate to the AP.
1991          * @return Builder for chaining.
1992          */
1993         @NonNull
setBlockedClientList(@onNull List<MacAddress> blockedClientList)1994         public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
1995             mBlockedClientList = new ArrayList<>(blockedClientList);
1996             return this;
1997         }
1998 
1999         /**
2000          * Specifies the level of MAC randomization for the AP BSSID.
2001          * The Soft AP BSSID will be randomized only if the BSSID isn't set
2002          * {@link #setBssid(MacAddress)} and this method is either uncalled
2003          * or called with {@link #RANDOMIZATION_PERSISTENT} or
2004          * {@link #RANDOMIZATION_NON_PERSISTENT}. When this method is called with
2005          * {@link #RANDOMIZATION_PERSISTENT} or {@link #RANDOMIZATION_NON_PERSISTENT}, the caller
2006          * the caller must not call {@link #setBssid(MacAddress)}.
2007          *
2008          * <p>
2009          * <li>If not set, defaults to {@link #RANDOMIZATION_NON_PERSISTENT}</li>
2010          *
2011          * <p>
2012          * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT} or
2013          * {@link #RANDOMIZATION_NON_PERSISTENT}.
2014          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2015          * {@link SoftApCapability#areFeaturesSupported(long)}
2016          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
2017          * whether or not this feature is supported.
2018          *
2019          * @param macRandomizationSetting One of the following setting:
2020          * {@link #RANDOMIZATION_NONE}, {@link #RANDOMIZATION_PERSISTENT} or
2021          * {@link #RANDOMIZATION_NON_PERSISTENT}.
2022          * @return Builder for chaining.
2023          *
2024          * @see #setBssid(MacAddress)
2025          */
2026         @RequiresApi(Build.VERSION_CODES.S)
2027         @NonNull
setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)2028         public Builder setMacRandomizationSetting(
2029                 @MacRandomizationSetting int macRandomizationSetting) {
2030             if (!SdkLevel.isAtLeastS()) {
2031                 throw new UnsupportedOperationException();
2032             }
2033             mMacRandomizationSetting = macRandomizationSetting;
2034             return this;
2035         }
2036 
2037 
2038         /**
2039          * Specifies whether or not opportunistic shut down of an AP instance in bridged mode
2040          * is enabled.
2041          *
2042          * <p>
2043          * If enabled, the framework will shutdown one of the AP instances if it is idle for
2044          * the timeout duration - meaning there are no devices connected to it.
2045          * If both AP instances are idle for the timeout duration then the framework will
2046          * shut down the AP instance operating on the higher frequency. For instance,
2047          * if the AP instances operate at 2.4GHz and 5GHz and are both idle for the
2048          * timeout duration then the 5GHz AP instance will be shut down.
2049          * <p>
2050          *
2051          * Note: the opportunistic timeout only applies to one AP instance of the bridge AP.
2052          * If one of the AP instances has already been disabled for any reason, including due to
2053          * an opportunistic timeout or hardware issues or coexistence issues,
2054          * then the opportunistic timeout is no longer active.
2055          *
2056          * <p>
2057          * The shutdown timer specified by {@link #setShutdownTimeoutMillis(long)} controls the
2058          * overall shutdown of the bridged AP and is still in use independently of the opportunistic
2059          * timer controlled by this AP.
2060          *
2061          * <p>
2062          * <li>If not set, defaults to true</li>
2063          *
2064          * @param enable true to enable, false to disable.
2065          * @return Builder for chaining.
2066          *
2067          */
2068         @RequiresApi(Build.VERSION_CODES.S)
2069         @NonNull
setBridgedModeOpportunisticShutdownEnabled(boolean enable)2070         public Builder setBridgedModeOpportunisticShutdownEnabled(boolean enable) {
2071             if (!SdkLevel.isAtLeastS()) {
2072                 throw new UnsupportedOperationException();
2073             }
2074             mBridgedModeOpportunisticShutdownEnabled = enable;
2075             return this;
2076         }
2077 
2078         /**
2079          * Specifies whether or not to enable 802.11ax on the Soft AP.
2080          *
2081          * <p>
2082          * Note: Only relevant when the device supports 802.11ax on the Soft AP.
2083          * If enabled on devices that do not support 802.11ax then ignored.
2084          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2085          * {@link SoftApCapability#areFeaturesSupported(long)}
2086          * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX} to determine
2087          * whether or not 802.11ax is supported on the Soft AP.
2088          * <p>
2089          * <li>If not set, defaults to true - which will be ignored on devices
2090          * which do not support 802.11ax</li>
2091          *
2092          * @param enable true to enable, false to disable.
2093          * @return Builder for chaining.
2094          *
2095          */
2096         @RequiresApi(Build.VERSION_CODES.S)
2097         @NonNull
setIeee80211axEnabled(boolean enable)2098         public Builder setIeee80211axEnabled(boolean enable) {
2099             if (!SdkLevel.isAtLeastS()) {
2100                 throw new UnsupportedOperationException();
2101             }
2102             mIeee80211axEnabled = enable;
2103             return this;
2104         }
2105 
2106         /**
2107          * Specifies whether or not to enable 802.11be on the Soft AP.
2108          *
2109          * <p>
2110          * Note: Only relevant when the device supports 802.11be on the Soft AP.
2111          * If enabled on devices that do not support 802.11be then ignored.
2112          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
2113          * {@link SoftApCapability#areFeaturesSupported(long)}
2114          * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_BE} to determine
2115          * whether or not 802.11be is supported on the Soft AP.
2116          * <p>
2117          * <li>If not set, defaults to true - which will be ignored on devices
2118          * which do not support 802.11be</li>
2119          *
2120          * @param enable true to enable, false to disable.
2121          * @return Builder for chaining.
2122          *
2123          */
2124         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2125         @NonNull
setIeee80211beEnabled(boolean enable)2126         public Builder setIeee80211beEnabled(boolean enable) {
2127             if (!SdkLevel.isAtLeastT()) {
2128                 throw new UnsupportedOperationException();
2129             }
2130             mIeee80211beEnabled = enable;
2131             return this;
2132         }
2133 
2134         /**
2135          * Specifies whether or not the configuration is configured by user.
2136          *
2137          * @param isUserConfigured true to user configuration, false otherwise.
2138          * @return Builder for chaining.
2139          *
2140          * @hide
2141          */
2142         @NonNull
setUserConfiguration(boolean isUserConfigured)2143         public Builder setUserConfiguration(boolean isUserConfigured) {
2144             mIsUserConfiguration = isUserConfigured;
2145             return this;
2146         }
2147 
2148         /**
2149          * Specifies bridged mode opportunistic shutdown timeout in milliseconds.
2150          * An instance of bridged Soft AP will shut down when there is no device connected to it
2151          * for this timeout duration.
2152          *
2153          * Specify a value of {@link DEFAULT_TIMEOUT} to have the framework automatically use
2154          * default timeout setting defined by
2155          * {@link
2156          * R.integer.config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond}
2157          *
2158          * <p>
2159          * <li>If not set, defaults to {@link #DEFAULT_TIMEOUT}</li>
2160          * <li>The shut down timeout will apply when
2161          * {@link #setBridgedModeOpportunisticShutdownEnabled(boolean)} is set to true</li>
2162          *
2163          * @param timeoutMillis milliseconds of the timeout delay. Any value less than 1 is invalid
2164          *                      except {@link #DEFAULT_TIMEOUT}.
2165          * @return Builder for chaining.
2166          *
2167          * @see #setBridgedModeOpportunisticShutdownEnabled(boolean)
2168          */
2169         @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2170         @NonNull
setBridgedModeOpportunisticShutdownTimeoutMillis( @ntRangefrom = -1) long timeoutMillis)2171         public Builder setBridgedModeOpportunisticShutdownTimeoutMillis(
2172                 @IntRange(from = -1) long timeoutMillis) {
2173             if (!SdkLevel.isAtLeastT()) {
2174                 throw new UnsupportedOperationException();
2175             }
2176             if (timeoutMillis < 1 && timeoutMillis != DEFAULT_TIMEOUT) {
2177                 throw new IllegalArgumentException("Invalid timeout value: " + timeoutMillis);
2178             }
2179             mBridgedModeOpportunisticShutdownTimeoutMillis = timeoutMillis;
2180             return this;
2181         }
2182 
2183         /**
2184          * @param mac persistent randomized MacAddress generated by the frameworks.
2185          * @hide
2186          */
2187         @NonNull
setRandomizedMacAddress(@onNull MacAddress mac)2188         public Builder setRandomizedMacAddress(@NonNull MacAddress mac) {
2189             if (mac == null) {
2190                 throw new IllegalArgumentException("setRandomizedMacAddress received"
2191                         + " null MacAddress.");
2192             }
2193             mPersistentRandomizedMacAddress = mac;
2194             return this;
2195         }
2196     }
2197 }
2198