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 static android.net.wifi.ScanResult.InformationElement.EID_VSA;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.junit.Assert.assertArrayEquals;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertThrows;
28 import static org.junit.Assert.assertTrue;
29 import static org.junit.Assert.fail;
30 import static org.junit.Assume.assumeFalse;
31 import static org.junit.Assume.assumeTrue;
32 import static org.mockito.Mockito.mock;
33 
34 import android.net.MacAddress;
35 import android.os.Parcel;
36 import android.os.PersistableBundle;
37 import android.util.SparseIntArray;
38 
39 import androidx.test.filters.SmallTest;
40 
41 import com.android.modules.utils.build.SdkLevel;
42 
43 import org.junit.Test;
44 
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.Random;
49 
50 @SmallTest
51 public class SoftApConfigurationTest {
52     private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";
53     private static final String TEST_BSSID = "aa:22:33:aa:bb:cc";
54     private static final List<ScanResult.InformationElement> TEST_TWO_VENDOR_ELEMENTS =
55             new ArrayList<>(Arrays.asList(
56                     new ScanResult.InformationElement(EID_VSA, 0, new byte[]{ 1, 2, 3, 4 }),
57                     new ScanResult.InformationElement(
58                             EID_VSA,
59                             0,
60                             new byte[]{ (byte) 170, (byte) 187, (byte) 204, (byte) 221 })
61                     ));
62     private static final List<ScanResult.InformationElement> TEST_TWO_VENDOR_ELEMENTS_INVALID =
63             new ArrayList<>(Arrays.asList(
64                     new ScanResult.InformationElement(EID_VSA, 0, new byte[]{ 1, 2, 3, 4 }),
65                     new ScanResult.InformationElement(
66                             (byte) 222,
67                             0,
68                             new byte[]{ (byte) 170, (byte) 187, (byte) 204, (byte) 221 })
69                     ));
70 
parcelUnparcel(SoftApConfiguration configIn)71     private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
72         Parcel parcel = Parcel.obtain();
73         parcel.writeParcelable(configIn, 0);
74         parcel.setDataPosition(0);
75         SoftApConfiguration configOut =
76                 parcel.readParcelable(SoftApConfiguration.class.getClassLoader());
77         parcel.recycle();
78         return configOut;
79     }
80 
81     /**
82      * Helper method to generate random string.
83      *
84      * Note: this method has limited use as a random string generator.
85      * The characters used in this method do no not cover all valid inputs.
86      * @param length number of characters to generate for the string
87      * @return String generated string of random characters
88      */
generateRandomString(int length)89     private String generateRandomString(int length) {
90         Random random = new Random();
91         StringBuilder stringBuilder = new StringBuilder(length);
92         int index = -1;
93         while (stringBuilder.length() < length) {
94             index = random.nextInt(TEST_CHAR_SET_AS_STRING.length());
95             stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
96         }
97         return stringBuilder.toString();
98     }
99 
100     @Test
testBasicSettings()101     public void testBasicSettings() {
102         MacAddress testBssid = MacAddress.fromString(TEST_BSSID);
103         String utf8Ssid = "ssid";
104         SoftApConfiguration original = new SoftApConfiguration.Builder()
105                 .setSsid(utf8Ssid)
106                 .build();
107         assertThat(original.getSsid()).isEqualTo(utf8Ssid);
108         assertThat(original.getWifiSsid()).isEqualTo(WifiSsid.fromUtf8Text(utf8Ssid));
109         assertThat(original.getPassphrase()).isNull();
110         assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
111         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
112         assertThat(original.getChannel()).isEqualTo(0);
113         assertThat(original.isHiddenSsid()).isEqualTo(false);
114         assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
115         assertThat(original.getPersistentRandomizedMacAddress()).isNull();
116         if (SdkLevel.isAtLeastS()) {
117             assertThat(original.isBridgedModeOpportunisticShutdownEnabled())
118                     .isEqualTo(true);
119             assertThat(original.isIeee80211axEnabled())
120                     .isEqualTo(true);
121             assertThat(original.isUserConfiguration())
122                     .isEqualTo(true);
123             if (SdkLevel.isAtLeastT()) {
124                 assertThat(original.getBridgedModeOpportunisticShutdownTimeoutMillis())
125                         .isEqualTo(SoftApConfiguration.DEFAULT_TIMEOUT);
126                 assertThat(original.getMacRandomizationSetting())
127                         .isEqualTo(SoftApConfiguration.RANDOMIZATION_NON_PERSISTENT);
128                 assertThat(original.getVendorElements().size()).isEqualTo(0);
129             } else {
130                 assertThat(original.getMacRandomizationSetting())
131                         .isEqualTo(SoftApConfiguration.RANDOMIZATION_PERSISTENT);
132             }
133         }
134 
135         SoftApConfiguration unparceled = parcelUnparcel(original);
136         assertThat(unparceled).isNotSameInstanceAs(original);
137         assertThat(unparceled).isEqualTo(original);
138         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
139 
140         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
141         assertThat(copy).isNotSameInstanceAs(original);
142         assertThat(copy).isEqualTo(original);
143         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
144     }
145 
146     @Test
testSetWifiSsid()147     public void testSetWifiSsid() {
148         assumeTrue(SdkLevel.isAtLeastT());
149 
150         // UTF-8
151         WifiSsid wifiSsidUtf8 = WifiSsid.fromUtf8Text("ssid");
152         SoftApConfiguration utf8Config = new SoftApConfiguration.Builder()
153                 .setWifiSsid(wifiSsidUtf8)
154                 .build();
155         assertThat(utf8Config.getWifiSsid()).isEqualTo(wifiSsidUtf8);
156         assertThat(utf8Config.getSsid()).isEqualTo("ssid");
157 
158         SoftApConfiguration unparceled = parcelUnparcel(utf8Config);
159         assertThat(unparceled).isNotSameInstanceAs(utf8Config);
160         assertThat(unparceled).isEqualTo(utf8Config);
161         assertThat(unparceled.hashCode()).isEqualTo(utf8Config.hashCode());
162 
163         // Non-UTF-8
164         byte[] nonUtf8Bytes =
165                 new byte[]{(byte) 0x01, (byte) 0x23, (byte) 0x45, (byte) 0x67, (byte) 0x89};
166         WifiSsid wifiSsidNonUtf8 = WifiSsid.fromBytes(nonUtf8Bytes);
167         SoftApConfiguration nonUtf8Config = new SoftApConfiguration.Builder()
168                 .setWifiSsid(wifiSsidNonUtf8)
169                 .build();
170         assertThat(nonUtf8Config.getWifiSsid()).isEqualTo(wifiSsidNonUtf8);
171         assertThat(nonUtf8Config.getSsid()).isEqualTo(WifiManager.UNKNOWN_SSID);
172 
173         unparceled = parcelUnparcel(nonUtf8Config);
174         assertThat(unparceled).isNotSameInstanceAs(nonUtf8Config);
175         assertThat(unparceled).isEqualTo(nonUtf8Config);
176         assertThat(unparceled.hashCode()).isEqualTo(nonUtf8Config.hashCode());
177     }
178 
179     @Test
testWpa2()180     public void testWpa2() {
181         SoftApConfiguration original = new SoftApConfiguration.Builder()
182                 .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
183                 .build();
184         assertThat(original.getPassphrase()).isEqualTo("secretsecret");
185         assertThat(original.getSecurityType()).isEqualTo(
186                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
187         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
188         assertThat(original.getChannel()).isEqualTo(0);
189         assertThat(original.isHiddenSsid()).isEqualTo(false);
190         assertThat(original.getMaxNumberOfClients()).isEqualTo(0);
191 
192         SoftApConfiguration unparceled = parcelUnparcel(original);
193         assertThat(unparceled).isNotSameInstanceAs(original);
194         assertThat(unparceled).isEqualTo(original);
195         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
196 
197         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
198         assertThat(copy).isNotSameInstanceAs(original);
199         assertThat(copy).isEqualTo(original);
200         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
201     }
202 
203     @Test
testWpa2WithAllFieldCustomized()204     public void testWpa2WithAllFieldCustomized() {
205         MacAddress testRandomizedMacAddress = MacAddress.fromString(TEST_BSSID);
206         List<MacAddress> testBlockedClientList = new ArrayList<>();
207         List<MacAddress> testAllowedClientList = new ArrayList<>();
208         testBlockedClientList.add(MacAddress.fromString("11:22:33:44:55:66"));
209         testAllowedClientList.add(MacAddress.fromString("aa:bb:cc:dd:ee:ff"));
210         SoftApConfiguration.Builder originalBuilder = new SoftApConfiguration.Builder()
211                 .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
212                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
213                 .setHiddenSsid(true)
214                 .setMaxNumberOfClients(10)
215                 .setAutoShutdownEnabled(true)
216                 .setShutdownTimeoutMillis(500000)
217                 .setClientControlByUserEnabled(true)
218                 .setBlockedClientList(testBlockedClientList)
219                 .setAllowedClientList(testAllowedClientList)
220                 .setRandomizedMacAddress(testRandomizedMacAddress);
221         if (SdkLevel.isAtLeastS()) {
222             originalBuilder.setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE);
223             originalBuilder.setBridgedModeOpportunisticShutdownEnabled(false);
224             originalBuilder.setIeee80211axEnabled(false);
225             originalBuilder.setUserConfiguration(false);
226         }
227 
228         if (SdkLevel.isAtLeastT()) {
229             originalBuilder.setBridgedModeOpportunisticShutdownTimeoutMillis(300_000);
230             originalBuilder.setVendorElements(TEST_TWO_VENDOR_ELEMENTS);
231         }
232 
233         SoftApConfiguration original = originalBuilder.build();
234         assertThat(original.getPassphrase()).isEqualTo("secretsecret");
235         assertThat(original.getSecurityType()).isEqualTo(
236                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
237         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
238         assertThat(original.getChannel()).isEqualTo(149);
239         assertThat(original.isHiddenSsid()).isEqualTo(true);
240         assertThat(original.getMaxNumberOfClients()).isEqualTo(10);
241         assertThat(original.isAutoShutdownEnabled()).isEqualTo(true);
242         assertThat(original.getShutdownTimeoutMillis()).isEqualTo(500000);
243         assertThat(original.isClientControlByUserEnabled()).isEqualTo(true);
244         assertThat(original.getBlockedClientList()).isEqualTo(testBlockedClientList);
245         assertThat(original.getAllowedClientList()).isEqualTo(testAllowedClientList);
246         assertThat(original.getPersistentRandomizedMacAddress())
247                 .isEqualTo(testRandomizedMacAddress);
248         if (SdkLevel.isAtLeastS()) {
249             assertThat(original.getMacRandomizationSetting())
250                     .isEqualTo(SoftApConfiguration.RANDOMIZATION_NONE);
251             assertThat(original.isBridgedModeOpportunisticShutdownEnabled())
252                     .isEqualTo(false);
253             assertThat(original.isIeee80211axEnabled())
254                     .isEqualTo(false);
255             assertThat(original.isUserConfiguration())
256                     .isEqualTo(false);
257         }
258         if (SdkLevel.isAtLeastT()) {
259             assertThat(original.getBridgedModeOpportunisticShutdownTimeoutMillis())
260                     .isEqualTo(300_000);
261             assertThat(original.getVendorElements())
262                     .isEqualTo(TEST_TWO_VENDOR_ELEMENTS);
263         }
264 
265         SoftApConfiguration unparceled = parcelUnparcel(original);
266         assertThat(unparceled).isNotSameInstanceAs(original);
267         assertThat(unparceled).isEqualTo(original);
268         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
269 
270         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
271         assertThat(copy).isNotSameInstanceAs(original);
272         assertThat(copy).isEqualTo(original);
273         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
274     }
275 
276     @Test
testWpa3Sae()277     public void testWpa3Sae() {
278         SoftApConfiguration original = new SoftApConfiguration.Builder()
279                 .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
280                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
281                 .setHiddenSsid(true)
282                 .build();
283         assertThat(original.getPassphrase()).isEqualTo("secretsecret");
284         assertThat(original.getSecurityType()).isEqualTo(
285                 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
286         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
287         assertThat(original.getChannel()).isEqualTo(149);
288         assertThat(original.isHiddenSsid()).isEqualTo(true);
289 
290 
291         SoftApConfiguration unparceled = parcelUnparcel(original);
292         assertThat(unparceled).isNotSameInstanceAs(original);
293         assertThat(unparceled).isEqualTo(original);
294         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
295 
296         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
297         assertThat(copy).isNotSameInstanceAs(original);
298         assertThat(copy).isEqualTo(original);
299         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
300     }
301 
302     @Test
testWpa3SaeTransition()303     public void testWpa3SaeTransition() {
304         SoftApConfiguration original = new SoftApConfiguration.Builder()
305                 .setPassphrase("secretsecret",
306                         SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
307                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
308                 .setHiddenSsid(true)
309                 .build();
310         assertThat(original.getSecurityType()).isEqualTo(
311                 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
312         assertThat(original.getPassphrase()).isEqualTo("secretsecret");
313         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
314         assertThat(original.getChannel()).isEqualTo(149);
315         assertThat(original.isHiddenSsid()).isEqualTo(true);
316 
317 
318         SoftApConfiguration unparceled = parcelUnparcel(original);
319         assertThat(unparceled).isNotSameInstanceAs(original);
320         assertThat(unparceled).isEqualTo(original);
321         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
322 
323         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
324         assertThat(copy).isNotSameInstanceAs(original);
325         assertThat(copy).isEqualTo(original);
326         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
327     }
328 
329     @Test
testWpa3OweTransition()330     public void testWpa3OweTransition() {
331         assumeTrue(SdkLevel.isAtLeastT());
332         SoftApConfiguration original = new SoftApConfiguration.Builder()
333                 .setPassphrase(null,
334                         SoftApConfiguration.SECURITY_TYPE_WPA3_OWE_TRANSITION)
335                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
336                 .setHiddenSsid(false)
337                 .build();
338         assertThat(original.getSecurityType()).isEqualTo(
339                 SoftApConfiguration.SECURITY_TYPE_WPA3_OWE_TRANSITION);
340         assertThat(original.getPassphrase()).isEqualTo(null);
341         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
342         assertThat(original.getChannel()).isEqualTo(149);
343         assertThat(original.isHiddenSsid()).isEqualTo(false);
344 
345         SoftApConfiguration unparceled = parcelUnparcel(original);
346         assertThat(unparceled).isNotSameInstanceAs(original);
347         assertThat(unparceled).isEqualTo(original);
348         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
349 
350         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
351         assertThat(copy).isNotSameInstanceAs(original);
352         assertThat(copy).isEqualTo(original);
353         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
354 
355         assertThrows(IllegalArgumentException.class,
356                 () -> new SoftApConfiguration.Builder().setPassphrase(
357                         "something or other",
358                         SoftApConfiguration.SECURITY_TYPE_WPA3_OWE_TRANSITION));
359     }
360 
361     @Test
testWpa3Owe()362     public void testWpa3Owe() {
363         assumeTrue(SdkLevel.isAtLeastT());
364         SoftApConfiguration original = new SoftApConfiguration.Builder()
365                 .setPassphrase(null,
366                         SoftApConfiguration.SECURITY_TYPE_WPA3_OWE)
367                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
368                 .setHiddenSsid(false)
369                 .build();
370         assertThat(original.getSecurityType()).isEqualTo(
371                 SoftApConfiguration.SECURITY_TYPE_WPA3_OWE);
372         assertThat(original.getPassphrase()).isEqualTo(null);
373         assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
374         assertThat(original.getChannel()).isEqualTo(149);
375         assertThat(original.isHiddenSsid()).isEqualTo(false);
376 
377         SoftApConfiguration unparceled = parcelUnparcel(original);
378         assertThat(unparceled).isNotSameInstanceAs(original);
379         assertThat(unparceled).isEqualTo(original);
380         assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
381 
382         SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
383         assertThat(copy).isNotSameInstanceAs(original);
384         assertThat(copy).isEqualTo(original);
385         assertThat(copy.hashCode()).isEqualTo(original.hashCode());
386 
387         assertThrows(IllegalArgumentException.class,
388                 () -> new SoftApConfiguration.Builder().setPassphrase(
389                         "something or other",
390                         SoftApConfiguration.SECURITY_TYPE_WPA3_OWE));
391     }
392 
393     @Test(expected = IllegalArgumentException.class)
testInvalidBroadcastBssid()394     public void testInvalidBroadcastBssid() {
395         SoftApConfiguration original = new SoftApConfiguration.Builder()
396                 .setBssid(MacAddress.BROADCAST_ADDRESS)
397                 .build();
398     }
399 
400     @Test(expected = IllegalArgumentException.class)
testInvalidMulticastBssid()401     public void testInvalidMulticastBssid() {
402         SoftApConfiguration original = new SoftApConfiguration.Builder()
403                 .setBssid(MacAddress.fromString("01:aa:bb:cc:dd:ee"))
404                 .build();
405     }
406 
407     @Test
testValidWpa2PasswordLength()408     public void testValidWpa2PasswordLength() {
409         // ASCII
410         new SoftApConfiguration.Builder().setPassphrase(
411                 "password",
412                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
413         // Pass without IllegalArgumentException
414 
415         // UTF-8
416         new SoftApConfiguration.Builder().setPassphrase(
417                 "パスワード",
418                 SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
419         // Pass without IllegalArgumentException
420     }
421 
422     @Test
testValidWpa3SaeTransitionPasswordLength()423     public void testValidWpa3SaeTransitionPasswordLength() {
424         // ASCII
425         new SoftApConfiguration.Builder().setPassphrase(
426                 "password",
427                 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
428         // Pass without IllegalArgumentException
429 
430         // UTF-8
431         new SoftApConfiguration.Builder().setPassphrase(
432                 "パスワード",
433                 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
434         // Pass without IllegalArgumentException
435     }
436 
437     @Test
testInvalidWpa2PasswordLength()438     public void testInvalidWpa2PasswordLength() {
439         assumeFalse(SdkLevel.isAtLeastT());
440         // Too short ASCII
441         try {
442             new SoftApConfiguration.Builder().setPassphrase(
443                     "Short!",
444                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
445             fail("Short ASCII password did not throw exception!");
446         } catch (IllegalArgumentException e) {
447             // Success
448         }
449 
450         // Too long ASCII
451         try {
452             new SoftApConfiguration.Builder().setPassphrase(
453                     "This ASCII passphrase is definitely much too long to be valid...",
454                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
455             fail("Long ASCII password did not throw exception!");
456         } catch (IllegalArgumentException e) {
457             // Success
458         }
459 
460         // Too short UTF-8
461         try {
462             new SoftApConfiguration.Builder().setPassphrase(
463                     "短い",
464                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
465             fail("Short UTF-8 password did not throw exception!");
466         } catch (IllegalArgumentException e) {
467             // Success
468         }
469 
470         // Too long UTF-8
471         try {
472             new SoftApConfiguration.Builder().setPassphrase(
473                     "このパスワードはちょっと長すぎて使えられません。",
474                     SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
475             fail("Long UTF-8 password did not throw exception!");
476         } catch (IllegalArgumentException e) {
477             // Success
478         }
479     }
480 
481     @Test
testInvalidWpa3SaeTransitionPasswordLength()482     public void testInvalidWpa3SaeTransitionPasswordLength() {
483         assumeFalse(SdkLevel.isAtLeastT());
484         // Too short ASCII
485         try {
486             new SoftApConfiguration.Builder().setPassphrase(
487                     "Short!",
488                     SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
489             fail("Short ASCII password did not throw exception!");
490         } catch (IllegalArgumentException e) {
491             // Success
492         }
493 
494         // Too long ASCII
495         try {
496             new SoftApConfiguration.Builder().setPassphrase(
497                     "This ASCII passphrase is definitely much too long to be valid...",
498                     SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
499             fail("Long ASCII password did not throw exception!");
500         } catch (IllegalArgumentException e) {
501             // Success
502         }
503 
504         // Too short UTF-8
505         try {
506             new SoftApConfiguration.Builder().setPassphrase(
507                     "短い",
508                     SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
509             fail("Short UTF-8 password did not throw exception!");
510         } catch (IllegalArgumentException e) {
511             // Success
512         }
513 
514         // Too long UTF-8
515         try {
516             new SoftApConfiguration.Builder().setPassphrase(
517                     "このパスワードはちょっと長すぎて使えられません。",
518                     SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
519             fail("Long UTF-8 password did not throw exception!");
520         } catch (IllegalArgumentException e) {
521             // Success
522         }
523     }
524 
525     @Test(expected = IllegalArgumentException.class)
testInvalieShutdownTimeoutMillis()526     public void testInvalieShutdownTimeoutMillis() {
527         SoftApConfiguration original = new SoftApConfiguration.Builder()
528                 .setShutdownTimeoutMillis(-2)
529                 .build();
530     }
531 
532     @Test(expected = IllegalArgumentException.class)
testZeroIsInvalidBridgedModeOpportunisticShutdownTimeoutMillis()533     public void testZeroIsInvalidBridgedModeOpportunisticShutdownTimeoutMillis() {
534         assumeTrue(SdkLevel.isAtLeastT());
535         SoftApConfiguration original = new SoftApConfiguration.Builder()
536                 .setBridgedModeOpportunisticShutdownTimeoutMillis(0)
537                 .build();
538     }
539 
540     @Test(expected = IllegalArgumentException.class)
testInvalidBridgedModeOpportunisticShutdownTimeoutMillis()541     public void testInvalidBridgedModeOpportunisticShutdownTimeoutMillis() {
542         assumeTrue(SdkLevel.isAtLeastT());
543         SoftApConfiguration original = new SoftApConfiguration.Builder()
544                 .setBridgedModeOpportunisticShutdownTimeoutMillis(-2)
545                 .build();
546     }
547 
548     @Test(expected = IllegalArgumentException.class)
testSetClientListExceptionWhenExistMacAddressInBothList()549     public void testSetClientListExceptionWhenExistMacAddressInBothList() {
550         final MacAddress testMacAddress_1 = MacAddress.fromString("22:33:44:55:66:77");
551         final MacAddress testMacAddress_2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff");
552         ArrayList<MacAddress> testAllowedClientList = new ArrayList<>();
553         testAllowedClientList.add(testMacAddress_1);
554         testAllowedClientList.add(testMacAddress_2);
555         ArrayList<MacAddress> testBlockedClientList = new ArrayList<>();
556         testBlockedClientList.add(testMacAddress_1);
557         SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
558         configBuilder.setBlockedClientList(testBlockedClientList)
559                 .setAllowedClientList(testAllowedClientList)
560                 .build();
561     }
562 
563     @Test
testToWifiConfigurationWithUnsupportedParameter()564     public void testToWifiConfigurationWithUnsupportedParameter() {
565         SoftApConfiguration sae_config = new SoftApConfiguration.Builder()
566                 .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
567                 .build();
568 
569         assertNull(sae_config.toWifiConfiguration());
570         SoftApConfiguration band_6g_config = new SoftApConfiguration.Builder()
571                 .setBand(SoftApConfiguration.BAND_6GHZ)
572                 .build();
573 
574         assertNull(band_6g_config.toWifiConfiguration());
575     }
576 
577     @Test
testToWifiConfigurationWithSupportedParameter()578     public void testToWifiConfigurationWithSupportedParameter() {
579         SoftApConfiguration softApConfig_2g = new SoftApConfiguration.Builder()
580                 .setPassphrase("secretsecret",
581                         SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
582                 .setChannel(11, SoftApConfiguration.BAND_2GHZ)
583                 .setHiddenSsid(true)
584                 .build();
585         WifiConfiguration wifiConfig_2g = softApConfig_2g.toWifiConfiguration();
586         assertThat(wifiConfig_2g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
587         assertThat(wifiConfig_2g.preSharedKey).isEqualTo("secretsecret");
588         assertThat(wifiConfig_2g.apBand).isEqualTo(WifiConfiguration.AP_BAND_2GHZ);
589         assertThat(wifiConfig_2g.apChannel).isEqualTo(11);
590         assertThat(wifiConfig_2g.hiddenSSID).isEqualTo(true);
591 
592         SoftApConfiguration softApConfig_5g = new SoftApConfiguration.Builder()
593                 .setPassphrase("secretsecret",
594                         SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
595                 .setChannel(149, SoftApConfiguration.BAND_5GHZ)
596                 .setHiddenSsid(true)
597                 .build();
598         WifiConfiguration wifiConfig_5g = softApConfig_5g.toWifiConfiguration();
599         assertThat(wifiConfig_5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
600         assertThat(wifiConfig_5g.preSharedKey).isEqualTo("secretsecret");
601         assertThat(wifiConfig_5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_5GHZ);
602         assertThat(wifiConfig_5g.apChannel).isEqualTo(149);
603         assertThat(wifiConfig_5g.hiddenSSID).isEqualTo(true);
604 
605         SoftApConfiguration softApConfig_2g5g = new SoftApConfiguration.Builder()
606                 .setPassphrase("secretsecret",
607                         SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
608                 .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
609                 .setHiddenSsid(true)
610                 .build();
611         WifiConfiguration wifiConfig_2g5g = softApConfig_2g5g.toWifiConfiguration();
612         assertThat(wifiConfig_2g5g.getAuthType()).isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
613         assertThat(wifiConfig_2g5g.preSharedKey).isEqualTo("secretsecret");
614         assertThat(wifiConfig_2g5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_ANY);
615         assertThat(wifiConfig_2g5g.apChannel).isEqualTo(0);
616         assertThat(wifiConfig_2g5g.hiddenSSID).isEqualTo(true);
617 
618         SoftApConfiguration softApConfig_sae_transition = new SoftApConfiguration.Builder()
619                 .setPassphrase("secretsecret",
620                 SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
621                 .build();
622 
623         WifiConfiguration wifiConfig_sae_transition =
624                 softApConfig_sae_transition.toWifiConfiguration();
625         assertThat(wifiConfig_sae_transition.getAuthType())
626                 .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
627         assertThat(wifiConfig_sae_transition.preSharedKey).isEqualTo("secretsecret");
628     }
629 
630     @Test
testDualBands()631     public void testDualBands() {
632         assumeTrue(SdkLevel.isAtLeastS());
633         int[] dual_bands = new int[2];
634         dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
635         dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
636         SoftApConfiguration dual_bands_config = new SoftApConfiguration.Builder()
637                 .setSsid("ssid")
638                 .setBands(dual_bands)
639                 .build();
640         assertTrue(Arrays.equals(dual_bands, dual_bands_config.getBands()));
641         assertThat(dual_bands_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
642     }
643 
644     @Test
testDualChannels()645     public void testDualChannels() {
646         assumeTrue(SdkLevel.isAtLeastS());
647         int[] expected_dual_bands = new int[2];
648         expected_dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
649         expected_dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
650         SparseIntArray dual_channels = new SparseIntArray(2);
651         dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
652         dual_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
653         SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
654                 .setSsid("ssid")
655                 .setChannels(dual_channels)
656                 .build();
657         assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
658         assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
659         assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
660         assertThat(dual_channels_config.getChannel()).isEqualTo(2);
661 
662         // Test different parameters.
663         dual_channels.clear();
664         dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
665         dual_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, 0);
666         expected_dual_bands[0] = SoftApConfiguration.BAND_5GHZ;
667         expected_dual_bands[1] = SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
668         dual_channels_config = new SoftApConfiguration.Builder()
669                 .setSsid("ssid")
670                 .setChannels(dual_channels)
671                 .build();
672         assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
673         assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
674         assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
675         assertThat(dual_channels_config.getChannel()).isEqualTo(149);
676     }
677 
678     @Test
testInvalidBandWhenSetBands()679     public void testInvalidBandWhenSetBands() {
680         assumeTrue(SdkLevel.isAtLeastS());
681         boolean isIllegalArgumentExceptionHappened = false;
682         int[] dual_bands = new int[2];
683         dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
684         dual_bands[1] = -1;
685         try {
686             SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
687                     .setSsid("ssid")
688                     .setBands(dual_bands)
689                     .build();
690             isIllegalArgumentExceptionHappened = false;
691         } catch (IllegalArgumentException iae) {
692             isIllegalArgumentExceptionHappened = true;
693         }
694         assertTrue(isIllegalArgumentExceptionHappened);
695 
696         try {
697             SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
698                     .setSsid("ssid")
699                     .setBands(new int[0])
700                     .build();
701             isIllegalArgumentExceptionHappened = false;
702         } catch (IllegalArgumentException iae) {
703             isIllegalArgumentExceptionHappened = true;
704         }
705         assertTrue(isIllegalArgumentExceptionHappened);
706 
707         try {
708             SoftApConfiguration dual_channels_config = new SoftApConfiguration.Builder()
709                     .setSsid("ssid")
710                     .setBands(new int[3])
711                     .build();
712             isIllegalArgumentExceptionHappened = false;
713         } catch (IllegalArgumentException iae) {
714             isIllegalArgumentExceptionHappened = true;
715         }
716         assertTrue(isIllegalArgumentExceptionHappened);
717     }
718 
719     @Test
testInvalidConfigWhenSetChannels()720     public void testInvalidConfigWhenSetChannels() {
721         assumeTrue(SdkLevel.isAtLeastS());
722         boolean isIllegalArgumentExceptionHappened = false;
723         SparseIntArray invalid_channels = new SparseIntArray();
724         try {
725             SoftApConfiguration zero_channels_config = new SoftApConfiguration.Builder()
726                     .setSsid("ssid")
727                     .setChannels(invalid_channels)
728                     .build();
729             isIllegalArgumentExceptionHappened = false;
730         } catch (IllegalArgumentException iae) {
731             isIllegalArgumentExceptionHappened = true;
732         }
733         assertTrue(isIllegalArgumentExceptionHappened);
734 
735         try {
736             invalid_channels.clear();
737             invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
738             invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 11);
739             SoftApConfiguration invalid_band_channels_config = new SoftApConfiguration.Builder()
740                     .setSsid("ssid")
741                     .setChannels(invalid_channels)
742                     .build();
743             isIllegalArgumentExceptionHappened = false;
744         } catch (IllegalArgumentException iae) {
745             isIllegalArgumentExceptionHappened = true;
746         }
747         assertTrue(isIllegalArgumentExceptionHappened);
748 
749         try {
750             invalid_channels.clear();
751             invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
752             invalid_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ,
753                     149);
754             SoftApConfiguration invalid_dual_channels_config = new SoftApConfiguration.Builder()
755                     .setSsid("ssid")
756                     .setChannels(invalid_channels)
757                     .build();
758             isIllegalArgumentExceptionHappened = false;
759         } catch (IllegalArgumentException iae) {
760             isIllegalArgumentExceptionHappened = true;
761         }
762         assertTrue(isIllegalArgumentExceptionHappened);
763 
764         try {
765             invalid_channels.clear();
766             invalid_channels.put(SoftApConfiguration.BAND_2GHZ, 2);
767             invalid_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
768             invalid_channels.put(SoftApConfiguration.BAND_6GHZ, 2);
769             SoftApConfiguration three_channels_config = new SoftApConfiguration.Builder()
770                     .setSsid("ssid")
771                     .setChannels(invalid_channels)
772                     .build();
773             isIllegalArgumentExceptionHappened = false;
774         } catch (IllegalArgumentException iae) {
775             isIllegalArgumentExceptionHappened = true;
776         }
777         assertTrue(isIllegalArgumentExceptionHappened);
778     }
779 
780     @Test(expected = IllegalArgumentException.class)
testInvalidConfigWhenSet60GhzChannels()781     public void testInvalidConfigWhenSet60GhzChannels() throws Exception {
782         assumeTrue(SdkLevel.isAtLeastS());
783         SparseIntArray invalid_channels = new SparseIntArray();
784         invalid_channels.put(SoftApConfiguration.BAND_60GHZ, 99);
785         SoftApConfiguration config = new SoftApConfiguration.Builder()
786                 .setSsid("ssid")
787                 .setChannels(invalid_channels)
788                 .build();
789     }
790 
791     @Test(expected = IllegalArgumentException.class)
testInvalidVendorElementsID()792     public void testInvalidVendorElementsID() {
793         assumeTrue(SdkLevel.isAtLeastT());
794         SoftApConfiguration original = new SoftApConfiguration.Builder()
795                 .setVendorElements(TEST_TWO_VENDOR_ELEMENTS_INVALID)
796                 .build();
797     }
798 
799     @Test(expected = IllegalArgumentException.class)
testInvalidVendorElementsDuplicate()800     public void testInvalidVendorElementsDuplicate() {
801         assumeTrue(SdkLevel.isAtLeastT());
802         List<ScanResult.InformationElement> dupElements = new ArrayList<>(TEST_TWO_VENDOR_ELEMENTS);
803         dupElements.addAll(TEST_TWO_VENDOR_ELEMENTS);
804         SoftApConfiguration original = new SoftApConfiguration.Builder()
805                 .setVendorElements(dupElements)
806                 .build();
807     }
808 
809     @Test(expected = IllegalArgumentException.class)
testThrowsExceptionWhenBssidSetButMacRandomizationSettingIsPersistent()810     public void testThrowsExceptionWhenBssidSetButMacRandomizationSettingIsPersistent() {
811         assumeTrue(SdkLevel.isAtLeastS());
812         MacAddress testBssid = MacAddress.fromString(TEST_BSSID);
813         SoftApConfiguration config_setBssidAfterSetMacRandomizationSettingToPersistent =
814                 new SoftApConfiguration.Builder()
815                 .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_PERSISTENT)
816                 .setBssid(testBssid)
817                 .build();
818     }
819 
820     @Test(expected = IllegalArgumentException.class)
testThrowsExceptionWhenBssidSetButMacRandomizationSettingIsNonPersistent()821     public void testThrowsExceptionWhenBssidSetButMacRandomizationSettingIsNonPersistent() {
822         assumeTrue(SdkLevel.isAtLeastS());
823         MacAddress testBssid = MacAddress.fromString(TEST_BSSID);
824         SoftApConfiguration config_setBssidAfterSetMacRandomizationSettingToNonPersistent =
825                 new SoftApConfiguration.Builder()
826                 .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NON_PERSISTENT)
827                 .setBssid(testBssid)
828                 .build();
829     }
830 
831     @Test
testSetBssidSucceededWWithDisableMacRandomizationSetting()832     public void testSetBssidSucceededWWithDisableMacRandomizationSetting() {
833         assumeTrue(SdkLevel.isAtLeastS());
834         MacAddress testBssid = MacAddress.fromString(TEST_BSSID);
835         SoftApConfiguration config_setBssidAfterSetMacRandomizationSettingToNone =
836                 new SoftApConfiguration.Builder()
837                 .setMacRandomizationSetting(SoftApConfiguration.RANDOMIZATION_NONE)
838                 .setBssid(testBssid)
839                 .build();
840         assertEquals(config_setBssidAfterSetMacRandomizationSettingToNone.getBssid(),
841                 testBssid);
842     }
843 
844     @Test
testSetAllowedAcsChannels()845     public void testSetAllowedAcsChannels() throws Exception {
846         assumeTrue(SdkLevel.isAtLeastT());
847 
848         SoftApConfiguration config = new SoftApConfiguration.Builder()
849                 .build();
850         assertEquals(0, config.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ).length);
851         assertEquals(0, config.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ).length);
852         assertEquals(0, config.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ).length);
853 
854         int[] channels2g = {1, 6, 11};
855         int[] channels5g = {36, 149, 136};
856         int[] channels6g = {1, 2, 3};
857 
858         config = new SoftApConfiguration.Builder()
859                 .setAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ, channels2g)
860                 .setAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ, channels5g)
861                 .setAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ, channels6g)
862                 .build();
863         assertArrayEquals(channels2g, config.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ));
864         assertArrayEquals(channels5g, config.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ));
865         assertArrayEquals(channels6g, config.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ));
866     }
867 
868     @Test
testSetAllowedAcsChannelsInvalidValues()869     public void testSetAllowedAcsChannelsInvalidValues() throws Exception {
870         assumeTrue(SdkLevel.isAtLeastT());
871 
872         int[] channels2g = {1, 6, 11, 50};
873         int[] channels5g = {36, 7, 149, 800};
874         int[] channels6g = {1, 2, -1, 3};
875 
876         assertThrows(IllegalArgumentException.class,
877                 () -> new SoftApConfiguration.Builder()
878                         .setAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ, channels2g));
879         assertThrows(IllegalArgumentException.class,
880                 () -> new SoftApConfiguration.Builder()
881                         .setAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ, channels5g));
882         assertThrows(IllegalArgumentException.class,
883                 () -> new SoftApConfiguration.Builder()
884                         .setAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ, channels6g));
885     }
886 
887     @Test
testMaxChannelBandwidth()888     public void testMaxChannelBandwidth() throws Exception {
889         assumeTrue(SdkLevel.isAtLeastT());
890 
891         SoftApConfiguration config = new SoftApConfiguration.Builder()
892                 .build();
893         assertEquals(SoftApInfo.CHANNEL_WIDTH_AUTO, config.getMaxChannelBandwidth());
894 
895         config = new SoftApConfiguration.Builder()
896                 .setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_20MHZ)
897                 .build();
898         assertEquals(SoftApInfo.CHANNEL_WIDTH_20MHZ, config.getMaxChannelBandwidth());
899 
900         config = new SoftApConfiguration.Builder()
901                 .setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_AUTO)
902                 .build();
903         assertEquals(SoftApInfo.CHANNEL_WIDTH_AUTO, config.getMaxChannelBandwidth());
904 
905         // Invalid value
906         assertThrows(IllegalArgumentException.class,
907                 () -> new SoftApConfiguration.Builder()
908                         .setMaxChannelBandwidth(SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ));
909     }
910 
911     @Test
testVendorDataValid()912     public void testVendorDataValid() throws Exception {
913         assumeTrue(SdkLevel.isAtLeastV());
914 
915         // Default value should be an empty list.
916         SoftApConfiguration config = new SoftApConfiguration.Builder().build();
917         List<OuiKeyedData> retrievedVendorData = config.getVendorData();
918         assertNotNull(retrievedVendorData);
919         assertEquals(0, retrievedVendorData.size());
920 
921         List<OuiKeyedData> mockVendorData = Arrays.asList(mock(OuiKeyedData.class));
922         config = new SoftApConfiguration.Builder().setVendorData(mockVendorData).build();
923         assertTrue(mockVendorData.equals(config.getVendorData()));
924     }
925 
926     @Test
testVendorDataInvalid()927     public void testVendorDataInvalid() {
928         assumeTrue(SdkLevel.isAtLeastV());
929         SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
930         // Vendor data must be non-null, if provided.
931         assertThrows(IllegalArgumentException.class, () -> builder.setVendorData(null));
932     }
933 
934     @Test
testVendorDataParcelUnparcel()935     public void testVendorDataParcelUnparcel() {
936         assumeTrue(SdkLevel.isAtLeastV());
937 
938         int oui = 0x00112233;
939         String fieldKey = "fieldKey";
940         PersistableBundle bundle = new PersistableBundle();
941         bundle.putInt(fieldKey, 12345);
942 
943         OuiKeyedData ouiKeyedData = new OuiKeyedData.Builder(oui, bundle).build();
944         List<OuiKeyedData> vendorData = Arrays.asList(ouiKeyedData);
945         SoftApConfiguration config =
946                 new SoftApConfiguration.Builder().setVendorData(vendorData).build();
947 
948         SoftApConfiguration unparceled = parcelUnparcel(config);
949         assertThat(unparceled).isNotSameInstanceAs(config);
950         assertThat(unparceled).isEqualTo(config);
951         assertThat(unparceled.hashCode()).isEqualTo(config.hashCode());
952         OuiKeyedData unparceledOuiKeyedData = unparceled.getVendorData().get(0);
953         assertEquals(bundle.getInt(fieldKey), unparceledOuiKeyedData.getData().getInt(fieldKey));
954     }
955 }
956