1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wifi;
18
19import static org.hamcrest.CoreMatchers.not;
20import static org.junit.Assert.*;
21import static org.mockito.Mockito.*;
22
23import android.content.Context;
24import android.content.pm.UserInfo;
25import android.net.wifi.FakeKeys;
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiConfiguration.AuthAlgorithm;
28import android.net.wifi.WifiConfiguration.GroupCipher;
29import android.net.wifi.WifiConfiguration.KeyMgmt;
30import android.net.wifi.WifiConfiguration.PairwiseCipher;
31import android.net.wifi.WifiConfiguration.Protocol;
32import android.net.wifi.WifiEnterpriseConfig;
33import android.net.wifi.WifiEnterpriseConfig.Eap;
34import android.net.wifi.WifiEnterpriseConfig.Phase2;
35import android.net.wifi.WifiScanner;
36import android.os.Process;
37import android.os.UserHandle;
38import android.os.UserManager;
39import android.security.Credentials;
40import android.security.KeyStore;
41import android.support.test.InstrumentationRegistry;
42import android.test.suitebuilder.annotation.SmallTest;
43import android.text.TextUtils;
44import android.util.Log;
45import android.util.SparseArray;
46
47import com.android.server.net.DelayedDiskWrite;
48import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
49import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager;
50import com.android.server.wifi.hotspot2.pps.Credential;
51import com.android.server.wifi.hotspot2.pps.HomeSP;
52
53import org.junit.Before;
54import org.junit.Test;
55import org.mockito.Mock;
56import org.mockito.MockitoAnnotations;
57
58import java.io.ByteArrayInputStream;
59import java.io.ByteArrayOutputStream;
60import java.io.DataInputStream;
61import java.io.DataOutputStream;
62import java.io.EOFException;
63import java.io.File;
64import java.io.FileOutputStream;
65import java.io.IOException;
66import java.lang.reflect.Field;
67import java.math.BigInteger;
68import java.security.cert.CertificateEncodingException;
69import java.security.cert.X509Certificate;
70import java.util.ArrayDeque;
71import java.util.ArrayList;
72import java.util.Arrays;
73import java.util.BitSet;
74import java.util.Collection;
75import java.util.Collections;
76import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
80import java.util.Random;
81import java.util.Set;
82import java.util.TreeMap;
83
84/**
85 * Unit tests for {@link com.android.server.wifi.WifiConfigManager}.
86 */
87@SmallTest
88public class WifiConfigManagerTest {
89    private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
90            WifiConfigurationTestUtil.generateWifiConfig(
91                    0, 1000000, "\"red\"", true, true, null, null),
92            WifiConfigurationTestUtil.generateWifiConfig(
93                    1, 1000001, "\"green\"", true, true, "example.com", "Green"),
94            WifiConfigurationTestUtil.generateWifiConfig(
95                    2, 1100000, "\"blue\"", false, true, "example.org", "Blue"),
96            WifiConfigurationTestUtil.generateWifiConfig(
97                    3, 1200000, "\"cyan\"", false, true, null, null));
98
99    private static final int[] USER_IDS = {0, 10, 11};
100    private static final int MANAGED_PROFILE_USER_ID = 12;
101    private static final int MANAGED_PROFILE_PARENT_USER_ID = 0;
102    private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
103    static {
104        USER_PROFILES.put(0, Arrays.asList(new UserInfo(0, "Owner", 0),
105                new UserInfo(12, "Managed Profile", 0)));
106        USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
107        USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
108    }
109
110    private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>();
111    static {
112        for (int userId : USER_IDS) {
113            List<WifiConfiguration> configs = new ArrayList<>();
114            for (int i = 0; i < CONFIGS.size(); ++i) {
115                if (WifiConfigurationUtil.isVisibleToAnyProfile(CONFIGS.get(i),
116                        USER_PROFILES.get(userId))) {
117                    configs.add(CONFIGS.get(i));
118                }
119            }
120            VISIBLE_CONFIGS.put(userId, configs);
121        }
122    }
123
124    /**
125     * Set of WifiConfigs for HasEverConnected tests.
126     */
127    private static final int HAS_EVER_CONNECTED_USER = 20;
128    private static final WifiConfiguration BASE_HAS_EVER_CONNECTED_CONFIG =
129            WifiConfigurationTestUtil.generateWifiConfig(
130                    0, HAS_EVER_CONNECTED_USER, "testHasEverConnected", false, true, null, null, 0);
131
132    public static final String TAG = "WifiConfigManagerTest";
133    @Mock private Context mContext;
134    @Mock private WifiNative mWifiNative;
135    @Mock private FrameworkFacade mFrameworkFacade;
136    @Mock private UserManager mUserManager;
137    @Mock private DelayedDiskWrite mWriter;
138    @Mock private PasspointManagementObjectManager mMOManager;
139    @Mock private Clock mClock;
140    private WifiConfigManager mWifiConfigManager;
141    private ConfigurationMap mConfiguredNetworks;
142    public byte[] mNetworkHistoryBytes;
143    private MockKeyStore mMockKeyStore;
144    private KeyStore mKeyStore;
145
146    /**
147     * Called before each test
148     */
149    @Before
150    public void setUp() throws Exception {
151        MockitoAnnotations.initMocks(this);
152
153        final Context realContext = InstrumentationRegistry.getContext();
154        when(mContext.getPackageName()).thenReturn(realContext.getPackageName());
155        when(mContext.getResources()).thenReturn(realContext.getResources());
156        when(mContext.getPackageManager()).thenReturn(realContext.getPackageManager());
157
158        when(mUserManager.getProfiles(UserHandle.USER_SYSTEM))
159                .thenReturn(USER_PROFILES.get(UserHandle.USER_SYSTEM));
160
161        for (int userId : USER_IDS) {
162            when(mUserManager.getProfiles(userId)).thenReturn(USER_PROFILES.get(userId));
163        }
164
165        mMockKeyStore = new MockKeyStore();
166
167        mWifiConfigManager = new WifiConfigManager(mContext, mWifiNative, mFrameworkFacade, mClock,
168                mUserManager, mMockKeyStore.createMock());
169
170        final Field configuredNetworksField =
171                WifiConfigManager.class.getDeclaredField("mConfiguredNetworks");
172        configuredNetworksField.setAccessible(true);
173        mConfiguredNetworks = (ConfigurationMap) configuredNetworksField.get(mWifiConfigManager);
174
175        // Intercept writes to networkHistory.txt.
176        doAnswer(new AnswerWithArguments() {
177            public void answer(String filePath, DelayedDiskWrite.Writer writer) throws Exception {
178                final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
179                final DataOutputStream stream = new DataOutputStream(buffer);
180                writer.onWriteCalled(stream);
181                stream.close();
182                mNetworkHistoryBytes = buffer.toByteArray();
183            }}).when(mWriter).write(anyString(), (DelayedDiskWrite.Writer) anyObject());
184        final Field writerField = WifiConfigManager.class.getDeclaredField("mWriter");
185        writerField.setAccessible(true);
186        writerField.set(mWifiConfigManager, mWriter);
187        final Field networkHistoryField =
188                WifiConfigManager.class.getDeclaredField("mWifiNetworkHistory");
189        networkHistoryField.setAccessible(true);
190        WifiNetworkHistory wifiNetworkHistory =
191                (WifiNetworkHistory) networkHistoryField.get(mWifiConfigManager);
192        final Field networkHistoryWriterField =
193                WifiNetworkHistory.class.getDeclaredField("mWriter");
194        networkHistoryWriterField.setAccessible(true);
195        networkHistoryWriterField.set(wifiNetworkHistory, mWriter);
196
197        when(mMOManager.isEnabled()).thenReturn(true);
198        final Field moManagerField = WifiConfigManager.class.getDeclaredField("mMOManager");
199        moManagerField.setAccessible(true);
200        moManagerField.set(mWifiConfigManager, mMOManager);
201    }
202
203    private void switchUser(int newUserId) {
204        when(mUserManager.getProfiles(newUserId))
205                .thenReturn(USER_PROFILES.get(newUserId));
206        mWifiConfigManager.handleUserSwitch(newUserId);
207    }
208
209    private void switchUserToCreatorOrParentOf(WifiConfiguration config) {
210        final int creatorUserId = UserHandle.getUserId(config.creatorUid);
211        if (creatorUserId == MANAGED_PROFILE_USER_ID) {
212            switchUser(MANAGED_PROFILE_PARENT_USER_ID);
213        } else {
214            switchUser(creatorUserId);
215        }
216    }
217
218    private void addNetworks() throws Exception {
219        for (int i = 0; i < CONFIGS.size(); ++i) {
220            assertEquals(i, CONFIGS.get(i).networkId);
221            addNetwork(CONFIGS.get(i));
222        }
223    }
224
225    private void addNetwork(WifiConfiguration config) throws Exception {
226        final int originalUserId = mWifiConfigManager.getCurrentUserId();
227
228        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
229        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
230                .thenReturn(true);
231
232        switchUserToCreatorOrParentOf(config);
233        final WifiConfiguration configCopy = new WifiConfiguration(config);
234        int networkId = config.networkId;
235        config.networkId = -1;
236        when(mWifiNative.addNetwork()).thenReturn(networkId);
237        when(mWifiNative.getNetworkVariable(networkId, WifiConfiguration.ssidVarName))
238                .thenReturn(encodeConfigSSID(config));
239        mWifiConfigManager.saveNetwork(config, configCopy.creatorUid);
240
241        switchUser(originalUserId);
242    }
243
244    private String encodeConfigSSID(WifiConfiguration config) throws Exception {
245        return new BigInteger(1, config.SSID.substring(1, config.SSID.length() - 1)
246                .getBytes("UTF-8")).toString(16);
247    }
248
249    /**
250     * Verifies that getConfiguredNetworksSize() returns the number of network configurations
251     * visible to the current user.
252     */
253    @Test
254    public void testGetConfiguredNetworksSize() throws Exception {
255        addNetworks();
256        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
257            switchUser(entry.getKey());
258            assertEquals(entry.getValue().size(), mWifiConfigManager.getConfiguredNetworksSize());
259        }
260    }
261
262    private void verifyNetworkConfig(WifiConfiguration expectedConfig,
263            WifiConfiguration actualConfig) {
264        assertNotNull(actualConfig);
265        assertEquals(expectedConfig.SSID, actualConfig.SSID);
266        assertEquals(expectedConfig.FQDN, actualConfig.FQDN);
267        assertEquals(expectedConfig.providerFriendlyName,
268                actualConfig.providerFriendlyName);
269        assertEquals(expectedConfig.configKey(), actualConfig.configKey(false));
270    }
271
272    private void verifyNetworkConfigs(Collection<WifiConfiguration> expectedConfigs,
273            Collection<WifiConfiguration> actualConfigs) {
274        assertEquals(expectedConfigs.size(), actualConfigs.size());
275        for (WifiConfiguration expectedConfig : expectedConfigs) {
276            WifiConfiguration actualConfig = null;
277            // Find the network configuration to test (assume that |actualConfigs| contains them in
278            // undefined order).
279            for (final WifiConfiguration candidate : actualConfigs) {
280                if (candidate.networkId == expectedConfig.networkId) {
281                    actualConfig = candidate;
282                    break;
283                }
284            }
285            verifyNetworkConfig(expectedConfig, actualConfig);
286        }
287    }
288
289    /**
290     * Verifies that getConfiguredNetworksSize() returns the network configurations visible to the
291     * current user.
292     */
293    @Test
294    public void testGetConfiguredNetworks() throws Exception {
295        addNetworks();
296        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
297            switchUser(entry.getKey());
298            verifyNetworkConfigs(entry.getValue(), mWifiConfigManager.getSavedNetworks());
299        }
300    }
301
302    /**
303     * Verifies that getPrivilegedConfiguredNetworks() returns the network configurations visible to
304     * the current user.
305     */
306    @Test
307    public void testGetPrivilegedConfiguredNetworks() throws Exception {
308        addNetworks();
309        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
310            switchUser(entry.getKey());
311            verifyNetworkConfigs(entry.getValue(),
312                    mWifiConfigManager.getPrivilegedSavedNetworks());
313        }
314    }
315
316    /**
317     * Verifies that getWifiConfiguration(int netId) can be used to access network configurations
318     * visible to the current user only.
319     */
320    @Test
321    public void testGetWifiConfigurationByNetworkId() throws Exception {
322        addNetworks();
323        for (int userId : USER_IDS) {
324            switchUser(userId);
325            for (WifiConfiguration expectedConfig: CONFIGS) {
326                final WifiConfiguration actualConfig =
327                        mWifiConfigManager.getWifiConfiguration(expectedConfig.networkId);
328                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
329                        USER_PROFILES.get(userId))) {
330                    verifyNetworkConfig(expectedConfig, actualConfig);
331                } else {
332                    assertNull(actualConfig);
333                }
334            }
335        }
336    }
337
338    /**
339     * Verifies that getWifiConfiguration(String key) can be used to access network configurations
340     * visible to the current user only.
341     */
342    @Test
343    public void testGetWifiConfigurationByConfigKey() throws Exception {
344        addNetworks();
345        for (int userId : USER_IDS) {
346            switchUser(userId);
347            for (WifiConfiguration expectedConfig: CONFIGS) {
348                final WifiConfiguration actualConfig =
349                        mWifiConfigManager.getWifiConfiguration(expectedConfig.configKey());
350                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
351                        USER_PROFILES.get(userId))) {
352                    verifyNetworkConfig(expectedConfig, actualConfig);
353                } else {
354                    assertNull(actualConfig);
355                }
356            }
357        }
358    }
359
360    /**
361     * Verifies that enableAllNetworks() enables all temporarily disabled network configurations
362     * visible to the current user.
363     */
364    @Test
365    public void testEnableAllNetworks() throws Exception {
366        addNetworks();
367        for (int userId : USER_IDS) {
368            switchUser(userId);
369
370            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
371                final WifiConfiguration.NetworkSelectionStatus status =
372                        config.getNetworkSelectionStatus();
373                status.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus
374                        .NETWORK_SELECTION_TEMPORARY_DISABLED);
375                status.setNetworkSelectionDisableReason(
376                        WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE);
377                status.setDisableTime(System.currentTimeMillis() - 60 * 60 * 1000);
378            }
379
380            mWifiConfigManager.enableAllNetworks();
381
382            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
383                assertEquals(WifiConfigurationUtil.isVisibleToAnyProfile(config,
384                        USER_PROFILES.get(userId)),
385                        config.getNetworkSelectionStatus().isNetworkEnabled());
386            }
387        }
388    }
389
390    /**
391     * Verifies that selectNetwork() disables all network configurations visible to the current user
392     * except the selected one.
393     */
394    @Test
395    public void testSelectNetwork() throws Exception {
396        addNetworks();
397
398        for (int userId : USER_IDS) {
399            switchUser(userId);
400
401            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
402                // Enable all network configurations.
403                for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
404                    config2.status = WifiConfiguration.Status.ENABLED;
405                }
406
407                // Try to select a network configuration.
408                reset(mWifiNative);
409                when(mWifiNative.selectNetwork(config.networkId)).thenReturn(true);
410                final boolean success =
411                        mWifiConfigManager.selectNetwork(config, false, config.creatorUid);
412                if (!WifiConfigurationUtil.isVisibleToAnyProfile(config,
413                        USER_PROFILES.get(userId))) {
414                    // If the network configuration is not visible to the current user, verify that
415                    // nothing changed.
416                    assertFalse(success);
417                    verify(mWifiNative, never()).selectNetwork(anyInt());
418                    verify(mWifiNative, never()).enableNetwork(anyInt());
419                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
420                        assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
421                    }
422                } else {
423                    // If the network configuration is visible to the current user, verify that it
424                    // was enabled and all other network configurations visible to the user were
425                    // disabled.
426                    assertTrue(success);
427                    verify(mWifiNative).selectNetwork(config.networkId);
428                    verify(mWifiNative, never()).selectNetwork(intThat(not(config.networkId)));
429                    verify(mWifiNative, never()).enableNetwork(config.networkId);
430                    verify(mWifiNative, never()).enableNetwork(intThat(not(config.networkId)));
431                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
432                        if (WifiConfigurationUtil.isVisibleToAnyProfile(config2,
433                                USER_PROFILES.get(userId))
434                                && config2.networkId != config.networkId) {
435                            assertEquals(WifiConfiguration.Status.DISABLED, config2.status);
436                        } else {
437                            assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
438                        }
439                    }
440                }
441            }
442        }
443    }
444
445    /**
446     * Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
447     * variables and the networkHistory.txt file.
448     * TODO: Test all variables. Currently, only the following variables are tested:
449     * - In the wpa_supplicant: "ssid", "id_str"
450     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
451     */
452    private void verifySaveNetwork(int network) throws Exception {
453        // Switch to the correct user.
454        switchUserToCreatorOrParentOf(CONFIGS.get(network));
455
456        // Set up wpa_supplicant.
457        when(mWifiNative.addNetwork()).thenReturn(0);
458        when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
459                .thenReturn(true);
460        when(mWifiNative.setNetworkExtra(eq(network), anyString(),
461                (Map<String, String>) anyObject())).thenReturn(true);
462        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
463                .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
464        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.pmfVarName))
465                .thenReturn("");
466
467        // Store a network configuration.
468        mWifiConfigManager.saveNetwork(CONFIGS.get(network), CONFIGS.get(network).creatorUid);
469
470        // Verify that wpa_supplicant variables were written correctly for the network
471        // configuration.
472        final Map<String, String> metadata = new HashMap<String, String>();
473        if (CONFIGS.get(network).FQDN != null) {
474            metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(network).FQDN);
475        }
476        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(network).configKey());
477        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
478                Integer.toString(CONFIGS.get(network).creatorUid));
479        verify(mWifiNative).setNetworkExtra(network, WifiConfigStore.ID_STRING_VAR_NAME,
480                metadata);
481
482        // Verify that an attempt to read back the requirePMF variable was made.
483        verify(mWifiNative).getNetworkVariable(network, WifiConfiguration.pmfVarName);
484
485        // Verify that no wpa_supplicant variables were read or written for any other network
486        // configurations.
487        verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
488                (Map<String, String>) anyObject());
489        verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
490                anyString());
491        verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
492
493        // Parse networkHistory.txt.
494        assertNotNull(mNetworkHistoryBytes);
495        final DataInputStream stream =
496                new DataInputStream(new ByteArrayInputStream(mNetworkHistoryBytes));
497        List<String> keys = new ArrayList<>();
498        List<String> values = new ArrayList<>();
499        try {
500            while (true) {
501                final String[] tokens = stream.readUTF().split(":", 2);
502                if (tokens.length == 2) {
503                    keys.add(tokens[0].trim());
504                    values.add(tokens[1].trim());
505                }
506            }
507        } catch (EOFException e) {
508            // Ignore. This is expected.
509        }
510
511        // Verify that a networkHistory.txt entry was written correctly for the network
512        // configuration.
513        assertTrue(keys.size() >= 3);
514        assertEquals(WifiNetworkHistory.CONFIG_KEY, keys.get(0));
515        assertEquals(CONFIGS.get(network).configKey(), values.get(0));
516        final int creatorUidIndex = keys.indexOf(WifiNetworkHistory.CREATOR_UID_KEY);
517        assertTrue(creatorUidIndex != -1);
518        assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
519                values.get(creatorUidIndex));
520        final int sharedIndex = keys.indexOf(WifiNetworkHistory.SHARED_KEY);
521        assertTrue(sharedIndex != -1);
522        assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
523
524        // Verify that no networkHistory.txt entries were written for any other network
525        // configurations.
526        final int lastConfigIndex = keys.lastIndexOf(WifiNetworkHistory.CONFIG_KEY);
527        assertEquals(0, lastConfigIndex);
528    }
529
530    /**
531     * Verifies that saveNetwork() correctly stores a regular network configuration.
532     */
533    @Test
534    public void testSaveNetworkRegular() throws Exception {
535        verifySaveNetwork(0);
536    }
537
538    /**
539     * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
540     */
541    @Test
542    public void testSaveNetworkHotspot20() throws Exception {
543        verifySaveNetwork(1);
544    }
545
546    /**
547     * Verifies that saveNetwork() correctly stores a private network configuration.
548     */
549    @Test
550    public void testSaveNetworkPrivate() throws Exception {
551        verifySaveNetwork(2);
552    }
553
554    /**
555     * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
556     * networkHistory.txt file and the MOManager, correlating the three sources based on the
557     * configKey and the FQDN for HotSpot 2.0 networks.
558     * TODO: Test all variables. Currently, only the following variables are tested:
559     * - In the wpa_supplicant: "ssid", "id_str"
560     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
561     */
562    @Test
563    public void testLoadConfiguredNetworks() throws Exception {
564        // Set up list of network configurations returned by wpa_supplicant.
565        final String header = "network id / ssid / bssid / flags";
566        String networks = header;
567        for (WifiConfiguration config : CONFIGS) {
568            networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
569        }
570        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
571        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
572
573        // Set up variables returned by wpa_supplicant for the individual network configurations.
574        for (int i = 0; i < CONFIGS.size(); ++i) {
575            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
576                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
577        }
578        // Legacy regular network configuration: No "id_str".
579        when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
580            .thenReturn(null);
581        // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
582        when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
583            .thenReturn(null);
584        when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
585            .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
586        // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str".
587        Map<String, String> metadata = new HashMap<String, String>();
588        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
589        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
590                Integer.toString(CONFIGS.get(2).creatorUid));
591        metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
592        when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
593            .thenReturn(metadata);
594        // Up-to-date regular network configuration: Metadata in "id_str".
595        metadata = new HashMap<String, String>();
596        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey());
597        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
598                Integer.toString(CONFIGS.get(3).creatorUid));
599        when(mWifiNative.getNetworkExtra(3, WifiConfigStore.ID_STRING_VAR_NAME))
600            .thenReturn(metadata);
601
602        // Set up networkHistory.txt file.
603        final File file = File.createTempFile("networkHistory.txt", null);
604        file.deleteOnExit();
605
606        Field wifiNetworkHistoryConfigFile =
607                WifiNetworkHistory.class.getDeclaredField("NETWORK_HISTORY_CONFIG_FILE");
608        wifiNetworkHistoryConfigFile.setAccessible(true);
609        wifiNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
610
611        final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
612        for (WifiConfiguration config : CONFIGS) {
613            stream.writeUTF(WifiNetworkHistory.CONFIG_KEY + ":  " + config.configKey() + '\n');
614            stream.writeUTF(WifiNetworkHistory.CREATOR_UID_KEY + ":  "
615                    + Integer.toString(config.creatorUid) + '\n');
616            stream.writeUTF(WifiNetworkHistory.SHARED_KEY + ":  "
617                    + Boolean.toString(config.shared) + '\n');
618        }
619        stream.close();
620
621        // Set up list of home service providers returned by MOManager.
622        final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
623        for (WifiConfiguration config : CONFIGS) {
624            if (config.FQDN != null) {
625                homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
626                        new HashSet<String>(),
627                        new HashSet<Long>(), new ArrayList<Long>(),
628                        config.providerFriendlyName, null,
629                        new Credential(0, 0, null, false, null, null),
630                        null, 0, null, null, null, 0));
631            }
632        }
633        when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
634
635        // Load network configurations.
636        mWifiConfigManager.loadConfiguredNetworks();
637
638        // Verify that network configurations were loaded and correlated correctly across the three
639        // sources.
640        verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
641    }
642
643    /**
644     * Verifies that loadConfiguredNetworks() correctly handles duplicates when reading network
645     * configurations from the wpa_supplicant: The second configuration overwrites the first.
646     */
647    @Test
648    public void testLoadConfiguredNetworksEliminatesDuplicates() throws Exception {
649        final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(0));
650        config.networkId = 1;
651
652        // Set up list of network configurations returned by wpa_supplicant. The two configurations
653        // are identical except for their network IDs.
654        final String header = "network id / ssid / bssid / flags";
655        final String networks =
656                header + "\n0\t" + config.SSID + "\tany\n1\t" + config.SSID + "\tany";
657        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
658        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
659
660        // Set up variables returned by wpa_supplicant.
661        when(mWifiNative.getNetworkVariable(anyInt(), eq(WifiConfiguration.ssidVarName)))
662            .thenReturn(encodeConfigSSID(config));
663        final Map<String, String> metadata = new HashMap<String, String>();
664        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, config.configKey());
665        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
666                Integer.toString(config.creatorUid));
667        when(mWifiNative.getNetworkExtra(anyInt(), eq(WifiConfigStore.ID_STRING_VAR_NAME)))
668            .thenReturn(metadata);
669
670        // Load network configurations.
671        mWifiConfigManager.loadConfiguredNetworks();
672
673        // Verify that the second network configuration (network ID 1) overwrote the first (network
674        // ID 0).
675        verifyNetworkConfigs(Arrays.asList(config), mConfiguredNetworks.valuesForAllUsers());
676    }
677
678    /**
679     * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
680     * configurations that should no longer be visible and enables network configurations that
681     * should become visible.
682     */
683    private void verifyHandleUserSwitch(int oldUserId, int newUserId,
684            boolean makeOneConfigEphemeral) throws Exception {
685        addNetworks();
686        switchUser(oldUserId);
687
688        reset(mWifiNative);
689        final Field lastSelectedConfigurationField =
690                WifiConfigManager.class.getDeclaredField("mLastSelectedConfiguration");
691        lastSelectedConfigurationField.setAccessible(true);
692        WifiConfiguration removedEphemeralConfig = null;
693        final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
694        final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
695        final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
696        final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
697        int expectedNumberOfConfigs = oldConfigs.size();
698        for (WifiConfiguration config : oldConfigs) {
699            if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) {
700                config.status = WifiConfiguration.Status.ENABLED;
701                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
702                        USER_PROFILES.get(newUserId))) {
703                    if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
704                        config.ephemeral = true;
705                        lastSelectedConfigurationField.set(mWifiConfigManager, config.configKey());
706                        removedEphemeralConfig = config;
707                    }
708                } else {
709                    oldUserOnlyConfigs.add(config);
710                }
711            } else {
712                config.status = WifiConfiguration.Status.DISABLED;
713                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
714                        USER_PROFILES.get(newUserId))) {
715                    newUserOnlyConfigs.add(config);
716                } else {
717                    neitherUserConfigs.add(config);
718                }
719            }
720        }
721
722        when(mWifiNative.disableNetwork(anyInt())).thenReturn(true);
723        when(mWifiNative.removeNetwork(anyInt())).thenReturn(true);
724
725        switchUser(newUserId);
726        if (makeOneConfigEphemeral) {
727            // Verify that the ephemeral network configuration was removed.
728            assertNotNull(removedEphemeralConfig);
729            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
730            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
731            verify(mWifiNative).removeNetwork(removedEphemeralConfig.networkId);
732            --expectedNumberOfConfigs;
733        } else {
734            assertNull(removedEphemeralConfig);
735        }
736
737        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
738        // appropriate.
739        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
740        assertEquals(expectedNumberOfConfigs, newConfigs.size());
741        for (WifiConfiguration config : newConfigs) {
742            if (oldUserOnlyConfigs.contains(config)) {
743                verify(mWifiNative).disableNetwork(config.networkId);
744                assertEquals(WifiConfiguration.Status.DISABLED, config.status);
745            } else {
746                verify(mWifiNative, never()).disableNetwork(config.networkId);
747                if (neitherUserConfigs.contains(config)) {
748                    assertEquals(WifiConfiguration.Status.DISABLED, config.status);
749                } else {
750                    // Only enabled in networkSelection.
751                    assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
752                }
753
754            }
755        }
756    }
757
758    /**
759     * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
760     * network configuration and reveals a private network configuration.
761     */
762    @Test
763    public void testHandleUserSwitchWithEphemeral() throws Exception {
764        verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
765    }
766
767    /**
768     * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
769     * network configuration.
770     */
771    @Test
772    public void testHandleUserSwitchWithoutEphemeral() throws Exception {
773        verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
774    }
775
776    @Test
777    public void testSaveLoadEapNetworks() {
778        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
779                .setPhase2(Phase2.MSCHAPV2)
780                .setIdentity("username", "password")
781                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0}));
782        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
783                .setPhase2(Phase2.MSCHAPV2)
784                .setIdentity("username", "password")
785                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1, FakeKeys.CA_CERT0}));
786
787    }
788
789    private void testSaveLoadSingleEapNetwork(String ssid, EnterpriseConfig eapConfig) {
790        final HashMap<String, String> networkVariables = new HashMap<String, String>();
791        reset(mWifiNative);
792        when(mWifiNative.addNetwork()).thenReturn(0);
793        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenAnswer(
794                new AnswerWithArguments() {
795                    public boolean answer(int netId, String name, String value) {
796                        // Verify that no wpa_supplicant variables were written for any other
797                        // network configurations.
798                        assertEquals(netId, 0);
799                        networkVariables.put(name, value);
800                        return true;
801                    }
802                });
803        when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
804                new AnswerWithArguments() {
805                    public String answer(int netId, String name) {
806                        // Verify that no wpa_supplicant variables were read for any other
807                        // network configurations.
808                        assertEquals(netId, 0);
809                        return networkVariables.get(name);
810                    }
811                });
812        when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
813                .thenReturn(true);
814
815        WifiConfiguration config = new WifiConfiguration();
816        config.SSID = ssid;
817        config.creatorUid = Process.WIFI_UID;
818        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
819        config.enterpriseConfig = eapConfig.enterpriseConfig;
820
821        // Store a network configuration.
822        mWifiConfigManager.saveNetwork(config, Process.WIFI_UID);
823
824        // Verify that wpa_supplicant variables were written correctly for the network
825        // configuration.
826        verify(mWifiNative).addNetwork();
827        assertEquals(eapConfig.eap,
828                unquote(networkVariables.get(WifiEnterpriseConfig.EAP_KEY)));
829        assertEquals(eapConfig.phase2,
830                unquote(networkVariables.get(WifiEnterpriseConfig.PHASE2_KEY)));
831        assertEquals(eapConfig.identity,
832                unquote(networkVariables.get(WifiEnterpriseConfig.IDENTITY_KEY)));
833        assertEquals(eapConfig.password,
834                unquote(networkVariables.get(WifiEnterpriseConfig.PASSWORD_KEY)));
835        assertSavedCaCerts(eapConfig,
836                unquote(networkVariables.get(WifiEnterpriseConfig.CA_CERT_KEY)));
837
838        // Prepare the scan result.
839        final String header = "network id / ssid / bssid / flags";
840        String networks = header + "\n" + Integer.toString(0) + "\t" + ssid + "\tany";
841        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
842        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
843
844        // Load back the configuration.
845        mWifiConfigManager.loadConfiguredNetworks();
846        List<WifiConfiguration> configs = mWifiConfigManager.getSavedNetworks();
847        assertEquals(1, configs.size());
848        WifiConfiguration loadedConfig = configs.get(0);
849        assertEquals(ssid, unquote(loadedConfig.SSID));
850        BitSet keyMgmt = new BitSet();
851        keyMgmt.set(KeyMgmt.WPA_EAP);
852        assertEquals(keyMgmt, loadedConfig.allowedKeyManagement);
853        assertEquals(eapConfig.enterpriseConfig.getEapMethod(),
854                loadedConfig.enterpriseConfig.getEapMethod());
855        assertEquals(eapConfig.enterpriseConfig.getPhase2Method(),
856                loadedConfig.enterpriseConfig.getPhase2Method());
857        assertEquals(eapConfig.enterpriseConfig.getIdentity(),
858                loadedConfig.enterpriseConfig.getIdentity());
859        assertEquals(eapConfig.enterpriseConfig.getPassword(),
860                loadedConfig.enterpriseConfig.getPassword());
861        asserCaCertsAliasesMatch(eapConfig.caCerts,
862                loadedConfig.enterpriseConfig.getCaCertificateAliases());
863    }
864
865    private String unquote(String value) {
866        if (value == null) {
867            return null;
868        }
869        int length = value.length();
870        if ((length > 1) && (value.charAt(0) == '"')
871                && (value.charAt(length - 1) == '"')) {
872            return value.substring(1, length - 1);
873        } else {
874            return value;
875        }
876    }
877
878    private void asserCaCertsAliasesMatch(X509Certificate[] certs, String[] aliases) {
879        assertEquals(certs.length, aliases.length);
880        List<String> aliasList = new ArrayList<String>(Arrays.asList(aliases));
881        try {
882            for (int i = 0; i < certs.length; i++) {
883                byte[] certPem = Credentials.convertToPem(certs[i]);
884                boolean found = false;
885                for (int j = 0; j < aliasList.size(); j++) {
886                    byte[] keystoreCert = mMockKeyStore.getKeyBlob(Process.WIFI_UID,
887                            Credentials.CA_CERTIFICATE + aliasList.get(j)).blob;
888                    if (Arrays.equals(keystoreCert, certPem)) {
889                        found = true;
890                        aliasList.remove(j);
891                        break;
892                    }
893                }
894                assertTrue(found);
895            }
896        } catch (CertificateEncodingException | IOException e) {
897            fail("Cannot convert CA certificate to encoded form.");
898        }
899    }
900
901    private void assertSavedCaCerts(EnterpriseConfig eapConfig, String caCertVariable) {
902        ArrayList<String> aliases = new ArrayList<String>();
903        if (TextUtils.isEmpty(caCertVariable)) {
904            // Do nothing.
905        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.CA_CERT_PREFIX)) {
906            aliases.add(caCertVariable.substring(WifiEnterpriseConfig.CA_CERT_PREFIX.length()));
907        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.KEYSTORES_URI)) {
908            String[] encodedAliases = TextUtils.split(
909                    caCertVariable.substring(WifiEnterpriseConfig.KEYSTORES_URI.length()),
910                    WifiEnterpriseConfig.CA_CERT_ALIAS_DELIMITER);
911            for (String encodedAlias : encodedAliases) {
912                String alias = WifiEnterpriseConfig.decodeCaCertificateAlias(encodedAlias);
913                assertTrue(alias.startsWith(Credentials.CA_CERTIFICATE));
914                aliases.add(alias.substring(Credentials.CA_CERTIFICATE.length()));
915            }
916        } else {
917            fail("Unrecognized ca_cert variable: " + caCertVariable);
918        }
919        asserCaCertsAliasesMatch(eapConfig.caCerts, aliases.toArray(new String[aliases.size()]));
920    }
921
922    private static class EnterpriseConfig {
923        public String eap;
924        public String phase2;
925        public String identity;
926        public String password;
927        public X509Certificate[] caCerts;
928        public WifiEnterpriseConfig enterpriseConfig;
929
930        public EnterpriseConfig(int eapMethod) {
931            enterpriseConfig = new WifiEnterpriseConfig();
932            enterpriseConfig.setEapMethod(eapMethod);
933            eap = Eap.strings[eapMethod];
934        }
935        public EnterpriseConfig setPhase2(int phase2Method) {
936            enterpriseConfig.setPhase2Method(phase2Method);
937            phase2 = "auth=" + Phase2.strings[phase2Method];
938            return this;
939        }
940        public EnterpriseConfig setIdentity(String identity, String password) {
941            enterpriseConfig.setIdentity(identity);
942            enterpriseConfig.setPassword(password);
943            this.identity = identity;
944            this.password = password;
945            return this;
946        }
947        public EnterpriseConfig setCaCerts(X509Certificate[] certs) {
948            enterpriseConfig.setCaCertificates(certs);
949            caCerts = certs;
950            return this;
951        }
952    }
953
954    /**
955     * Generates an array of unique random numbers below the specified maxValue.
956     * Values range from 0 to maxValue-1.
957     */
958    private static ArrayDeque<Integer> getUniqueRandomNumberValues(
959            int seed,
960            int maxValue,
961            int numValues) {
962        assertTrue(numValues <= maxValue);
963        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode() + seed);
964        ArrayDeque<Integer> randomNumberList = new ArrayDeque<>();
965        for (int i = 0; i < numValues; i++) {
966            int num = rand.nextInt(maxValue);
967            while (randomNumberList.contains(num)) {
968                num = rand.nextInt(maxValue);
969            }
970            randomNumberList.push(num);
971        }
972        return randomNumberList;
973    }
974
975    /**
976     * Verifies that the networks in pnoNetworkList is sorted in the same order as the
977     * network in expectedNetworkIDOrder list.
978     */
979    private static void verifyPnoNetworkListOrder(
980            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList,
981            ArrayList<Integer> expectedNetworkIdOrder) throws Exception  {
982        int i = 0;
983        for (WifiScanner.PnoSettings.PnoNetwork pnoNetwork : pnoNetworkList) {
984            Log.i(TAG, "PNO Network List Index: " + i + ", networkID: " + pnoNetwork.networkId);
985            assertEquals("Expected network ID: " + pnoNetwork.networkId,
986                    pnoNetwork.networkId, expectedNetworkIdOrder.get(i++).intValue());
987        }
988    }
989
990    /**
991     * Verifies the retrieveDisconnectedPnoNetworkList API. The test verifies that the list
992     * returned from the API is sorted as expected.
993     */
994    @Test
995    public void testDisconnectedPnoNetworkListCreation() throws Exception {
996        addNetworks();
997
998        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
999
1000        // First assign random |numAssociation| values and verify that the list is sorted
1001        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus
1002        // values constant.
1003        for (int userId : USER_IDS) {
1004            switchUser(userId);
1005            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1006                    new TreeMap<>(Collections.reverseOrder());
1007            ArrayDeque<Integer> numAssociationValues =
1008                    getUniqueRandomNumberValues(
1009                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1010            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1011                config.numAssociation = numAssociationValues.pop();
1012                config.priority = rand.nextInt(10000);
1013                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1014                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1015                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1016                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1017                        + config.numAssociation);
1018            }
1019            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1020                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1021            verifyPnoNetworkListOrder(pnoNetworkList,
1022                    new ArrayList(numAssociationToNetworkIdMap.values()));
1023        }
1024
1025        // Assign random |priority| values and verify that the list is sorted in descending order
1026        // of |priority| values. Keep numAssociation/NetworkSelectionStatus values constant.
1027        for (int userId : USER_IDS) {
1028            switchUser(userId);
1029            TreeMap<Integer, Integer> priorityToNetworkIdMap =
1030                    new TreeMap<>(Collections.reverseOrder());
1031            ArrayDeque<Integer> priorityValues =
1032                    getUniqueRandomNumberValues(
1033                            2, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1034            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1035                config.numAssociation = 0;
1036                config.priority = priorityValues.pop();
1037                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1038                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1039                priorityToNetworkIdMap.put(config.priority, config.networkId);
1040                Log.i(TAG, "networkID: " + config.networkId + ", priority: " + config.priority);
1041            }
1042            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1043                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1044            verifyPnoNetworkListOrder(pnoNetworkList,
1045                    new ArrayList(priorityToNetworkIdMap.values()));
1046        }
1047
1048        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1049        // ascending order of |NetworkSelectionStatus| values.
1050        for (int userId : USER_IDS) {
1051            switchUser(userId);
1052            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1053            ArrayDeque<Integer> networkSelectionStatusValues =
1054                    getUniqueRandomNumberValues(
1055                            3,
1056                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1057                            mConfiguredNetworks.valuesForCurrentUser().size());
1058            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1059                config.numAssociation = rand.nextInt(10000);
1060                config.priority = rand.nextInt(10000);
1061                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1062                        networkSelectionStatusValues.pop());
1063                networkSelectionStatusToNetworkIdMap.put(
1064                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1065                        config.networkId);
1066                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1067                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1068            }
1069            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1070                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1071            verifyPnoNetworkListOrder(pnoNetworkList,
1072                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1073        }
1074    }
1075
1076    /**
1077     * Verifies the retrieveConnectedPnoNetworkList API. The test verifies that the list
1078     * returned from the API is sorted as expected.
1079     */
1080    @Test
1081    public void testConnectedPnoNetworkListCreation() throws Exception {
1082        addNetworks();
1083
1084        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1085
1086        // First assign |lastSeen| values and verify that the list is sorted
1087        // in descending order of |lastSeen| values. Keep NetworkSelectionStatus
1088        // values constant.
1089        for (int userId : USER_IDS) {
1090            switchUser(userId);
1091            TreeMap<Boolean, Integer> lastSeenToNetworkIdMap =
1092                    new TreeMap<>(Collections.reverseOrder());
1093            ArrayDeque<Integer> lastSeenValues = getUniqueRandomNumberValues(1, 2, 2);
1094            if (mConfiguredNetworks.valuesForCurrentUser().size() > 2) continue;
1095            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1096                config.numAssociation = rand.nextInt(10000);
1097                config.priority = rand.nextInt(10000);
1098                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1099                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1100                boolean lastSeenValue = (lastSeenValues.pop()  == 1);
1101                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(
1102                        lastSeenValue);
1103                lastSeenToNetworkIdMap.put(lastSeenValue, config.networkId);
1104                Log.i(TAG, "networkID: " + config.networkId + ", lastSeen: " + lastSeenValue);
1105            }
1106            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1107                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1108            verifyPnoNetworkListOrder(pnoNetworkList,
1109                    new ArrayList(lastSeenToNetworkIdMap.values()));
1110        }
1111
1112        // Assign random |numAssociation| values and verify that the list is sorted
1113        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus/lastSeen
1114        // values constant.
1115        for (int userId : USER_IDS) {
1116            switchUser(userId);
1117            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1118                    new TreeMap<>(Collections.reverseOrder());
1119            ArrayDeque<Integer> numAssociationValues =
1120                    getUniqueRandomNumberValues(
1121                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1122            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1123                config.numAssociation = numAssociationValues.pop();
1124                config.priority = rand.nextInt(10000);
1125                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1126                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1127                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true);
1128                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1129                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1130                        + config.numAssociation);
1131            }
1132            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1133                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1134            verifyPnoNetworkListOrder(pnoNetworkList,
1135                    new ArrayList(numAssociationToNetworkIdMap.values()));
1136        }
1137
1138        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1139        // ascending order of |NetworkSelectionStatus| values.
1140        for (int userId : USER_IDS) {
1141            switchUser(userId);
1142            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1143            ArrayDeque<Integer> networkSelectionStatusValues =
1144                    getUniqueRandomNumberValues(
1145                            3,
1146                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1147                            mConfiguredNetworks.valuesForCurrentUser().size());
1148            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1149                config.numAssociation = rand.nextInt(10000);
1150                config.priority = rand.nextInt(10000);
1151                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1152                        networkSelectionStatusValues.pop());
1153                networkSelectionStatusToNetworkIdMap.put(
1154                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1155                        config.networkId);
1156                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1157                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1158            }
1159            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1160                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1161            verifyPnoNetworkListOrder(pnoNetworkList,
1162                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1163        }
1164    }
1165
1166    /**
1167     * Verifies that hasEverConnected is false for a newly added network
1168     */
1169    @Test
1170    public void testAddNetworkHasEverConnectedFalse() throws Exception {
1171        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1172        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1173                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1174        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1175                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1176    }
1177
1178
1179    /**
1180     * Verifies that hasEverConnected is false for a newly added network even when new config has
1181     * mistakenly set HasEverConnected to true.
1182    */
1183    @Test
1184    public void testAddNetworkOverridesHasEverConnectedWhenTrueInNewConfig() throws Exception {
1185        WifiConfiguration newNetworkWithHasEverConnectedTrue =
1186                new WifiConfiguration(BASE_HAS_EVER_CONNECTED_CONFIG);
1187        newNetworkWithHasEverConnectedTrue.getNetworkSelectionStatus().setHasEverConnected(true);
1188        addNetwork(newNetworkWithHasEverConnectedTrue);
1189        // check if addNetwork clears the bit.
1190        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1191                newNetworkWithHasEverConnectedTrue.networkId);
1192        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1193                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1194    }
1195
1196
1197    /**
1198     * Verify that setting HasEverConnected with a config update can be read back.
1199     */
1200    @Test
1201    public void testUpdateConfigToHasEverConnectedTrue() throws Exception {
1202        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1203
1204        // Get the newly saved config and update HasEverConnected
1205        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1206                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1207        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1208                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1209        checkConfig.getNetworkSelectionStatus().setHasEverConnected(true);
1210        mWifiConfigManager.addOrUpdateNetwork(checkConfig, HAS_EVER_CONNECTED_USER);
1211
1212        // verify that HasEverConnected was properly written and read back
1213        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1214    }
1215
1216
1217    /**
1218     * Verifies that hasEverConnected is cleared when a network config preSharedKey is updated.
1219     */
1220    @Test
1221    public void testUpdatePreSharedKeyClearsHasEverConnected() throws Exception {
1222        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1223
1224        testUpdateConfigToHasEverConnectedTrue();
1225
1226        WifiConfiguration original = mWifiConfigManager.getWifiConfiguration(
1227                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1228
1229        WifiConfiguration updatePreSharedKeyConfig = new WifiConfiguration();
1230        updatePreSharedKeyConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1231        updatePreSharedKeyConfig.SSID = original.SSID;
1232        updatePreSharedKeyConfig.preSharedKey = "newpassword";
1233        switchUserToCreatorOrParentOf(original);
1234        mWifiConfigManager.addOrUpdateNetwork(updatePreSharedKeyConfig,
1235                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1236
1237        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1238        switchUser(originalUserId);
1239    }
1240
1241    /**
1242     * Verifies that hasEverConnected is cleared when a network config allowedKeyManagement is
1243     * updated.
1244     */
1245    @Test
1246    public void testUpdateAllowedKeyManagementChanged() throws Exception {
1247        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1248
1249        testUpdateConfigToHasEverConnectedTrue();
1250
1251        WifiConfiguration updateAllowedKeyManagementConfig = new WifiConfiguration();
1252        updateAllowedKeyManagementConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1253        updateAllowedKeyManagementConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1254        updateAllowedKeyManagementConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
1255
1256        // Set up mock to allow the new value to be read back into the config
1257        String allowedKeyManagementString = makeString(
1258                updateAllowedKeyManagementConfig.allowedKeyManagement,
1259                    WifiConfiguration.KeyMgmt.strings);
1260        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1261                KeyMgmt.varName)).thenReturn(allowedKeyManagementString);
1262
1263        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1264        mWifiConfigManager.addOrUpdateNetwork(updateAllowedKeyManagementConfig,
1265                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1266
1267        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1268        switchUser(originalUserId);
1269    }
1270
1271    /**
1272     * Verifies that hasEverConnected is cleared when a network config allowedProtocols is
1273     * updated.
1274     */
1275    @Test
1276    public void testUpdateAllowedProtocolsChanged() throws Exception {
1277        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1278
1279        testUpdateConfigToHasEverConnectedTrue();
1280
1281        WifiConfiguration updateAllowedProtocolsConfig = new WifiConfiguration();
1282        updateAllowedProtocolsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1283        updateAllowedProtocolsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1284        updateAllowedProtocolsConfig.allowedProtocols.set(
1285                WifiConfiguration.Protocol.RSN);
1286
1287        // Set up mock to allow the new value to be read back into the config
1288        String allowedProtocolsString = makeString(
1289                updateAllowedProtocolsConfig.allowedProtocols,
1290                    WifiConfiguration.Protocol.strings);
1291        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1292                Protocol.varName)).thenReturn(allowedProtocolsString);
1293
1294        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1295        mWifiConfigManager.addOrUpdateNetwork(updateAllowedProtocolsConfig,
1296                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1297
1298        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1299        switchUser(originalUserId);
1300    }
1301
1302    /**
1303     * Verifies that hasEverConnected is cleared when a network config allowedAuthAlgorithms is
1304     * updated.
1305     */
1306    @Test
1307    public void testUpdateAllowedAuthAlgorithmsChanged() throws Exception {
1308        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1309
1310        testUpdateConfigToHasEverConnectedTrue();
1311
1312        WifiConfiguration updateAllowedAuthAlgorithmsConfig = new WifiConfiguration();
1313        updateAllowedAuthAlgorithmsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1314        updateAllowedAuthAlgorithmsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1315        updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms.set(
1316                WifiConfiguration.AuthAlgorithm.SHARED);
1317
1318        // Set up mock to allow the new value to be read back into the config
1319        String allowedAuthAlgorithmsString = makeString(
1320                updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms,
1321                    WifiConfiguration.AuthAlgorithm.strings);
1322        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1323                AuthAlgorithm.varName)).thenReturn(allowedAuthAlgorithmsString);
1324
1325        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1326        mWifiConfigManager.addOrUpdateNetwork(updateAllowedAuthAlgorithmsConfig,
1327                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1328
1329        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1330        switchUser(originalUserId);
1331    }
1332
1333    /**
1334     * Verifies that hasEverConnected is cleared when a network config allowedPairwiseCiphers is
1335     * updated.
1336     */
1337    @Test
1338    public void testUpdateAllowedPairwiseCiphersChanged() throws Exception {
1339        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1340
1341        testUpdateConfigToHasEverConnectedTrue();
1342
1343        WifiConfiguration updateAllowedPairwiseCiphersConfig = new WifiConfiguration();
1344        updateAllowedPairwiseCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1345        updateAllowedPairwiseCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1346        updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers.set(
1347                WifiConfiguration.PairwiseCipher.CCMP);
1348
1349        // Set up mock to allow the new value to be read back into the config
1350        String allowedPairwiseCiphersString = makeString(
1351                updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers,
1352                    WifiConfiguration.PairwiseCipher.strings);
1353        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1354                PairwiseCipher.varName)).thenReturn(allowedPairwiseCiphersString);
1355
1356        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1357        mWifiConfigManager.addOrUpdateNetwork(updateAllowedPairwiseCiphersConfig,
1358                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1359
1360        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1361        switchUser(originalUserId);
1362    }
1363
1364    /**
1365     * Verifies that hasEverConnected is cleared when a network config allowedGroupCiphers is
1366     * updated.
1367     */
1368    @Test
1369    public void testUpdateAllowedGroupCiphersChanged() throws Exception {
1370        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1371
1372        testUpdateConfigToHasEverConnectedTrue();
1373
1374        WifiConfiguration updateAllowedGroupCiphersConfig = new WifiConfiguration();
1375        updateAllowedGroupCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1376        updateAllowedGroupCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1377        updateAllowedGroupCiphersConfig.allowedGroupCiphers.set(
1378                WifiConfiguration.GroupCipher.CCMP);
1379
1380        // Set up mock to allow the new value to be read back into the config
1381        String allowedGroupCiphersString = makeString(
1382                updateAllowedGroupCiphersConfig.allowedGroupCiphers,
1383                    WifiConfiguration.GroupCipher.strings);
1384        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1385                GroupCipher.varName)).thenReturn(allowedGroupCiphersString);
1386
1387        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1388        mWifiConfigManager.addOrUpdateNetwork(updateAllowedGroupCiphersConfig,
1389                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1390
1391        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1392        switchUser(originalUserId);
1393    }
1394
1395    /**
1396     * Verifies that hasEverConnected is cleared when a network config wepKeys is
1397     * updated.
1398     */
1399    @Test
1400    public void testUpdateWepKeysChanged() throws Exception {
1401        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1402
1403        testUpdateConfigToHasEverConnectedTrue();
1404
1405        String tempKey = "hereisakey";
1406        WifiConfiguration updateWepKeysConfig = new WifiConfiguration();
1407        updateWepKeysConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1408        updateWepKeysConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1409        updateWepKeysConfig.wepKeys = new String[] {tempKey};
1410
1411        // Set up mock to allow the new value to be read back into the config
1412        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1413                WifiConfiguration.wepKeyVarNames[0])).thenReturn(tempKey);
1414
1415        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1416        mWifiConfigManager.addOrUpdateNetwork(updateWepKeysConfig,
1417                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1418
1419        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1420        switchUser(originalUserId);
1421    }
1422
1423    /**
1424     * Verifies that hasEverConnected is cleared when a network config hiddenSSID is
1425     * updated.
1426     */
1427    @Test
1428    public void testUpdateHiddenSSIDChanged() throws Exception {
1429        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1430
1431        testUpdateConfigToHasEverConnectedTrue();
1432
1433        WifiConfiguration updateHiddenSSIDConfig = new WifiConfiguration();
1434        updateHiddenSSIDConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1435        updateHiddenSSIDConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1436        updateHiddenSSIDConfig.hiddenSSID = true;
1437
1438        // Set up mock to allow the new value to be read back into the config
1439        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1440                WifiConfiguration.hiddenSSIDVarName)).thenReturn("1");
1441
1442        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1443        mWifiConfigManager.addOrUpdateNetwork(updateHiddenSSIDConfig,
1444                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1445
1446        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1447        switchUser(originalUserId);
1448    }
1449
1450    /**
1451     * Verifies that hasEverConnected is cleared when a network config pmfVarName is
1452     * updated.
1453     */
1454    @Test
1455    public void testUpdateRequirePMFChanged() throws Exception {
1456        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1457
1458        testUpdateConfigToHasEverConnectedTrue();
1459
1460        WifiConfiguration updateRequirePMFConfig = new WifiConfiguration();
1461        updateRequirePMFConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1462        updateRequirePMFConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1463        updateRequirePMFConfig.requirePMF = true;
1464
1465        // Set up mock to allow the new value to be read back into the config
1466        // TODO: please see b/28088226  - this test is implemented as if WifiConfigStore correctly
1467        // read back the boolean value.  When fixed, uncomment the following line and the
1468        // checkHasEverConnectedFalse below.
1469        //when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1470        //        WifiConfiguration.pmfVarName)).thenReturn("2");
1471
1472        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1473        mWifiConfigManager.addOrUpdateNetwork(updateRequirePMFConfig,
1474                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1475
1476        //checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1477        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1478        switchUser(originalUserId);
1479    }
1480
1481    /**
1482     * Verify WifiEnterpriseConfig changes are detected in WifiConfigManager.
1483     */
1484    @Test
1485    public void testEnterpriseConfigAdded() {
1486        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1487                .setPhase2(Phase2.MSCHAPV2)
1488                .setIdentity("username", "password")
1489                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1490
1491        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(null, eapConfig.enterpriseConfig));
1492    }
1493
1494    /**
1495     * Verify WifiEnterpriseConfig eap change is detected.
1496     */
1497    @Test
1498    public void testEnterpriseConfigEapChangeDetected() {
1499        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS);
1500        EnterpriseConfig peapConfig = new EnterpriseConfig(Eap.PEAP);
1501
1502        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1503                peapConfig.enterpriseConfig));
1504    }
1505
1506    /**
1507     * Verify WifiEnterpriseConfig phase2 method change is detected.
1508     */
1509    @Test
1510    public void testEnterpriseConfigPhase2ChangeDetected() {
1511        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.MSCHAPV2);
1512        EnterpriseConfig papConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.PAP);
1513
1514        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1515                papConfig.enterpriseConfig));
1516    }
1517
1518    /**
1519     * Verify WifiEnterpriseConfig added Certificate is detected.
1520     */
1521    @Test
1522    public void testCaCertificateAddedDetected() {
1523        EnterpriseConfig eapConfigNoCerts =  new EnterpriseConfig(Eap.TTLS)
1524                .setPhase2(Phase2.MSCHAPV2)
1525                .setIdentity("username", "password");
1526
1527        EnterpriseConfig eapConfig1Cert =  new EnterpriseConfig(Eap.TTLS)
1528                .setPhase2(Phase2.MSCHAPV2)
1529                .setIdentity("username", "password")
1530                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1531
1532        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfigNoCerts.enterpriseConfig,
1533                eapConfig1Cert.enterpriseConfig));
1534    }
1535
1536    /**
1537     * Verify WifiEnterpriseConfig Certificate change is detected.
1538     */
1539    @Test
1540    public void testDifferentCaCertificateDetected() {
1541        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1542                .setPhase2(Phase2.MSCHAPV2)
1543                .setIdentity("username", "password")
1544                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1545
1546        EnterpriseConfig eapConfigNewCert =  new EnterpriseConfig(Eap.TTLS)
1547                .setPhase2(Phase2.MSCHAPV2)
1548                .setIdentity("username", "password")
1549                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1});
1550
1551        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1552                eapConfigNewCert.enterpriseConfig));
1553    }
1554
1555    /**
1556     * Verify WifiEnterpriseConfig added Certificate changes are detected.
1557     */
1558    @Test
1559    public void testCaCertificateChangesDetected() {
1560        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1561                .setPhase2(Phase2.MSCHAPV2)
1562                .setIdentity("username", "password")
1563                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1564
1565        EnterpriseConfig eapConfigAddedCert =  new EnterpriseConfig(Eap.TTLS)
1566                .setPhase2(Phase2.MSCHAPV2)
1567                .setIdentity("username", "password")
1568                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1569
1570        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1571                eapConfigAddedCert.enterpriseConfig));
1572    }
1573
1574    /**
1575     * Verify that WifiEnterpriseConfig does not detect changes for identical configs.
1576     */
1577    @Test
1578    public void testWifiEnterpriseConfigNoChanges() {
1579        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1580                .setPhase2(Phase2.MSCHAPV2)
1581                .setIdentity("username", "password")
1582                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1583
1584        // Just to be clear that check is not against the same object
1585        EnterpriseConfig eapConfigSame =  new EnterpriseConfig(Eap.TTLS)
1586                .setPhase2(Phase2.MSCHAPV2)
1587                .setIdentity("username", "password")
1588                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1589
1590        assertFalse(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1591                eapConfigSame.enterpriseConfig));
1592    }
1593
1594
1595    private void checkHasEverConnectedTrue(int networkId) {
1596        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(networkId);
1597        assertTrue("hasEverConnected expected to be true.",
1598                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1599    }
1600
1601    private void checkHasEverConnectedFalse(int networkId) {
1602        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(networkId);
1603        assertFalse("Updating credentials network config should clear hasEverConnected.",
1604                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1605    }
1606
1607    /**
1608     *  Helper function to translate from WifiConfiguration BitSet to String.
1609     */
1610    private static String makeString(BitSet set, String[] strings) {
1611        StringBuffer buf = new StringBuffer();
1612        int nextSetBit = -1;
1613
1614        /* Make sure all set bits are in [0, strings.length) to avoid
1615         * going out of bounds on strings.  (Shouldn't happen, but...) */
1616        set = set.get(0, strings.length);
1617
1618        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
1619            buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
1620        }
1621
1622        // remove trailing space
1623        if (set.cardinality() > 0) {
1624            buf.setLength(buf.length() - 1);
1625        }
1626
1627        return buf.toString();
1628    }
1629
1630
1631}
1632