• 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.net.MacAddress;
25 import android.os.Build;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.text.TextUtils;
29 import android.util.Log;
30 import android.util.SparseIntArray;
31 
32 import androidx.annotation.RequiresApi;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.internal.util.Preconditions;
36 import com.android.modules.utils.build.SdkLevel;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.nio.charset.StandardCharsets;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Objects;
44 
45 /**
46  * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
47  *
48  * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
49  * framework how it should configure a hotspot.
50  *
51  * System apps can use this to configure a tethered hotspot using
52  * {@code WifiManager#startTetheredHotspot(SoftApConfiguration)} and
53  * {@code WifiManager#setSoftApConfiguration(SoftApConfiguration)}
54  * or local-only hotspot using
55  * {@code WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
56  * WifiManager.LocalOnlyHotspotCallback)}.
57  *
58  * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to
59  * create a new instance.
60  *
61  */
62 public final class SoftApConfiguration implements Parcelable {
63 
64     private static final String TAG = "SoftApConfiguration";
65 
66     @VisibleForTesting
67     static final int PSK_MIN_LEN = 8;
68 
69     @VisibleForTesting
70     static final int PSK_MAX_LEN = 63;
71 
72     /**
73      * 2GHz band.
74      * @hide
75      */
76     @SystemApi
77     public static final int BAND_2GHZ = 1 << 0;
78 
79     /**
80      * 5GHz band.
81      * @hide
82      */
83     @SystemApi
84     public static final int BAND_5GHZ = 1 << 1;
85 
86     /**
87      * 6GHz band.
88      * @hide
89      */
90     @SystemApi
91     public static final int BAND_6GHZ = 1 << 2;
92 
93     /**
94      * 60GHz band.
95      * @hide
96      */
97     @SystemApi
98     public static final int BAND_60GHZ = 1 << 3;
99 
100     /**
101      * Device is allowed to choose the optimal band (2GHz, 5GHz, 6GHz) based on device capability,
102      * operating country code and current radio conditions.
103      * @hide
104      *
105      * @deprecated This is no longer supported. The value is fixed at
106      * (BAND_2GHZ | BAND_5GHZ | BAND_6GHZ) even if a new band is supported in the future, for
107      * instance {@code BAND_60GHZ}. The bands are a bit mask - use any combination of
108      * {@code BAND_}, for instance {@code BAND_2GHZ | BAND_5GHZ}.
109      */
110     @SystemApi
111     public static final int BAND_ANY = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ;
112 
113     /** @hide */
114     @Retention(RetentionPolicy.SOURCE)
115     @IntDef(flag = true, prefix = { "BAND_TYPE_" }, value = {
116             BAND_2GHZ,
117             BAND_5GHZ,
118             BAND_6GHZ,
119             BAND_60GHZ,
120     })
121     public @interface BandType {}
122 
123     /**
124      * All of the supported band types.
125      * @hide
126      */
127     public static int[] BAND_TYPES = {BAND_2GHZ, BAND_5GHZ, BAND_6GHZ, BAND_60GHZ};
128 
isBandValid(@andType int band)129     private static boolean isBandValid(@BandType int band) {
130         int bandAny = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ | BAND_60GHZ;
131         return ((band != 0) && ((band & ~bandAny) == 0));
132     }
133 
134     private static final int MIN_CH_2G_BAND = 1;
135     private static final int MAX_CH_2G_BAND = 14;
136     private static final int MIN_CH_5G_BAND = 34;
137     private static final int MAX_CH_5G_BAND = 196;
138     private static final int MIN_CH_6G_BAND = 1;
139     private static final int MAX_CH_6G_BAND = 253;
140     private static final int MIN_CH_60G_BAND = 1;
141     private static final int MAX_CH_60G_BAND = 6;
142 
143 
144 
isChannelBandPairValid(int channel, @BandType int band)145     private static boolean isChannelBandPairValid(int channel, @BandType int band) {
146         switch (band) {
147             case BAND_2GHZ:
148                 if (channel < MIN_CH_2G_BAND || channel >  MAX_CH_2G_BAND) {
149                     return false;
150                 }
151                 break;
152 
153             case BAND_5GHZ:
154                 if (channel < MIN_CH_5G_BAND || channel >  MAX_CH_5G_BAND) {
155                     return false;
156                 }
157                 break;
158 
159             case BAND_6GHZ:
160                 if (channel < MIN_CH_6G_BAND || channel >  MAX_CH_6G_BAND) {
161                     return false;
162                 }
163                 break;
164 
165             case BAND_60GHZ:
166                 if (channel < MIN_CH_60G_BAND || channel >  MAX_CH_60G_BAND) {
167                     return false;
168                 }
169                 break;
170 
171             default:
172                 return false;
173         }
174         return true;
175     }
176 
177     /**
178      * SSID for the AP, or null for a framework-determined SSID.
179      */
180     private final @Nullable String mSsid;
181 
182     /**
183      * BSSID for the AP, or null to use a framework-determined BSSID.
184      */
185     private final @Nullable MacAddress mBssid;
186 
187     /**
188      * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
189      * the security type.
190      */
191     private final @Nullable String mPassphrase;
192 
193     /**
194      * This is a network that does not broadcast its SSID, so an
195      * SSID-specific probe request must be used for scans.
196      */
197     private final boolean mHiddenSsid;
198 
199     /**
200      * The operating channels of the dual APs.
201      *
202      * The SparseIntArray that consists the band and the channel of matching the band.
203      */
204     @NonNull
205     private final SparseIntArray mChannels;
206 
207     /**
208      * The maximim allowed number of clients that can associate to the AP.
209      */
210     private final int mMaxNumberOfClients;
211 
212     /**
213      * The operating security type of the AP.
214      * One of the following security types:
215      * {@link #SECURITY_TYPE_OPEN},
216      * {@link #SECURITY_TYPE_WPA2_PSK},
217      * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
218      * {@link #SECURITY_TYPE_WPA3_SAE}
219      */
220     private final @SecurityType int mSecurityType;
221 
222     /**
223      * The flag to indicate client need to authorize by user
224      * when client is connecting to AP.
225      */
226     private final boolean mClientControlByUser;
227 
228     /**
229      * The list of blocked client that can't associate to the AP.
230      */
231     private final List<MacAddress> mBlockedClientList;
232 
233     /**
234      * The list of allowed client that can associate to the AP.
235      */
236     private final List<MacAddress> mAllowedClientList;
237 
238     /**
239      * Whether auto shutdown of soft AP is enabled or not.
240      */
241     private final boolean mAutoShutdownEnabled;
242 
243     /**
244      * Delay in milliseconds before shutting down soft AP when
245      * there are no connected devices.
246      */
247     private final long mShutdownTimeoutMillis;
248 
249     /** @hide */
250     @Retention(RetentionPolicy.SOURCE)
251     @IntDef(prefix = {"RANDOMIZATION_"}, value = {
252             RANDOMIZATION_NONE,
253             RANDOMIZATION_PERSISTENT})
254     public @interface MacRandomizationSetting {}
255 
256     /**
257      * Use factory MAC as BSSID for the AP
258      * @hide
259      */
260     @SystemApi
261     public static final int RANDOMIZATION_NONE = 0;
262     /**
263      * Generate a randomized MAC as BSSID for the AP
264      * @hide
265      */
266     @SystemApi
267     public static final int RANDOMIZATION_PERSISTENT = 1;
268 
269     /**
270      * Level of MAC randomization for the AP BSSID.
271      */
272     @MacRandomizationSetting
273     private int mMacRandomizationSetting;
274 
275 
276     /**
277      * Whether opportunistic shutdown of an instance in bridged AP is enabled or not.
278      */
279     private boolean mBridgedModeOpportunisticShutdownEnabled;
280 
281     /**
282      * Whether 802.11ax AP is enabled or not.
283      */
284     private boolean mIeee80211axEnabled;
285 
286     /**
287      * Whether the current configuration is configured by user or not.
288      */
289     private boolean mIsUserConfiguration;
290 
291 
292     /**
293      * THe definition of security type OPEN.
294      */
295     public static final int SECURITY_TYPE_OPEN = 0;
296 
297     /**
298      * The definition of security type WPA2-PSK.
299      */
300     public static final int SECURITY_TYPE_WPA2_PSK = 1;
301 
302     /**
303      * The definition of security type WPA3-SAE Transition mode.
304      */
305     public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;
306 
307     /**
308      * The definition of security type WPA3-SAE.
309      */
310     public static final int SECURITY_TYPE_WPA3_SAE = 3;
311 
312     /** @hide */
313     @Retention(RetentionPolicy.SOURCE)
314     @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
315         SECURITY_TYPE_OPEN,
316         SECURITY_TYPE_WPA2_PSK,
317         SECURITY_TYPE_WPA3_SAE_TRANSITION,
318         SECURITY_TYPE_WPA3_SAE,
319     })
320     public @interface SecurityType {}
321 
322     /** Private constructor for Builder and Parcelable implementation. */
SoftApConfiguration(@ullable String 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 isUserConfiguration)323     private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
324             @Nullable String passphrase, boolean hiddenSsid, @NonNull SparseIntArray channels,
325             @SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
326             long shutdownTimeoutMillis, boolean clientControlByUser,
327             @NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList,
328             int macRandomizationSetting, boolean bridgedModeOpportunisticShutdownEnabled,
329             boolean ieee80211axEnabled, boolean isUserConfiguration) {
330         mSsid = ssid;
331         mBssid = bssid;
332         mPassphrase = passphrase;
333         mHiddenSsid = hiddenSsid;
334         if (channels.size() != 0) {
335             mChannels = channels.clone();
336         } else {
337             mChannels = new SparseIntArray(1);
338             mChannels.put(BAND_2GHZ, 0);
339         }
340         mSecurityType = securityType;
341         mMaxNumberOfClients = maxNumberOfClients;
342         mAutoShutdownEnabled = shutdownTimeoutEnabled;
343         mShutdownTimeoutMillis = shutdownTimeoutMillis;
344         mClientControlByUser = clientControlByUser;
345         mBlockedClientList = new ArrayList<>(blockedList);
346         mAllowedClientList = new ArrayList<>(allowedList);
347         mMacRandomizationSetting = macRandomizationSetting;
348         mBridgedModeOpportunisticShutdownEnabled = bridgedModeOpportunisticShutdownEnabled;
349         mIeee80211axEnabled = ieee80211axEnabled;
350         mIsUserConfiguration = isUserConfiguration;
351     }
352 
353     @Override
equals(Object otherObj)354     public boolean equals(Object otherObj) {
355         if (this == otherObj) {
356             return true;
357         }
358         if (!(otherObj instanceof SoftApConfiguration)) {
359             return false;
360         }
361         SoftApConfiguration other = (SoftApConfiguration) otherObj;
362         return Objects.equals(mSsid, other.mSsid)
363                 && Objects.equals(mBssid, other.mBssid)
364                 && Objects.equals(mPassphrase, other.mPassphrase)
365                 && mHiddenSsid == other.mHiddenSsid
366                 && mChannels.toString().equals(other.mChannels.toString())
367                 && mSecurityType == other.mSecurityType
368                 && mMaxNumberOfClients == other.mMaxNumberOfClients
369                 && mAutoShutdownEnabled == other.mAutoShutdownEnabled
370                 && mShutdownTimeoutMillis == other.mShutdownTimeoutMillis
371                 && mClientControlByUser == other.mClientControlByUser
372                 && Objects.equals(mBlockedClientList, other.mBlockedClientList)
373                 && Objects.equals(mAllowedClientList, other.mAllowedClientList)
374                 && mMacRandomizationSetting == other.mMacRandomizationSetting
375                 && mBridgedModeOpportunisticShutdownEnabled
376                 == other.mBridgedModeOpportunisticShutdownEnabled
377                 && mIeee80211axEnabled == other.mIeee80211axEnabled
378                 && mIsUserConfiguration == other.mIsUserConfiguration;
379     }
380 
381     @Override
hashCode()382     public int hashCode() {
383         return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
384                 mChannels.toString(), mSecurityType, mMaxNumberOfClients, mAutoShutdownEnabled,
385                 mShutdownTimeoutMillis, mClientControlByUser, mBlockedClientList,
386                 mAllowedClientList, mMacRandomizationSetting,
387                 mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled,
388                 mIsUserConfiguration);
389     }
390 
391     @Override
toString()392     public String toString() {
393         StringBuilder sbuf = new StringBuilder();
394         sbuf.append("ssid = ").append(mSsid);
395         if (mBssid != null) sbuf.append(" \n bssid = ").append(mBssid.toString());
396         sbuf.append(" \n Passphrase = ").append(
397                 TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
398         sbuf.append(" \n HiddenSsid = ").append(mHiddenSsid);
399         sbuf.append(" \n Channels = ").append(mChannels);
400         sbuf.append(" \n SecurityType = ").append(getSecurityType());
401         sbuf.append(" \n MaxClient = ").append(mMaxNumberOfClients);
402         sbuf.append(" \n AutoShutdownEnabled = ").append(mAutoShutdownEnabled);
403         sbuf.append(" \n ShutdownTimeoutMillis = ").append(mShutdownTimeoutMillis);
404         sbuf.append(" \n ClientControlByUser = ").append(mClientControlByUser);
405         sbuf.append(" \n BlockedClientList = ").append(mBlockedClientList);
406         sbuf.append(" \n AllowedClientList= ").append(mAllowedClientList);
407         sbuf.append(" \n MacRandomizationSetting = ").append(mMacRandomizationSetting);
408         sbuf.append(" \n BridgedModeInstanceOpportunisticEnabled = ")
409                 .append(mBridgedModeOpportunisticShutdownEnabled);
410         sbuf.append(" \n Ieee80211axEnabled = ").append(mIeee80211axEnabled);
411         sbuf.append(" \n isUserConfiguration = ").append(mIsUserConfiguration);
412         return sbuf.toString();
413     }
414 
415     @Override
writeToParcel(@onNull Parcel dest, int flags)416     public void writeToParcel(@NonNull Parcel dest, int flags) {
417         dest.writeString(mSsid);
418         dest.writeParcelable(mBssid, flags);
419         dest.writeString(mPassphrase);
420         dest.writeBoolean(mHiddenSsid);
421         writeSparseIntArray(dest, mChannels);
422         dest.writeInt(mSecurityType);
423         dest.writeInt(mMaxNumberOfClients);
424         dest.writeBoolean(mAutoShutdownEnabled);
425         dest.writeLong(mShutdownTimeoutMillis);
426         dest.writeBoolean(mClientControlByUser);
427         dest.writeTypedList(mBlockedClientList);
428         dest.writeTypedList(mAllowedClientList);
429         dest.writeInt(mMacRandomizationSetting);
430         dest.writeBoolean(mBridgedModeOpportunisticShutdownEnabled);
431         dest.writeBoolean(mIeee80211axEnabled);
432         dest.writeBoolean(mIsUserConfiguration);
433     }
434 
435     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
writeSparseIntArray(@onNull Parcel dest, @Nullable SparseIntArray val)436     private static void writeSparseIntArray(@NonNull Parcel dest,
437             @Nullable SparseIntArray val) {
438         if (val == null) {
439             dest.writeInt(-1);
440             return;
441         }
442         int n = val.size();
443         dest.writeInt(n);
444         int i = 0;
445         while (i < n) {
446             dest.writeInt(val.keyAt(i));
447             dest.writeInt(val.valueAt(i));
448             i++;
449         }
450     }
451 
452 
453     /* Reference from frameworks/base/core/java/android/os/Parcel.java */
454     @NonNull
readSparseIntArray(@onNull Parcel in)455     private static SparseIntArray readSparseIntArray(@NonNull Parcel in) {
456         int n = in.readInt();
457         if (n < 0) {
458             return new SparseIntArray();
459         }
460         SparseIntArray sa = new SparseIntArray(n);
461         while (n > 0) {
462             int key = in.readInt();
463             int value = in.readInt();
464             sa.append(key, value);
465             n--;
466         }
467         return sa;
468     }
469 
470 
471     @Override
describeContents()472     public int describeContents() {
473         return 0;
474     }
475 
476     @NonNull
477     public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() {
478         @Override
479         public SoftApConfiguration createFromParcel(Parcel in) {
480             return new SoftApConfiguration(
481                     in.readString(),
482                     in.readParcelable(MacAddress.class.getClassLoader()),
483                     in.readString(), in.readBoolean(), readSparseIntArray(in), in.readInt(),
484                     in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
485                     in.createTypedArrayList(MacAddress.CREATOR),
486                     in.createTypedArrayList(MacAddress.CREATOR), in.readInt(), in.readBoolean(),
487                     in.readBoolean(), in.readBoolean());
488         }
489 
490         @Override
491         public SoftApConfiguration[] newArray(int size) {
492             return new SoftApConfiguration[size];
493         }
494     };
495 
496     /**
497      * Return String set to be the SSID for the AP.
498      * See also {@link Builder#setSsid(String)}.
499      */
500     @Nullable
getSsid()501     public String getSsid() {
502         return mSsid;
503     }
504 
505     /**
506      * Returns MAC address set to be BSSID for the AP.
507      * See also {@link Builder#setBssid(MacAddress)}.
508      */
509     @Nullable
getBssid()510     public MacAddress getBssid() {
511         return mBssid;
512     }
513 
514     /**
515      * Returns String set to be passphrase for current AP.
516      * See also {@link Builder#setPassphrase(String, int)}.
517      */
518     @Nullable
getPassphrase()519     public String getPassphrase() {
520         return mPassphrase;
521     }
522 
523     /**
524      * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
525      * not (false: broadcasts its SSID) for the AP.
526      * See also {@link Builder#setHiddenSsid(boolean)}.
527      */
isHiddenSsid()528     public boolean isHiddenSsid() {
529         return mHiddenSsid;
530     }
531 
532     /**
533      * Returns band type set to be the band for the AP.
534      *
535      * One or combination of {@code BAND_}, for instance
536      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
537      *
538      * Note: Returns the lowest band when more than one band is set.
539      * Use {@link #getChannels()} to get dual bands setting.
540      *
541      * See also {@link Builder#setBand(int)}.
542      *
543      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
544      * @hide
545      */
546     @Deprecated
547     @SystemApi
getBand()548     public @BandType int getBand() {
549         return mChannels.keyAt(0);
550     }
551 
552     /**
553      * Returns a sorted array in ascending order that consists of the configured band types
554      * for the APs.
555      *
556      * The band type is one or combination of {@code BAND_}, for instance
557      * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, or {@code BAND_2GHZ | BAND_5GHZ}.
558      *
559      * Note: return array may only include one band when current setting is single AP mode.
560      * See also {@link Builder#setBands(int[])}.
561      *
562      * @hide
563      */
getBands()564     public @NonNull int[] getBands() {
565         int[] bands = new int[mChannels.size()];
566         for (int i = 0; i < bands.length; i++) {
567             bands[i] = mChannels.keyAt(i);
568         }
569         return bands;
570     }
571 
572     /**
573      * Returns Integer set to be the channel for the AP.
574      *
575      * Note: Returns the channel which associated to the lowest band if more than one channel
576      * is set. Use {@link Builder#getChannels()} to get dual channel setting.
577      * See also {@link Builder#setChannel(int, int)}.
578      *
579      * @deprecated This API is deprecated. Use {@link #getChannels()} instead.
580      * @hide
581      */
582     @Deprecated
583     @SystemApi
getChannel()584     public int getChannel() {
585         return mChannels.valueAt(0);
586     }
587 
588 
589     /**
590      * Returns SparseIntArray (key: {@code BandType} , value: channel) that consists of
591      * the configured bands and channels for the AP(s).
592      *
593      * The returned channel value is Wi-Fi channel numbering.
594      * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
595      * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
596      *
597      * Note: return array may only include one channel when current setting is single AP mode.
598      * See also {@link Builder#setChannels(SparseIntArray)}.
599      *
600      * @hide
601      */
602     @RequiresApi(Build.VERSION_CODES.S)
603     @SystemApi
getChannels()604     public @NonNull SparseIntArray getChannels() {
605         if (!SdkLevel.isAtLeastS()) {
606             throw new UnsupportedOperationException();
607         }
608         return mChannels.clone();
609     }
610 
611     /**
612      * Get security type params which depends on which security passphrase to set.
613      *
614      * @return One of:
615      * {@link #SECURITY_TYPE_OPEN},
616      * {@link #SECURITY_TYPE_WPA2_PSK},
617      * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
618      * {@link #SECURITY_TYPE_WPA3_SAE}
619      */
getSecurityType()620     public @SecurityType int getSecurityType() {
621         return mSecurityType;
622     }
623 
624     /**
625      * Returns the maximum number of clients that can associate to the AP.
626      * See also {@link Builder#setMaxNumberOfClients(int)}.
627      *
628      * @hide
629      */
630     @SystemApi
getMaxNumberOfClients()631     public int getMaxNumberOfClients() {
632         return mMaxNumberOfClients;
633     }
634 
635     /**
636      * Returns whether auto shutdown is enabled or not.
637      * The Soft AP will shutdown when there are no devices associated to it for
638      * the timeout duration. See also {@link Builder#setAutoShutdownEnabled(boolean)}.
639      *
640      * @hide
641      */
642     @SystemApi
isAutoShutdownEnabled()643     public boolean isAutoShutdownEnabled() {
644         return mAutoShutdownEnabled;
645     }
646 
647     /**
648      * Returns the shutdown timeout in milliseconds.
649      * The Soft AP will shutdown when there are no devices associated to it for
650      * the timeout duration. See also {@link Builder#setShutdownTimeoutMillis(long)}.
651      *
652      * @hide
653      */
654     @SystemApi
getShutdownTimeoutMillis()655     public long getShutdownTimeoutMillis() {
656         return mShutdownTimeoutMillis;
657     }
658 
659     /**
660      * Returns a flag indicating whether clients need to be pre-approved by the user.
661      * (true: authorization required) or not (false: not required).
662      * See also {@link Builder#setClientControlByUserEnabled(Boolean)}.
663      *
664      * @hide
665      */
666     @SystemApi
isClientControlByUserEnabled()667     public boolean isClientControlByUserEnabled() {
668         return mClientControlByUser;
669     }
670 
671     /**
672      * Returns List of clients which aren't allowed to associate to the AP.
673      *
674      * Clients are configured using {@link Builder#setBlockedClientList(List)}
675      *
676      * @hide
677      */
678     @NonNull
679     @SystemApi
getBlockedClientList()680     public List<MacAddress> getBlockedClientList() {
681         return mBlockedClientList;
682     }
683 
684     /**
685      * List of clients which are allowed to associate to the AP.
686      * Clients are configured using {@link Builder#setAllowedClientList(List)}
687      *
688      * @hide
689      */
690     @NonNull
691     @SystemApi
getAllowedClientList()692     public List<MacAddress> getAllowedClientList() {
693         return mAllowedClientList;
694     }
695 
696     /**
697      * Returns the level of MAC randomization for the AP BSSID.
698      * See also {@link Builder#setMacRandomizationSetting(int)}.
699      *
700      * @hide
701      */
702     @RequiresApi(Build.VERSION_CODES.S)
703     @SystemApi
704     @MacRandomizationSetting
getMacRandomizationSetting()705     public int getMacRandomizationSetting() {
706         if (!SdkLevel.isAtLeastS()) {
707             throw new UnsupportedOperationException();
708         }
709         return getMacRandomizationSettingInternal();
710     }
711 
712     /**
713      * @hide
714      */
715     @MacRandomizationSetting
getMacRandomizationSettingInternal()716     public int getMacRandomizationSettingInternal() {
717         return mMacRandomizationSetting;
718     }
719 
720     /**
721      * Returns whether opportunistic shutdown of an instance in bridged AP is enabled or not.
722      *
723      * See also {@link Builder#setBridgedModeOpportunisticShutdownEnabled(boolean}}
724      * @hide
725      */
726     @RequiresApi(Build.VERSION_CODES.S)
727     @SystemApi
isBridgedModeOpportunisticShutdownEnabled()728     public boolean isBridgedModeOpportunisticShutdownEnabled() {
729         if (!SdkLevel.isAtLeastS()) {
730             throw new UnsupportedOperationException();
731         }
732         return isBridgedModeOpportunisticShutdownEnabledInternal();
733     }
734 
735     /**
736      * @see #isBridgedModeOpportunisticShutdownEnabled()
737      * @hide
738      */
isBridgedModeOpportunisticShutdownEnabledInternal()739     public boolean isBridgedModeOpportunisticShutdownEnabledInternal() {
740         return mBridgedModeOpportunisticShutdownEnabled;
741     }
742 
743     /**
744      * @see #isIeee80211axEnabled()
745      * @hide
746      */
isIeee80211axEnabledInternal()747     public boolean isIeee80211axEnabledInternal() {
748         return mIeee80211axEnabled;
749     }
750 
751     /**
752      * Returns whether or not 802.11ax is enabled on the SoftAP.
753      * This is an indication that if the device support 802.11ax AP then to enable or disable
754      * that feature. If the device does not support 802.11ax AP then this flag is ignored.
755      * See also {@link Builder#setIeee80211axEnabled(boolean}}
756      * @hide
757      */
758     @RequiresApi(Build.VERSION_CODES.S)
759     @SystemApi
isIeee80211axEnabled()760     public boolean isIeee80211axEnabled() {
761         if (!SdkLevel.isAtLeastS()) {
762             throw new UnsupportedOperationException();
763         }
764         return isIeee80211axEnabledInternal();
765     }
766 
767     /**
768      * Returns whether or not the {@link SoftApConfiguration} was configured by the user
769      * (as opposed to the default system configuration).
770      * <p>
771      * The {@link SoftApConfiguration} is considered user edited once the
772      * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} is called
773      * - whether or not that configuration is the same as the default system configuration!
774      *
775      * @hide
776      */
777     @RequiresApi(Build.VERSION_CODES.S)
778     @SystemApi
isUserConfiguration()779     public boolean isUserConfiguration() {
780         if (!SdkLevel.isAtLeastS()) {
781             throw new UnsupportedOperationException();
782         }
783         return isUserConfigurationInternal();
784     }
785 
786     /**
787      * @hide
788      */
isUserConfigurationInternal()789     public boolean isUserConfigurationInternal() {
790         return mIsUserConfiguration;
791     }
792 
793     /**
794      * Returns a {@link WifiConfiguration} representation of this {@link SoftApConfiguration}.
795      * Note that SoftApConfiguration may contain configuration which is cannot be represented
796      * by the legacy WifiConfiguration, in such cases a null will be returned.
797      *
798      * <li> SoftAp band in {@link WifiConfiguration.apBand} only supports
799      * 2GHz, 5GHz, 2GHz+5GHz bands, so conversion is limited to these bands. </li>
800      *
801      * <li> SoftAp security type in {@link WifiConfiguration.KeyMgmt} only supports
802      * NONE, WPA2_PSK, so conversion is limited to these security type.</li>
803      * @hide
804      */
805     @Nullable
806     @SystemApi
toWifiConfiguration()807     public WifiConfiguration toWifiConfiguration() {
808         WifiConfiguration wifiConfig = new WifiConfiguration();
809         wifiConfig.SSID = mSsid;
810         wifiConfig.preSharedKey = mPassphrase;
811         wifiConfig.hiddenSSID = mHiddenSsid;
812         wifiConfig.apChannel = getChannel();
813         switch (mSecurityType) {
814             case SECURITY_TYPE_OPEN:
815                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
816                 break;
817             case SECURITY_TYPE_WPA2_PSK:
818             case SECURITY_TYPE_WPA3_SAE_TRANSITION:
819                 wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK);
820                 break;
821             default:
822                 Log.e(TAG, "Convert fail, unsupported security type :" + mSecurityType);
823                 return null;
824         }
825 
826         switch (getBand()) {
827             case BAND_2GHZ:
828                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_2GHZ;
829                 break;
830             case BAND_5GHZ:
831                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_5GHZ;
832                 break;
833             case BAND_2GHZ | BAND_5GHZ:
834                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
835                 break;
836             case BAND_ANY:
837                 wifiConfig.apBand  = WifiConfiguration.AP_BAND_ANY;
838                 break;
839             default:
840                 Log.e(TAG, "Convert fail, unsupported band setting :" + getBand());
841                 return null;
842         }
843         return wifiConfig;
844     }
845 
846     /**
847      * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
848      * Soft AP.
849      *
850      * All fields are optional. By default, SSID and BSSID are automatically chosen by the
851      * framework, and an open network is created.
852      *
853      * @hide
854      */
855     @SystemApi
856     public static final class Builder {
857         private String mSsid;
858         private MacAddress mBssid;
859         private String mPassphrase;
860         private boolean mHiddenSsid;
861         private SparseIntArray mChannels;
862         private int mMaxNumberOfClients;
863         private int mSecurityType;
864         private boolean mAutoShutdownEnabled;
865         private long mShutdownTimeoutMillis;
866         private boolean mClientControlByUser;
867         private List<MacAddress> mBlockedClientList;
868         private List<MacAddress> mAllowedClientList;
869         private int mMacRandomizationSetting;
870         private boolean mBridgedModeOpportunisticShutdownEnabled;
871         private boolean mIeee80211axEnabled;
872         private boolean mIsUserConfiguration;
873 
874         /**
875          * Constructs a Builder with default values (see {@link Builder}).
876          */
Builder()877         public Builder() {
878             mSsid = null;
879             mBssid = null;
880             mPassphrase = null;
881             mHiddenSsid = false;
882             mChannels = new SparseIntArray(1);
883             mChannels.put(BAND_2GHZ, 0);
884             mMaxNumberOfClients = 0;
885             mSecurityType = SECURITY_TYPE_OPEN;
886             mAutoShutdownEnabled = true; // enabled by default.
887             mShutdownTimeoutMillis = 0;
888             mClientControlByUser = false;
889             mBlockedClientList = new ArrayList<>();
890             mAllowedClientList = new ArrayList<>();
891             mMacRandomizationSetting = RANDOMIZATION_PERSISTENT;
892             mBridgedModeOpportunisticShutdownEnabled = true;
893             mIeee80211axEnabled = true;
894             mIsUserConfiguration = true;
895         }
896 
897         /**
898          * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
899          */
Builder(@onNull SoftApConfiguration other)900         public Builder(@NonNull SoftApConfiguration other) {
901             Objects.requireNonNull(other);
902 
903             mSsid = other.mSsid;
904             mBssid = other.mBssid;
905             mPassphrase = other.mPassphrase;
906             mHiddenSsid = other.mHiddenSsid;
907             mChannels = other.mChannels.clone();
908             mMaxNumberOfClients = other.mMaxNumberOfClients;
909             mSecurityType = other.mSecurityType;
910             mAutoShutdownEnabled = other.mAutoShutdownEnabled;
911             mShutdownTimeoutMillis = other.mShutdownTimeoutMillis;
912             mClientControlByUser = other.mClientControlByUser;
913             mBlockedClientList = new ArrayList<>(other.mBlockedClientList);
914             mAllowedClientList = new ArrayList<>(other.mAllowedClientList);
915             mMacRandomizationSetting = other.mMacRandomizationSetting;
916             mBridgedModeOpportunisticShutdownEnabled =
917                     other.mBridgedModeOpportunisticShutdownEnabled;
918             mIeee80211axEnabled = other.mIeee80211axEnabled;
919             mIsUserConfiguration = other.mIsUserConfiguration;
920         }
921 
922         /**
923          * Builds the {@link SoftApConfiguration}.
924          *
925          * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
926          */
927         @NonNull
build()928         public SoftApConfiguration build() {
929             for (MacAddress client : mAllowedClientList) {
930                 if (mBlockedClientList.contains(client)) {
931                     throw new IllegalArgumentException("A MacAddress exist in both client list");
932                 }
933             }
934             return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
935                     mHiddenSsid, mChannels, mSecurityType, mMaxNumberOfClients,
936                     mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
937                     mBlockedClientList, mAllowedClientList, mMacRandomizationSetting,
938                     mBridgedModeOpportunisticShutdownEnabled, mIeee80211axEnabled,
939                     mIsUserConfiguration);
940         }
941 
942         /**
943          * Specifies an SSID for the AP.
944          * <p>
945          * Null SSID only support when configure a local-only hotspot.
946          * <p>
947          * <li>If not set, defaults to null.</li>
948          *
949          * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
950          *             chosen by the framework.
951          * @return Builder for chaining.
952          * @throws IllegalArgumentException when the SSID is empty or not valid Unicode.
953          */
954         @NonNull
setSsid(@ullable String ssid)955         public Builder setSsid(@Nullable String ssid) {
956             if (ssid != null) {
957                 Preconditions.checkStringNotEmpty(ssid);
958                 Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
959             }
960             mSsid = ssid;
961             return this;
962         }
963 
964         /**
965          * Specifies a BSSID for the AP.
966          * <p>
967          * <li>If not set, defaults to null.</li>
968          *
969          * If multiple bands are requested via {@link #setBands(int[])} or
970          * {@link #setChannels(SparseIntArray)}, HAL will derive 2 MAC addresses since framework
971          * only sends down 1 MAC address.
972          *
973          * An example (but different implementation may perform a different mapping):
974          * <li>MAC address 1: copy value of MAC address,
975          * and set byte 1 = (0xFF - BSSID[1])</li>
976          * <li>MAC address 2: copy value of MAC address,
977          * and set byte 2 = (0xFF - BSSID[2])</li>
978          *
979          * Example BSSID argument: e2:38:60:c4:0e:b7
980          * Derived MAC address 1: e2:c7:60:c4:0e:b7
981          * Derived MAC address 2: e2:38:9f:c4:0e:b7
982          *
983          * <p>
984          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
985          * {@link SoftApCapability#areFeaturesSupported(long)}
986          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
987          * whether or not this feature is supported.
988          *
989          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
990          *              responsible for avoiding collisions.
991          * @return Builder for chaining.
992          * @throws IllegalArgumentException when the given BSSID is the all-zero
993          *                                  , multicast or broadcast MAC address.
994          */
995         @NonNull
setBssid(@ullable MacAddress bssid)996         public Builder setBssid(@Nullable MacAddress bssid) {
997             if (bssid != null) {
998                 Preconditions.checkArgument(!bssid.equals(WifiManager.ALL_ZEROS_MAC_ADDRESS));
999                 if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) {
1000                     throw new IllegalArgumentException("bssid doesn't support "
1001                             + "multicast or broadcast mac address");
1002                 }
1003             }
1004             mBssid = bssid;
1005             return this;
1006         }
1007 
1008         /**
1009          * Specifies that this AP should use specific security type with the given ASCII passphrase.
1010          *
1011          * @param securityType One of the following security types:
1012          * {@link #SECURITY_TYPE_OPEN},
1013          * {@link #SECURITY_TYPE_WPA2_PSK},
1014          * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
1015          * {@link #SECURITY_TYPE_WPA3_SAE}.
1016          * @param passphrase The passphrase to use for sepcific {@code securityType} configuration
1017          * or null with {@link #SECURITY_TYPE_OPEN}.
1018          *
1019          * @return Builder for chaining.
1020          * @throws IllegalArgumentException when the passphrase length is invalid and
1021          *         {@code securityType} is not {@link #SECURITY_TYPE_OPEN}
1022          *         or non-null passphrase and {@code securityType} is
1023          *         {@link #SECURITY_TYPE_OPEN}.
1024          */
1025         @NonNull
setPassphrase(@ullable String passphrase, @SecurityType int securityType)1026         public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
1027             if (securityType == SECURITY_TYPE_OPEN) {
1028                 if (passphrase != null) {
1029                     throw new IllegalArgumentException(
1030                             "passphrase should be null when security type is open");
1031                 }
1032             } else {
1033                 Preconditions.checkStringNotEmpty(passphrase);
1034                 if (securityType == SECURITY_TYPE_WPA2_PSK
1035                         || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
1036                     if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
1037                         throw new IllegalArgumentException(
1038                                 "Password size must be at least " + PSK_MIN_LEN
1039                                 + " and no more than " + PSK_MAX_LEN
1040                                 + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
1041                     }
1042                 }
1043             }
1044             mSecurityType = securityType;
1045             mPassphrase = passphrase;
1046             return this;
1047         }
1048 
1049         /**
1050          * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
1051          * not (broadcasts its SSID).
1052          * <p>
1053          * <li>If not set, defaults to false (i.e not a hidden network).</li>
1054          *
1055          * @param hiddenSsid true for a hidden SSID, false otherwise.
1056          * @return Builder for chaining.
1057          */
1058         @NonNull
setHiddenSsid(boolean hiddenSsid)1059         public Builder setHiddenSsid(boolean hiddenSsid) {
1060             mHiddenSsid = hiddenSsid;
1061             return this;
1062         }
1063 
1064         /**
1065          * Specifies the band for the AP.
1066          * <p>
1067          * <li>If not set, defaults to {@link #BAND_2GHZ}.</li>
1068          *
1069          * @param band One or combination of the following band type:
1070          * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
1071          * @return Builder for chaining.
1072          * @throws IllegalArgumentException when an invalid band type is provided.
1073          */
1074         @NonNull
setBand(@andType int band)1075         public Builder setBand(@BandType int band) {
1076             if (!isBandValid(band)) {
1077                 throw new IllegalArgumentException("Invalid band type: " + band);
1078             }
1079             mChannels = new SparseIntArray(1);
1080             mChannels.put(band, 0);
1081             return this;
1082         }
1083 
1084         /**
1085          * Specifies the bands for the APs.
1086          * If more than 1 band is set, this will bring up concurrent APs.
1087          * on the requested bands (if possible).
1088          * <p>
1089          *
1090          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1091          * whether or not concurrent APs are supported.
1092          *
1093          * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1094          * when multiple bands are configured. Otherwise,
1095          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1096          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1097          *
1098          * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error
1099          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1100          *
1101          * @param bands Array of the {@link #BandType}.
1102          * @return Builder for chaining.
1103          * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
1104          *                                  is provided.
1105          */
1106         @RequiresApi(Build.VERSION_CODES.S)
1107         @NonNull
setBands(@onNull int[] bands)1108         public Builder setBands(@NonNull int[] bands) {
1109             if (!SdkLevel.isAtLeastS()) {
1110                 throw new UnsupportedOperationException();
1111             }
1112             if (bands.length == 0 || bands.length > 2) {
1113                 throw new IllegalArgumentException("Unsupported number of bands("
1114                         + bands.length + ") configured");
1115             }
1116             SparseIntArray channels = new SparseIntArray(bands.length);
1117             for (int val : bands) {
1118                 if (!isBandValid(val)) {
1119                     throw new IllegalArgumentException("Invalid band type: " + val);
1120                 }
1121                 channels.put(val, 0);
1122             }
1123             mChannels = channels;
1124             return this;
1125         }
1126 
1127 
1128         /**
1129          * Specifies the channel and associated band for the AP.
1130          *
1131          * The channel which AP resides on. Valid channels are country dependent.
1132          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
1133          * valid channels.
1134          *
1135          * <p>
1136          * If not set, the default for the channel is the special value 0 which has the
1137          * framework auto-select a valid channel from the band configured with
1138          * {@link #setBand(int)}.
1139          *
1140          * The channel auto selection will be offloaded to driver when
1141          * {@link SoftApCapability#areFeaturesSupported(long)}
1142          * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1143          * return true. The driver will auto select the best channel (e.g. best performance)
1144          * based on environment interference. Check {@link SoftApCapability} for more detail.
1145          *
1146          * The API contains (band, channel) input since the 6GHz band uses the same channel
1147          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1148          * uniquely identify individual channels.
1149          *
1150          * <p>
1151          * @param channel operating channel of the AP.
1152          * @param band containing this channel.
1153          * @return Builder for chaining.
1154          * @throws IllegalArgumentException when the invalid channel or band type is configured.
1155          */
1156         @NonNull
setChannel(int channel, @BandType int band)1157         public Builder setChannel(int channel, @BandType int band) {
1158             if (!isChannelBandPairValid(channel, band)) {
1159                 throw new IllegalArgumentException("Invalid channel(" + channel
1160                         + ") & band (" + band + ") configured");
1161             }
1162             mChannels = new SparseIntArray(1);
1163             mChannels.put(band, channel);
1164             return this;
1165         }
1166 
1167         /**
1168          * Specifies the channels and associated bands for the APs.
1169          *
1170          * When more than 1 channel is set, this will bring up concurrent APs on the requested
1171          * channels and bands (if possible).
1172          *
1173          * Valid channels are country dependent.
1174          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
1175          * valid channels in each band.
1176          *
1177          * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
1178          * whether or not concurrent APs are supported.
1179          *
1180          * <p>
1181          * If not set, the default for the channel is the special value 0 which has the framework
1182          * auto-select a valid channel from the band configured with {@link #setBands(int[])}.
1183          *
1184          * The channel auto selection will be offloaded to driver when
1185          * {@link SoftApCapability#areFeaturesSupported(long)}
1186          * with {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1187          * returns true. The driver will auto select the best channel (e.g. best performance)
1188          * based on environment interference. Check {@link SoftApCapability} for more detail.
1189          *
1190          * Requires the driver to support {@link SoftApCapability.SOFTAP_FEATURE_ACS_OFFLOAD}
1191          * when multiple bands are configured without specified channel value (i.e. channel is
1192          * the special value 0). Otherwise,
1193          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1194          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1195          *
1196          * Note: Only supports 2.4GHz + 5GHz bands. If any other band is set, will report error
1197          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1198          *
1199          * The API contains (band, channel) input since the 6GHz band uses the same channel
1200          * numbering scheme as is used in the 2.4GHz and 5GHz band. Therefore, both are needed to
1201          * uniquely identify individual channels.
1202          *
1203          * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
1204          * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
1205          *
1206          * <p>
1207          * @param channels SparseIntArray (key: {@code #BandType} , value: channel) consists of
1208          *                 {@code BAND_} and corresponding channel.
1209          * @return Builder for chaining.
1210          * @throws IllegalArgumentException when more than 2 channels are set or the invalid
1211          *                                  channel or band type is configured.
1212          */
1213         @RequiresApi(Build.VERSION_CODES.S)
1214         @NonNull
setChannels(@onNull SparseIntArray channels)1215         public Builder setChannels(@NonNull SparseIntArray channels) {
1216             if (!SdkLevel.isAtLeastS()) {
1217                 throw new UnsupportedOperationException();
1218             }
1219             if (channels.size() == 0 || channels.size() > 2) {
1220                 throw new IllegalArgumentException("Unsupported number of channels("
1221                         + channels.size() + ") configured");
1222             }
1223             for (int i = 0; i < channels.size(); i++) {
1224                 int channel = channels.valueAt(i);
1225                 int band = channels.keyAt(i);
1226                 if (channel == 0) {
1227                     if (!isBandValid(band)) {
1228                         throw new IllegalArgumentException("Invalid band type: " + band);
1229                     }
1230                 } else {
1231                     if (!isChannelBandPairValid(channel, band)) {
1232                         throw new IllegalArgumentException("Invalid channel(" + channel
1233                                 + ") & band (" + band + ") configured");
1234                     }
1235                 }
1236             }
1237             mChannels = channels.clone();
1238             return this;
1239         }
1240 
1241 
1242         /**
1243          * Specifies the maximum number of clients that can associate to the AP.
1244          *
1245          * The maximum number of clients (STAs) which can associate to the AP.
1246          * The AP will reject association from any clients above this number.
1247          * Specify a value of 0 to have the framework automatically use the maximum number
1248          * which the device can support (based on hardware and carrier constraints).
1249          * <p>
1250          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1251          * {@link SoftApCapability#getMaxSupportedClients} to get the maximum number of clients
1252          * which the device supports (based on hardware and carrier constraints).
1253          *
1254          * <p>
1255          * <li>If not set, defaults to 0.</li>
1256          *
1257          * This method requires HAL support. If the method is used to set a
1258          * non-zero {@code maxNumberOfClients} value then
1259          * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will report error code
1260          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1261          *
1262          * <p>
1263          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1264          * {@link SoftApCapability#areFeaturesSupported(long)}
1265          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} to determine whether
1266          * or not this feature is supported.
1267          *
1268          * @param maxNumberOfClients maximum client number of the AP.
1269          * @return Builder for chaining.
1270          */
1271         @NonNull
setMaxNumberOfClients(@ntRangefrom = 0) int maxNumberOfClients)1272         public Builder setMaxNumberOfClients(@IntRange(from = 0) int maxNumberOfClients) {
1273             if (maxNumberOfClients < 0) {
1274                 throw new IllegalArgumentException("maxNumberOfClients should be not negative");
1275             }
1276             mMaxNumberOfClients = maxNumberOfClients;
1277             return this;
1278         }
1279 
1280         /**
1281          * Specifies whether auto shutdown is enabled or not.
1282          * The Soft AP will shut down when there are no devices connected to it for
1283          * the timeout duration.
1284          *
1285          * <p>
1286          * <li>If not set, defaults to true</li>
1287          *
1288          * @param enable true to enable, false to disable.
1289          * @return Builder for chaining.
1290          *
1291          * @see #setShutdownTimeoutMillis(long)
1292          */
1293         @NonNull
setAutoShutdownEnabled(boolean enable)1294         public Builder setAutoShutdownEnabled(boolean enable) {
1295             mAutoShutdownEnabled = enable;
1296             return this;
1297         }
1298 
1299         /**
1300          * Specifies the shutdown timeout in milliseconds.
1301          * The Soft AP will shut down when there are no devices connected to it for
1302          * the timeout duration.
1303          *
1304          * Specify a value of 0 to have the framework automatically use default timeout
1305          * setting which defined in {@link R.integer.config_wifi_framework_soft_ap_timeout_delay}
1306          *
1307          * <p>
1308          * <li>If not set, defaults to 0</li>
1309          * <li>The shut down timeout will apply when {@link #setAutoShutdownEnabled(boolean)} is
1310          * set to true</li>
1311          *
1312          * @param timeoutMillis milliseconds of the timeout delay.
1313          * @return Builder for chaining.
1314          *
1315          * @see #setAutoShutdownEnabled(boolean)
1316          */
1317         @NonNull
setShutdownTimeoutMillis(@ntRangefrom = 0) long timeoutMillis)1318         public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) {
1319             if (timeoutMillis < 0) {
1320                 throw new IllegalArgumentException("Invalid timeout value");
1321             }
1322             mShutdownTimeoutMillis = timeoutMillis;
1323             return this;
1324         }
1325 
1326         /**
1327          * Configure the Soft AP to require manual user control of client association.
1328          * If disabled (the default) then any client which isn't in the blocked list
1329          * {@link #getBlockedClientList()} can associate to this Soft AP using the
1330          * correct credentials until the Soft AP capacity is reached (capacity is hardware, carrier,
1331          * or user limited - using {@link #setMaxNumberOfClients(int)}).
1332          *
1333          * If manual user control is enabled then clients will be accepted, rejected, or require
1334          * a user approval based on the configuration provided by
1335          * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
1336          *
1337          * <p>
1338          * This method requires HAL support. HAL support can be determined using
1339          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1340          * {@link SoftApCapability#areFeaturesSupported(long)}
1341          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
1342          *
1343          * <p>
1344          * If the method is called on a device without HAL support then starting the soft AP
1345          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
1346          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1347          *
1348          * <p>
1349          * <li>If not set, defaults to false (i.e The authoriztion is not required).</li>
1350          *
1351          * @param enabled true for enabling the control by user, false otherwise.
1352          * @return Builder for chaining.
1353          */
1354         @NonNull
setClientControlByUserEnabled(boolean enabled)1355         public Builder setClientControlByUserEnabled(boolean enabled) {
1356             mClientControlByUser = enabled;
1357             return this;
1358         }
1359 
1360 
1361         /**
1362          * This method together with {@link setClientControlByUserEnabled(boolean)} control client
1363          * connections to the AP. If client control by user is disabled using the above method then
1364          * this API has no effect and clients are allowed to associate to the AP (within limit of
1365          * max number of clients).
1366          *
1367          * If client control by user is enabled then this API configures the list of clients
1368          * which are explicitly allowed. These are auto-accepted.
1369          *
1370          * All other clients which attempt to associate, whose MAC addresses are on neither list,
1371          * are:
1372          * <ul>
1373          * <li>Rejected</li>
1374          * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
1375          * is issued (which allows the user to add them to the allowed client list if desired).<li>
1376          * </ul>
1377          *
1378          * @param allowedClientList list of clients which are allowed to associate to the AP
1379          *                          without user pre-approval.
1380          * @return Builder for chaining.
1381          */
1382         @NonNull
setAllowedClientList(@onNull List<MacAddress> allowedClientList)1383         public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
1384             mAllowedClientList = new ArrayList<>(allowedClientList);
1385             return this;
1386         }
1387 
1388         /**
1389          * This API configures the list of clients which are blocked and cannot associate
1390          * to the Soft AP.
1391          *
1392          * <p>
1393          * This method requires HAL support. HAL support can be determined using
1394          * {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1395          * {@link SoftApCapability#areFeaturesSupported(long)}
1396          * with {@link SoftApCapability.SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT}
1397          *
1398          * <p>
1399          * If the method is called on a device without HAL support then starting the soft AP
1400          * using {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} will fail with
1401          * {@link WifiManager#SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
1402          *
1403          * @param blockedClientList list of clients which are not allowed to associate to the AP.
1404          * @return Builder for chaining.
1405          */
1406         @NonNull
setBlockedClientList(@onNull List<MacAddress> blockedClientList)1407         public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
1408             mBlockedClientList = new ArrayList<>(blockedClientList);
1409             return this;
1410         }
1411 
1412         /**
1413          * Specifies the level of MAC randomization for the AP BSSID.
1414          * The Soft AP BSSID will be randomized only if the BSSID isn't set
1415          * {@link #setBssid(MacAddress)} and this method is either uncalled
1416          * or called with {@link #RANDOMIZATION_PERSISTENT}.
1417          *
1418          * <p>
1419          * <li>If not set, defaults to {@link #RANDOMIZATION_PERSISTENT}</li>
1420          *
1421          * <p>
1422          * Requires HAL support when set to {@link #RANDOMIZATION_PERSISTENT}.
1423          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1424          * {@link SoftApCapability#areFeaturesSupported(long)}
1425          * with {@link SoftApCapability.SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION} to determine
1426          * whether or not this feature is supported.
1427          *
1428          * @param macRandomizationSetting One of the following setting:
1429          * {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
1430          * @return Builder for chaining.
1431          *
1432          * @see #setBssid(MacAddress)
1433          */
1434         @RequiresApi(Build.VERSION_CODES.S)
1435         @NonNull
setMacRandomizationSetting( @acRandomizationSetting int macRandomizationSetting)1436         public Builder setMacRandomizationSetting(
1437                 @MacRandomizationSetting int macRandomizationSetting) {
1438             if (!SdkLevel.isAtLeastS()) {
1439                 throw new UnsupportedOperationException();
1440             }
1441             mMacRandomizationSetting = macRandomizationSetting;
1442             return this;
1443         }
1444 
1445 
1446         /**
1447          * Specifies whether or not opportunistic shut down of an AP instance in bridged mode
1448          * is enabled.
1449          *
1450          * <p>
1451          * If enabled, the framework will shutdown one of the AP instances if it is idle for
1452          * the timeout duration - meaning there are no devices connected to it.
1453          * If both AP instances are idle for the timeout duration then the framework will
1454          * shut down the AP instance operating on the higher frequency. For instance,
1455          * if the AP instances operate at 2.4GHz and 5GHz and are both idle for the
1456          * timeout duration then the 5GHz AP instance will be shut down.
1457          * <p>
1458          *
1459          * Note: the opportunistic timeout only applies to one AP instance of the bridge AP.
1460          * If one of the AP instances has already been disabled for any reason, including due to
1461          * an opportunistic timeout or hardware issues or coexistence issues,
1462          * then the opportunistic timeout is no longer active.
1463          *
1464          * <p>
1465          * The shutdown timer specified by {@link #setShutdownTimeoutMillis(long)} controls the
1466          * overall shutdown of the bridged AP and is still in use independently of the opportunistic
1467          * timer controlled by this AP.
1468          *
1469          * <p>
1470          * <li>If not set, defaults to true</li>
1471          *
1472          * @param enable true to enable, false to disable.
1473          * @return Builder for chaining.
1474          *
1475          */
1476         @RequiresApi(Build.VERSION_CODES.S)
1477         @NonNull
setBridgedModeOpportunisticShutdownEnabled(boolean enable)1478         public Builder setBridgedModeOpportunisticShutdownEnabled(boolean enable) {
1479             if (!SdkLevel.isAtLeastS()) {
1480                 throw new UnsupportedOperationException();
1481             }
1482             mBridgedModeOpportunisticShutdownEnabled = enable;
1483             return this;
1484         }
1485 
1486         /**
1487          * Specifies whether or not to enable 802.11ax on the Soft AP.
1488          *
1489          * <p>
1490          * Note: Only relevant when the device supports 802.11ax on the Soft AP.
1491          * If enabled on devices that do not support 802.11ax then ignored.
1492          * Use {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)} and
1493          * {@link SoftApCapability#areFeaturesSupported(long)}
1494          * with {@link SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX} to determine
1495          * whether or not 802.11ax is supported on the Soft AP.
1496          * <p>
1497          * <li>If not set, defaults to true - which will be ignored on devices
1498          * which do not support 802.11ax</li>
1499          *
1500          * @param enable true to enable, false to disable.
1501          * @return Builder for chaining.
1502          *
1503          */
1504         @RequiresApi(Build.VERSION_CODES.S)
1505         @NonNull
setIeee80211axEnabled(boolean enable)1506         public Builder setIeee80211axEnabled(boolean enable) {
1507             if (!SdkLevel.isAtLeastS()) {
1508                 throw new UnsupportedOperationException();
1509             }
1510             mIeee80211axEnabled = enable;
1511             return this;
1512         }
1513 
1514         /**
1515          * Specifies whether or not the configuration is configured by user.
1516          *
1517          * @param isUserConfigured true to user configuration, false otherwise.
1518          * @return Builder for chaining.
1519          *
1520          * @hide
1521          */
1522         @NonNull
setUserConfiguration(boolean isUserConfigured)1523         public Builder setUserConfiguration(boolean isUserConfigured) {
1524             mIsUserConfiguration = isUserConfigured;
1525             return this;
1526         }
1527     }
1528 }
1529