WifiStateMachineTest.java revision 9bd76b7c0afc90d800066397497b5947916b90fa
1/*
2 * Copyright (C) 2015 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.junit.Assert.assertEquals;
20import static org.junit.Assert.assertTrue;
21import static org.mockito.Mockito.any;
22import static org.mockito.Mockito.anyBoolean;
23import static org.mockito.Mockito.anyInt;
24import static org.mockito.Mockito.anyObject;
25import static org.mockito.Mockito.anyString;
26import static org.mockito.Mockito.mock;
27import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.when;
29import static org.mockito.Mockito.withSettings;
30
31import android.content.ContentResolver;
32import android.content.Context;
33import android.content.pm.PackageManager;
34import android.content.res.Resources;
35import android.net.BaseDhcpStateMachine;
36import android.net.ConnectivityManager;
37import android.net.DhcpResults;
38import android.net.DhcpStateMachine;
39import android.net.ip.IpManager;
40import android.net.wifi.ScanResult;
41import android.net.wifi.SupplicantState;
42import android.net.wifi.WifiConfiguration;
43import android.net.wifi.WifiManager;
44import android.net.wifi.WifiScanner;
45import android.net.wifi.WifiSsid;
46import android.net.wifi.p2p.IWifiP2pManager;
47import android.os.BatteryStats;
48import android.os.Handler;
49import android.os.HandlerThread;
50import android.os.IBinder;
51import android.os.IInterface;
52import android.os.INetworkManagementService;
53import android.os.IPowerManager;
54import android.os.Looper;
55import android.os.Message;
56import android.os.Messenger;
57import android.os.PowerManager;
58import android.os.UserHandle;
59import android.provider.Settings;
60import android.test.suitebuilder.annotation.SmallTest;
61import android.util.Log;
62
63import com.android.internal.R;
64import com.android.internal.app.IBatteryStats;
65import com.android.internal.util.AsyncChannel;
66import com.android.internal.util.IState;
67import com.android.internal.util.StateMachine;
68import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
69import com.android.server.wifi.hotspot2.NetworkDetail;
70import com.android.server.wifi.hotspot2.SupplicantBridge;
71import com.android.server.wifi.hotspot2.omadm.MOManager;
72import com.android.server.wifi.hotspot2.osu.OSUManager;
73import com.android.server.wifi.p2p.WifiP2pServiceImpl;
74
75import org.junit.After;
76import org.junit.Before;
77import org.junit.Test;
78import org.mockito.ArgumentCaptor;
79import org.mockito.Mock;
80import org.mockito.Mockito;
81import org.mockito.MockitoAnnotations;
82
83import java.io.ByteArrayOutputStream;
84import java.io.PrintWriter;
85import java.lang.reflect.Field;
86import java.lang.reflect.InvocationTargetException;
87import java.lang.reflect.Method;
88import java.util.ArrayList;
89import java.util.Arrays;
90import java.util.HashMap;
91import java.util.List;
92import java.util.Map;
93
94/**
95 * Unit tests for {@link com.android.server.wifi.WifiStateMachine}.
96 */
97@SmallTest
98public class WifiStateMachineTest {
99    public static final String TAG = "WifiStateMachineTest";
100
101    private static final String IFNAME = "wlan0";
102
103    private static <T> T mockWithInterfaces(Class<T> class1, Class<?>... interfaces) {
104        return mock(class1, withSettings().extraInterfaces(interfaces));
105    }
106
107    private static <T, I> IBinder mockService(Class<T> class1, Class<I> iface) {
108        T tImpl = mockWithInterfaces(class1, iface);
109        IBinder binder = mock(IBinder.class);
110        when(((IInterface) tImpl).asBinder()).thenReturn(binder);
111        when(binder.queryLocalInterface(iface.getCanonicalName()))
112                .thenReturn((IInterface) tImpl);
113        return binder;
114    }
115
116    private void enableDebugLogs() {
117        mWsm.enableVerboseLogging(1);
118    }
119
120    private static void installWlanWifiNative(WifiNative wifiNative) throws Exception {
121        Field field = WifiNative.class.getDeclaredField("wlanNativeInterface");
122        field.setAccessible(true);
123        field.set(null, wifiNative);
124
125        when(wifiNative.getInterfaceName()).thenReturn(IFNAME);
126    }
127
128    private class TestIpManager extends IpManager {
129        TestIpManager(Context context, String ifname, IpManager.Callback callback) {
130            // Call test-only superclass constructor.
131            super(ifname, callback);
132        }
133
134        @Override
135        public void startProvisioning() {}
136
137        @Override
138        public void stop() {}
139
140        @Override
141        public void confirmConfiguration() {}
142
143        @Override
144        public void updateWithDhcpResults(DhcpResults dhcpResults, int reason) {
145            if (dhcpResults != null) {
146                mCallback.onIPv4ProvisioningSuccess(dhcpResults, reason);
147            } else {
148                mCallback.onIPv4ProvisioningFailure(reason);
149            }
150        }
151    }
152
153    private FrameworkFacade getFrameworkFacade() throws InterruptedException {
154        FrameworkFacade facade = mock(FrameworkFacade.class);
155
156        when(facade.makeBaseLogger()).thenReturn(mock(BaseWifiLogger.class));
157        when(facade.getService(Context.NETWORKMANAGEMENT_SERVICE)).thenReturn(
158                mockWithInterfaces(IBinder.class, INetworkManagementService.class));
159
160        IBinder p2pBinder = mockService(WifiP2pServiceImpl.class, IWifiP2pManager.class);
161        when(facade.getService(Context.WIFI_P2P_SERVICE)).thenReturn(p2pBinder);
162
163        WifiP2pServiceImpl p2pm = (WifiP2pServiceImpl) p2pBinder.queryLocalInterface(
164                IWifiP2pManager.class.getCanonicalName());
165
166        final Object sync = new Object();
167        synchronized (sync) {
168            mP2pThread = new HandlerThread("WifiP2pMockThread") {
169                @Override
170                protected void onLooperPrepared() {
171                    synchronized (sync) {
172                        sync.notifyAll();
173                    }
174                }
175            };
176
177            mP2pThread.start();
178            sync.wait();
179        }
180
181        Handler handler = new Handler(mP2pThread.getLooper());
182        when(p2pm.getP2pStateMachineMessenger()).thenReturn(new Messenger(handler));
183
184        IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
185        when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
186
187        when(facade.makeOsuManager(any(WifiConfigStore.class), any(Context.class), any(
188                SupplicantBridge.class), any(MOManager.class), any(WifiStateMachine.class)))
189                .thenReturn(mock(OSUManager.class));
190
191        when(facade.makeDhcpStateMachine(
192                any(Context.class), any(StateMachine.class), any(String.class))).thenReturn(
193                mock(BaseDhcpStateMachine.class));
194
195        when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class)))
196                .then(new AnswerWithArguments<IpManager>() {
197                    public IpManager answer(
198                            Context context, String ifname, IpManager.Callback callback) {
199                        return new TestIpManager(context, ifname, callback);
200                    }
201                });
202
203        return facade;
204    }
205
206    private Context getContext() throws Exception {
207        PackageManager pkgMgr = mock(PackageManager.class);
208        when(pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
209
210        Context context = mock(Context.class);
211        when(context.getPackageManager()).thenReturn(pkgMgr);
212        when(context.getContentResolver()).thenReturn(mock(ContentResolver.class));
213
214        MockResources resources = new com.android.server.wifi.MockResources();
215        when(context.getResources()).thenReturn(resources);
216
217        ContentResolver cr = mock(ContentResolver.class);
218        when(context.getContentResolver()).thenReturn(cr);
219
220        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(
221                new PowerManager(context, mock(IPowerManager.class), new Handler()));
222
223        mAlarmManager = new MockAlarmManager();
224        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(
225                mAlarmManager.getAlarmManager());
226
227        when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(
228                mock(ConnectivityManager.class));
229
230        when(context.getSystemService(Context.WIFI_SCANNING_SERVICE)).thenReturn(mWifiScanner);
231
232        return context;
233    }
234
235    private Resources getMockResources() {
236        MockResources resources = new MockResources();
237        resources.setBoolean(R.bool.config_wifi_enable_wifi_firmware_debugging, false);
238        return resources;
239    }
240
241    private IState getCurrentState() throws
242            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
243        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
244        method.setAccessible(true);
245        return (IState) method.invoke(mWsm);
246    }
247
248    private static HandlerThread getWsmHandlerThread(WifiStateMachine wsm) throws
249            NoSuchFieldException, InvocationTargetException, IllegalAccessException {
250        Field field = StateMachine.class.getDeclaredField("mSmThread");
251        field.setAccessible(true);
252        return (HandlerThread) field.get(wsm);
253    }
254
255    private static void stopLooper(final Looper looper) throws Exception {
256        new Handler(looper).post(new Runnable() {
257            @Override
258            public void run() {
259                looper.quitSafely();
260            }
261        });
262    }
263
264    private void wait(int delayInMs) throws InterruptedException {
265        Looper looper = mWsmThread.getLooper();
266        final Handler handler = new Handler(looper);
267        synchronized (handler) {
268            handler.postDelayed(new Runnable() {
269                @Override
270                public void run() {
271                    synchronized (handler) {
272                        handler.notifyAll();
273                    }
274                }
275            }, delayInMs);
276
277            handler.wait();
278        }
279    }
280
281    private void dumpState() {
282        ByteArrayOutputStream stream = new ByteArrayOutputStream();
283        PrintWriter writer = new PrintWriter(stream);
284        mWsm.dump(null, writer, null);
285        writer.flush();
286        Log.d(TAG, "WifiStateMachine state -" + stream.toString());
287    }
288
289    private static ScanDetail getGoogleGuestScanDetail(int rssi) {
290        ScanResult.InformationElement ie[] = new ScanResult.InformationElement[1];
291        ie[0] = ScanResults.generateSsidIe(sSSID);
292        NetworkDetail nd = new NetworkDetail(sBSSID, ie, new ArrayList<String>(), sFreq);
293        ScanDetail detail = new ScanDetail(nd, sWifiSsid, sBSSID, "", rssi, sFreq,
294                Long.MAX_VALUE /* needed so that scan results aren't rejected because
295                                  there older than scan start */);
296        detail.getScanResult().informationElements = ie;
297        detail.getScanResult().anqpLines = new ArrayList<String>();
298        return detail;
299    }
300
301    private ScanResult[] getMockScanResults() {
302        ScanResults sr = ScanResults.create(0, 2412, 2437, 2462, 5180, 5220, 5745, 5825);
303        // copy generated results and add space on the end for one more
304        ScanResult[] results = Arrays.copyOf(sr.getScanData().getResults(),
305                sr.getScanData().getResults().length + 1);
306
307        int rssi = -65;
308        results[results.length - 1] = getGoogleGuestScanDetail(rssi).getScanResult();
309        return results;
310    }
311
312    static final String   sSSID = "\"GoogleGuest\"";
313    static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
314    static final String   sHexSSID = sWifiSsid.getHexString().replace("0x", "").replace("22", "");
315    static final String   sBSSID = "01:02:03:04:05:06";
316    static final int      sFreq = 2437;
317
318    WifiStateMachine mWsm;
319    HandlerThread mWsmThread;
320    HandlerThread mP2pThread;
321    HandlerThread mSyncThread;
322    AsyncChannel  mWsmAsyncChannel;
323    MockAlarmManager mAlarmManager;
324    MockWifiMonitor mWifiMonitor;
325
326    @Mock WifiNative mWifiNative;
327    @Mock WifiScanner mWifiScanner;
328    @Mock SupplicantStateTracker mSupplicantStateTracker;
329    @Mock WifiMetrics mWifiMetrics;
330
331    public WifiStateMachineTest() throws Exception {
332    }
333
334    @Before
335    public void setUp() throws Exception {
336        Log.d(TAG, "Setting up ...");
337
338        // Ensure looper exists
339        MockLooper looper = new MockLooper();
340
341        MockitoAnnotations.initMocks(this);
342
343        /** uncomment this to enable logs from WifiStateMachines */
344        // enableDebugLogs();
345
346        installWlanWifiNative(mWifiNative);
347        mWifiMonitor = new MockWifiMonitor();
348        mWifiMetrics = mock(WifiMetrics.class);
349        FrameworkFacade factory = getFrameworkFacade();
350        Context context = getContext();
351
352        Resources resources = getMockResources();
353        when(context.getResources()).thenReturn(resources);
354
355        when(factory.getIntegerSetting(context,
356                Settings.Global.WIFI_FREQUENCY_BAND,
357                WifiManager.WIFI_FREQUENCY_BAND_AUTO)).thenReturn(
358                WifiManager.WIFI_FREQUENCY_BAND_AUTO);
359
360        when(factory.makeApConfigStore(Mockito.eq(context), any(Handler.class)))
361                .thenCallRealMethod();
362
363        when(factory.makeSupplicantStateTracker(
364                any(Context.class), any(WifiStateMachine.class), any(WifiConfigStore.class),
365                any(Handler.class))).thenReturn(mSupplicantStateTracker);
366
367        mWsm = new WifiStateMachine(context, null, factory, mWifiMetrics);
368        mWsmThread = getWsmHandlerThread(mWsm);
369
370        final Object sync = new Object();
371        synchronized (sync) {
372            mSyncThread = new HandlerThread("SynchronizationThread");
373            final AsyncChannel channel = new AsyncChannel();
374            mSyncThread.start();
375            Handler handler = new Handler(mSyncThread.getLooper()) {
376                @Override
377                public void handleMessage(Message msg) {
378                    switch (msg.what) {
379                        case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
380                            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
381                                mWsmAsyncChannel = channel;
382                                synchronized (sync) {
383                                    sync.notifyAll();
384                                    Log.d(TAG, "Successfully connected " + this);
385                                }
386                            } else {
387                                Log.d(TAG, "Failed to connect Command channel " + this);
388                            }
389                            break;
390                        case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
391                            Log.d(TAG, "Command channel disconnected" + this);
392                            break;
393                    }
394                }
395            };
396
397            channel.connect(context, handler, mWsm.getMessenger());
398            sync.wait();
399        }
400
401        /* Now channel is supposed to be connected */
402    }
403
404    @After
405    public void cleanUp() throws Exception {
406
407        if (mSyncThread != null) stopLooper(mSyncThread.getLooper());
408        if (mWsmThread != null) stopLooper(mWsmThread.getLooper());
409        if (mP2pThread != null) stopLooper(mP2pThread.getLooper());
410
411        mWsmThread = null;
412        mP2pThread = null;
413        mSyncThread = null;
414        mWsmAsyncChannel = null;
415        mWsm = null;
416    }
417
418    @Test
419    public void createNew() throws Exception {
420        assertEquals("InitialState", getCurrentState().getName());
421
422        mWsm.sendMessage(WifiStateMachine.CMD_BOOT_COMPLETED);
423        wait(200);
424        assertEquals("InitialState", getCurrentState().getName());
425    }
426
427    @Test
428    public void loadComponents() throws Exception {
429
430        when(mWifiNative.loadDriver()).thenReturn(true);
431        when(mWifiNative.startHal()).thenReturn(true);
432        when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(true);
433
434        mWsm.setSupplicantRunning(true);
435        wait(200);
436        assertEquals("SupplicantStartingState", getCurrentState().getName());
437
438        when(mWifiNative.setBand(anyInt())).thenReturn(true);
439        when(mWifiNative.setDeviceName(anyString())).thenReturn(true);
440        when(mWifiNative.setManufacturer(anyString())).thenReturn(true);
441        when(mWifiNative.setModelName(anyString())).thenReturn(true);
442        when(mWifiNative.setModelNumber(anyString())).thenReturn(true);
443        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
444        when(mWifiNative.setConfigMethods(anyString())).thenReturn(true);
445        when(mWifiNative.setDeviceType(anyString())).thenReturn(true);
446        when(mWifiNative.setSerialNumber(anyString())).thenReturn(true);
447        when(mWifiNative.setScanningMacOui(any(byte[].class))).thenReturn(true);
448        when(mWifiNative.enableBackgroundScan(anyBoolean())).thenReturn(true);
449
450        mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
451        wait(200);
452        assertEquals("DisconnectedState", getCurrentState().getName());
453    }
454
455    @Test
456    public void loadComponentsFailure() throws Exception {
457        when(mWifiNative.loadDriver()).thenReturn(false);
458        when(mWifiNative.startHal()).thenReturn(false);
459        when(mWifiNative.startSupplicant(anyBoolean())).thenReturn(false);
460
461        mWsm.setSupplicantRunning(true);
462        wait(200);
463        assertEquals("InitialState", getCurrentState().getName());
464
465        when(mWifiNative.loadDriver()).thenReturn(true);
466        mWsm.setSupplicantRunning(true);
467        wait(200);
468        assertEquals("InitialState", getCurrentState().getName());
469
470        when(mWifiNative.startHal()).thenReturn(true);
471        mWsm.setSupplicantRunning(true);
472        wait(200);
473        assertEquals("InitialState", getCurrentState().getName());
474    }
475
476    @Test
477    public void addNetwork() throws Exception {
478
479        loadComponents();
480
481        final HashMap<String, String> nameToValue = new HashMap<String, String>();
482
483        when(mWifiNative.addNetwork()).thenReturn(0);
484        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString()))
485                .then(new AnswerWithArguments<Boolean>() {
486                    public boolean answer(int netId, String name, String value) {
487                        if (netId != 0) {
488                            Log.d(TAG, "Can't set var " + name + " for " + netId);
489                            return false;
490                        }
491
492                        Log.d(TAG, "Setting var " + name + " to " + value + " for " + netId);
493                        nameToValue.put(name, value);
494                        return true;
495                    }
496                });
497
498        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
499                .then(new AnswerWithArguments<Boolean>() {
500                        public boolean answer(int netId, String name, Map<String, String> values) {
501                            if (netId != 0) {
502                                Log.d(TAG, "Can't set extra " + name + " for " + netId);
503                                return false;
504                            }
505
506                            Log.d(TAG, "Setting extra for " + netId);
507                            return true;
508                        }
509                    });
510
511        when(mWifiNative.getNetworkVariable(anyInt(), anyString()))
512                .then(new AnswerWithArguments<String>() {
513                    public String answer(int netId, String name) throws Throwable {
514                        if (netId != 0) {
515                            Log.d(TAG, "Can't find var " + name + " for " + netId);
516                            return null;
517                        }
518                        String value = nameToValue.get(name);
519                        if (value != null) {
520                            Log.d(TAG, "Returning var " + name + " to " + value + " for " + netId);
521                        } else {
522                            Log.d(TAG, "Can't find var " + name + " for " + netId);
523                        }
524                        return value;
525                    }
526                });
527
528        WifiConfiguration config = new WifiConfiguration();
529        config.SSID = sSSID;
530        config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
531        mWsm.syncAddOrUpdateNetwork(mWsmAsyncChannel, config);
532        wait(200);
533
534        verify(mWifiNative).addNetwork();
535        verify(mWifiNative).setNetworkVariable(0, "ssid", sHexSSID);
536
537        List<WifiConfiguration> configs = mWsm.syncGetConfiguredNetworks(-1, mWsmAsyncChannel);
538        assertEquals(1, configs.size());
539
540        WifiConfiguration config2 = configs.get(0);
541        assertEquals("\"GoogleGuest\"", config2.SSID);
542        assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE));
543    }
544
545    @Test
546    public void scan() throws Exception {
547
548        addNetwork();
549
550        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
551
552        mWsm.startScan(-1, 0, null, null);
553        wait(200);
554
555        ArgumentCaptor<WifiScanner.ScanSettings> scanSettingsCaptor =
556                ArgumentCaptor.forClass(WifiScanner.ScanSettings.class);
557        ArgumentCaptor<WifiScanner.ScanListener> scanListenerCaptor =
558                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
559        verify(mWifiScanner).startScan(scanSettingsCaptor.capture(), scanListenerCaptor.capture());
560        assertEquals("band", WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
561                scanSettingsCaptor.getValue().band);
562        assertEquals("reportEvents", WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
563                | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
564                scanSettingsCaptor.getValue().reportEvents);
565
566        ScanResult[] results = getMockScanResults();
567        for (ScanResult result : results) {
568            scanListenerCaptor.getValue().onFullResult(result);
569        }
570        scanListenerCaptor.getValue().onResults(
571                new WifiScanner.ScanData[] {new WifiScanner.ScanData(0, 0, results)});
572
573        wait(200);
574        List<ScanResult> reportedResults = mWsm.syncGetScanResultsList();
575        assertEquals(8, reportedResults.size());
576    }
577
578    @Test
579    public void connect() throws Exception {
580
581        addNetwork();
582
583        mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
584        mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true);
585        wait(200);
586
587        verify(mWifiNative).enableNetwork(0, true);
588
589        mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
590        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
591                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
592        wait(200);
593
594        assertEquals("ObtainingIpState", getCurrentState().getName());
595
596        DhcpResults dhcpResults = new DhcpResults();
597        dhcpResults.setGateway("1.2.3.4");
598        dhcpResults.setIpAddress("192.168.1.100", 0);
599        dhcpResults.addDns("8.8.8.8");
600        dhcpResults.setLeaseDuration(3600);
601
602        mWsm.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION, DhcpStateMachine.DHCP_SUCCESS, 0,
603                dhcpResults);
604        wait(200);
605
606        assertEquals("ConnectedState", getCurrentState().getName());
607    }
608
609    @Test
610    public void disconnect() throws Exception {
611        connect();
612
613        mWsm.sendMessage(WifiMonitor.NETWORK_DISCONNECTION_EVENT, -1, 3, "01:02:03:04:05:06");
614        mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
615                new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.DISCONNECTED));
616        wait(200);
617
618        assertEquals("DisconnectedState", getCurrentState().getName());
619    }
620
621    @Test
622    public void handleUserSwitch() throws Exception {
623        assertEquals(UserHandle.USER_SYSTEM, mWsm.getCurrentUserId());
624
625        mWsm.handleUserSwitch(10);
626        wait(200);
627
628        assertEquals(10, mWsm.getCurrentUserId());
629    }
630}
631