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 com.android.server.wifi.WifiController.CMD_AP_STOPPED;
20import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
21import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
22import static com.android.server.wifi.WifiController.CMD_SET_AP;
23import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
24
25import static org.junit.Assert.assertEquals;
26import static org.mockito.Matchers.*;
27import static org.mockito.Mockito.*;
28
29import android.content.ContentResolver;
30import android.content.Context;
31import android.test.suitebuilder.annotation.SmallTest;
32import android.util.Log;
33
34import com.android.internal.util.IState;
35import com.android.internal.util.StateMachine;
36
37import org.junit.After;
38import org.junit.Before;
39import org.junit.Test;
40import org.mockito.InOrder;
41import org.mockito.Mock;
42import org.mockito.MockitoAnnotations;
43
44import java.io.ByteArrayOutputStream;
45import java.io.PrintWriter;
46import java.lang.reflect.Method;
47
48/**
49 * Test WifiController for changes in and out of ECM and SoftAP modes.
50 */
51@SmallTest
52public class WifiControllerTest {
53
54    private static final String TAG = "WifiControllerTest";
55
56    private void dumpState() {
57        ByteArrayOutputStream stream = new ByteArrayOutputStream();
58        PrintWriter writer = new PrintWriter(stream);
59        mWifiController.dump(null, writer, null);
60        writer.flush();
61        Log.d(TAG, "WifiStateMachine state -" + stream.toString());
62    }
63
64    private IState getCurrentState() throws Exception {
65        Method method = StateMachine.class.getDeclaredMethod("getCurrentState");
66        method.setAccessible(true);
67        return (IState) method.invoke(mWifiController);
68    }
69
70    private void initializeSettingsStore() throws Exception {
71        when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
72        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
73        when(mSettingsStore.isScanAlwaysAvailable()).thenReturn(true);
74    }
75
76    MockLooper mLooper;
77    @Mock Context mContext;
78    @Mock WifiServiceImpl mService;
79    @Mock FrameworkFacade mFacade;
80    @Mock WifiSettingsStore mSettingsStore;
81    @Mock WifiStateMachine mWifiStateMachine;
82    @Mock WifiServiceImpl.LockList mLockList;
83
84    WifiController mWifiController;
85
86    @Before
87    public void setUp() throws Exception {
88        MockitoAnnotations.initMocks(this);
89
90        mLooper = new MockLooper();
91
92        initializeSettingsStore();
93
94        when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
95
96        mWifiController = new WifiController(mContext, mWifiStateMachine,
97                mSettingsStore, mLockList, mLooper.getLooper(), mFacade);
98
99        mWifiController.start();
100        mLooper.dispatchAll();
101    }
102
103    @After
104    public void cleanUp() {
105        mLooper.dispatchAll();
106    }
107
108    @Test
109    public void enableWifi() throws Exception {
110        assertEquals("StaDisabledWithScanState", getCurrentState().getName());
111
112        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
113        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
114        mLooper.dispatchAll();
115        assertEquals("DeviceActiveState", getCurrentState().getName());
116
117        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
118        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
119        mLooper.dispatchAll();
120        assertEquals("StaDisabledWithScanState", getCurrentState().getName());
121
122        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
123        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
124        mLooper.dispatchAll();
125        assertEquals("DeviceActiveState", getCurrentState().getName());
126    }
127
128    @Test
129    public void testEcmOn() throws Exception {
130        enableWifi();
131
132        // Test with WifiDisableInECBM turned on:
133        when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(true);
134        doTestEcm(true);
135    }
136
137    @Test
138    public void testEcmOff() throws Exception {
139        enableWifi();
140
141        // Test with WifiDisableInECBM turned off
142        when(mFacade.getConfigWiFiDisableInECBM(mContext)).thenReturn(false);
143        doTestEcm(false);
144    }
145
146    private void assertInEcm(boolean ecmEnabled) throws Exception {
147        if (ecmEnabled) {
148            assertEquals("EcmState", getCurrentState().getName());
149        } else {
150            assertEquals("DeviceActiveState", getCurrentState().getName());
151        }
152    }
153
154
155    private void doTestEcm(boolean ecmEnabled) throws Exception {
156
157        // test ecm changed
158        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1);
159        mLooper.dispatchAll();
160        assertInEcm(ecmEnabled);
161
162        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0);
163        mLooper.dispatchAll();
164        assertEquals("DeviceActiveState", getCurrentState().getName());
165
166        // test call state changed
167        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
168        mLooper.dispatchAll();
169        assertInEcm(ecmEnabled);
170
171        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0);
172        mLooper.dispatchAll();
173        assertEquals("DeviceActiveState", getCurrentState().getName());
174
175
176        // test both changed (variation 1 - the good case)
177        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
178        mLooper.dispatchAll();
179        assertInEcm(ecmEnabled);
180
181        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1);
182        mLooper.dispatchAll();
183        assertInEcm(ecmEnabled);
184
185        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0);
186        mLooper.dispatchAll();
187        assertInEcm(ecmEnabled);
188
189        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0);
190        mLooper.dispatchAll();
191        assertEquals("DeviceActiveState", getCurrentState().getName());
192
193        // test both changed (variation 2 - emergency call in ecm)
194        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1);
195        mLooper.dispatchAll();
196        assertInEcm(ecmEnabled);
197
198        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
199        mLooper.dispatchAll();
200        assertInEcm(ecmEnabled);
201
202        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0);
203        mLooper.dispatchAll();
204        assertInEcm(ecmEnabled);
205
206        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0);
207        mLooper.dispatchAll();
208        assertEquals("DeviceActiveState", getCurrentState().getName());
209
210        // test both changed (variation 3 - not so good order of events)
211        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
212        mLooper.dispatchAll();
213        assertInEcm(ecmEnabled);
214
215        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 1);
216        mLooper.dispatchAll();
217        assertInEcm(ecmEnabled);
218
219        mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, 0);
220        mLooper.dispatchAll();
221        assertInEcm(ecmEnabled);
222
223        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0);
224        mLooper.dispatchAll();
225        assertEquals("DeviceActiveState", getCurrentState().getName());
226
227        // test that Wifi toggle doesn't exit Ecm
228        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 1);
229        mLooper.dispatchAll();
230        assertInEcm(ecmEnabled);
231
232        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
233        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
234        mLooper.dispatchAll();
235        assertInEcm(ecmEnabled);
236
237        mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, 0);
238        mLooper.dispatchAll();
239        assertEquals("DeviceActiveState", getCurrentState().getName());
240    }
241
242    /**
243     * When AP mode is enabled and wifi was previously in AP mode, we should return to
244     * DeviceActiveState after the AP is disabled.
245     * Enter DeviceActiveState, activate AP mode, disable AP mode.
246     * <p>
247     * Expected: AP should successfully start and exit, then return to DeviceActiveState.
248     */
249    @Test
250    public void testReturnToDeviceActiveStateAfterAPModeShutdown() throws Exception {
251        enableWifi();
252        assertEquals("DeviceActiveState", getCurrentState().getName());
253
254        mWifiController.obtainMessage(CMD_SET_AP, 1, 0).sendToTarget();
255        mLooper.dispatchAll();
256        assertEquals("ApEnabledState", getCurrentState().getName());
257
258        when(mSettingsStore.getWifiSavedState()).thenReturn(1);
259        mWifiController.obtainMessage(CMD_AP_STOPPED).sendToTarget();
260        mLooper.dispatchAll();
261
262        InOrder inOrder = inOrder(mWifiStateMachine);
263        inOrder.verify(mWifiStateMachine).setSupplicantRunning(true);
264        inOrder.verify(mWifiStateMachine).setOperationalMode(WifiStateMachine.CONNECT_MODE);
265        inOrder.verify(mWifiStateMachine).setDriverStart(true);
266        assertEquals("DeviceActiveState", getCurrentState().getName());
267    }
268}
269