1package com.android.systemui.statusbar.policy;
2
3import android.content.Intent;
4import android.net.NetworkBadging;
5import android.net.NetworkCapabilities;
6import android.net.NetworkInfo;
7import android.net.NetworkKey;
8import android.net.RssiCurve;
9import android.net.ScoredNetwork;
10import android.net.WifiKey;
11import android.net.wifi.WifiInfo;
12import android.net.wifi.WifiManager;
13import android.net.wifi.WifiNetworkScoreCache;
14import android.os.Bundle;
15import android.provider.Settings;
16import android.support.test.runner.AndroidJUnit4;
17import android.test.suitebuilder.annotation.SmallTest;
18
19import com.android.settingslib.Utils;
20import com.android.systemui.statusbar.policy.NetworkController.IconState;
21
22import org.junit.Test;
23import org.junit.runner.RunWith;
24import org.mockito.ArgumentCaptor;
25import org.mockito.Matchers;
26import org.mockito.Mockito;
27import org.mockito.invocation.InvocationOnMock;
28import org.mockito.stubbing.Answer;
29
30import static junit.framework.Assert.assertEquals;
31
32import static org.mockito.Matchers.any;
33import static org.mockito.Matchers.anyBoolean;
34import static org.mockito.Matchers.anyInt;
35import static org.mockito.Mockito.doAnswer;
36import static org.mockito.Mockito.mock;
37import static org.mockito.Mockito.verify;
38import static org.mockito.Mockito.when;
39
40import java.util.Arrays;
41import java.util.ArrayList;
42import java.util.List;
43import java.util.concurrent.CountDownLatch;
44import java.util.concurrent.TimeUnit;
45
46@SmallTest
47@RunWith(AndroidJUnit4.class)
48public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
49    // These match the constants in WifiManager and need to be kept up to date.
50    private static final int MIN_RSSI = -100;
51    private static final int MAX_RSSI = -55;
52
53    private static final int LATCH_TIMEOUT = 2000;
54    private static final String TEST_SSID = "\"Test SSID\"";
55    private static final String TEST_BSSID = "00:00:00:00:00:00";
56
57    private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
58    private CountDownLatch mRequestScoresLatch;
59
60    @Test
61    public void testWifiIcon() {
62        String testSsid = "Test SSID";
63        setWifiEnabled(true);
64        verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
65
66        setWifiState(true, testSsid);
67        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
68
69        for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
70            setWifiLevel(testLevel);
71
72            setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
73            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
74            setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true);
75            verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
76        }
77    }
78
79    @Test
80    public void testBadgedWifiIcon() throws Exception {
81        // TODO(sghuman): Refactor this setup code when creating a test for the badged QsIcon.
82        int testLevel = 1;
83        RssiCurve mockBadgeCurve = mock(RssiCurve.class);
84        Bundle attr = new Bundle();
85        attr.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve);
86        ScoredNetwork score =
87                new ScoredNetwork(
88                        new NetworkKey(new WifiKey(TEST_SSID, TEST_BSSID)),
89                        null,
90                        false /* meteredHint */,
91                        attr);
92
93        // Must set the Settings value before instantiating the NetworkControllerImpl due to bugs in
94        // TestableSettingsProvider.
95        Settings.Global.putString(mContext.getContentResolver(),
96                Settings.Global.NETWORK_SCORING_UI_ENABLED,
97                "1");
98        super.setUp(); // re-instantiate NetworkControllImpl now that setting has been updated
99        setupNetworkScoreManager();
100
101        // Test Requesting Scores
102        mRequestScoresLatch = new CountDownLatch(1);
103        setWifiEnabled(true);
104        setWifiState(true, TEST_SSID, TEST_BSSID);
105        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
106
107        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) NetworkBadging.BADGING_SD);
108
109        ArgumentCaptor<WifiNetworkScoreCache> scoreCacheCaptor =
110                ArgumentCaptor.forClass(WifiNetworkScoreCache.class);
111        verify(mMockNetworkScoreManager).registerNetworkScoreCache(
112                anyInt(),
113                scoreCacheCaptor.capture(),
114                Matchers.anyInt());
115        scoreCacheCaptor.getValue().updateScores(Arrays.asList(score));
116
117        //  Test badge is set
118        setWifiLevel(testLevel);
119
120        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
121        Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
122                anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
123                any(), anyBoolean());
124        IconState iconState = iconArg.getValue();
125
126        assertEquals("Badged Wifi Resource is set",
127                Utils.WIFI_PIE_FOR_BADGING[testLevel],
128                iconState.icon);
129        assertEquals("SD Badge is set",
130                Utils.getWifiBadgeResource(NetworkBadging.BADGING_SD),
131                iconState.iconOverlay);
132    }
133
134    private void setupNetworkScoreManager() {
135        // Capture requested keys and count down latch if present
136        doAnswer(
137                new Answer<Boolean>() {
138                    @Override
139                    public Boolean answer(InvocationOnMock input) {
140                        if (mRequestScoresLatch != null) {
141                            mRequestScoresLatch.countDown();
142                        }
143                        NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0];
144                        for (NetworkKey key : keys) {
145                            mRequestedKeys.add(key);
146                        }
147                        return true;
148                    }
149                }).when(mMockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());
150    }
151
152    @Test
153    public void testQsWifiIcon() {
154        String testSsid = "Test SSID";
155
156        setWifiEnabled(false);
157        verifyLastQsWifiIcon(false, false, WifiIcons.QS_WIFI_NO_NETWORK, null);
158
159        setWifiEnabled(true);
160        verifyLastQsWifiIcon(true, false, WifiIcons.QS_WIFI_NO_NETWORK, null);
161
162        setWifiState(true, testSsid);
163        for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
164            setWifiLevel(testLevel);
165
166            setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
167            verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel],
168                    testSsid);
169            setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, false, true);
170            verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
171                    testSsid);
172        }
173    }
174
175    @Test
176    public void testQsDataDirection() {
177        // Setup normal connection
178        String testSsid = "Test SSID";
179        int testLevel = 2;
180        setWifiEnabled(true);
181        setWifiState(true, testSsid);
182        setWifiLevel(testLevel);
183        setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
184        verifyLastQsWifiIcon(true, true,
185                WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
186
187        // Set to different activity state first to ensure a callback happens.
188        setWifiActivity(WifiManager.DATA_ACTIVITY_IN);
189
190        setWifiActivity(WifiManager.DATA_ACTIVITY_NONE);
191        verifyLastQsDataDirection(false, false);
192        setWifiActivity(WifiManager.DATA_ACTIVITY_IN);
193        verifyLastQsDataDirection(true, false);
194        setWifiActivity(WifiManager.DATA_ACTIVITY_OUT);
195        verifyLastQsDataDirection(false, true);
196        setWifiActivity(WifiManager.DATA_ACTIVITY_INOUT);
197        verifyLastQsDataDirection(true, true);
198    }
199
200    @Test
201    public void testRoamingIconDuringWifi() {
202        // Setup normal connection
203        String testSsid = "\"Test SSID\"";
204        int testLevel = 2;
205        setWifiEnabled(true);
206        setWifiState(true, testSsid);
207        setWifiLevel(testLevel);
208        setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
209        verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
210
211        setupDefaultSignal();
212        setGsmRoaming(true);
213        // Still be on wifi though.
214        setConnectivity(NetworkCapabilities.TRANSPORT_WIFI, true, true);
215        setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
216        verifyLastMobileDataIndicators(true,
217                DEFAULT_LEVEL,
218                0, true);
219    }
220
221    protected void setWifiActivity(int activity) {
222        // TODO: Not this, because this variable probably isn't sticking around.
223        mNetworkController.mWifiSignalController.setActivity(activity);
224    }
225
226    protected void setWifiLevel(int level) {
227        float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1);
228        int rssi = (int)(MIN_RSSI + level * amountPerLevel);
229        // Put RSSI in the middle of the range.
230        rssi += amountPerLevel / 2;
231        Intent i = new Intent(WifiManager.RSSI_CHANGED_ACTION);
232        i.putExtra(WifiManager.EXTRA_NEW_RSSI, rssi);
233        mNetworkController.onReceive(mContext, i);
234    }
235
236    protected void setWifiEnabled(boolean enabled) {
237        Intent i = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
238        i.putExtra(WifiManager.EXTRA_WIFI_STATE,
239                enabled ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED);
240        mNetworkController.onReceive(mContext, i);
241    }
242
243    protected void setWifiState(boolean connected, String ssid) {
244        setWifiState(connected, ssid, null);
245    }
246
247    protected void setWifiState(boolean connected, String ssid, String bssid) {
248        Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
249        NetworkInfo networkInfo = Mockito.mock(NetworkInfo.class);
250        Mockito.when(networkInfo.isConnected()).thenReturn(connected);
251
252        WifiInfo wifiInfo = Mockito.mock(WifiInfo.class);
253        Mockito.when(wifiInfo.getSSID()).thenReturn(ssid);
254        if (bssid != null) {
255            Mockito.when(wifiInfo.getBSSID()).thenReturn(bssid);
256        }
257
258        i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
259        i.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo);
260        mNetworkController.onReceive(mContext, i);
261    }
262
263    protected void verifyLastQsDataDirection(boolean in, boolean out) {
264        ArgumentCaptor<Boolean> inArg = ArgumentCaptor.forClass(Boolean.class);
265        ArgumentCaptor<Boolean> outArg = ArgumentCaptor.forClass(Boolean.class);
266
267        Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
268                anyBoolean(), any(), any(), inArg.capture(), outArg.capture(), any(), anyBoolean());
269        assertEquals("WiFi data in, in quick settings", in, (boolean) inArg.getValue());
270        assertEquals("WiFi data out, in quick settings", out, (boolean) outArg.getValue());
271    }
272
273    protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon,
274            String description) {
275        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
276        ArgumentCaptor<Boolean> enabledArg = ArgumentCaptor.forClass(Boolean.class);
277        ArgumentCaptor<String> descArg = ArgumentCaptor.forClass(String.class);
278
279        Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
280                enabledArg.capture(), any(), iconArg.capture(), anyBoolean(),
281                anyBoolean(),  descArg.capture(), anyBoolean());
282        IconState iconState = iconArg.getValue();
283        assertEquals("WiFi enabled, in quick settings", enabled, (boolean) enabledArg.getValue());
284        assertEquals("WiFi connected, in quick settings", connected, iconState.visible);
285        assertEquals("WiFi signal, in quick settings", icon, iconState.icon);
286        assertEquals("WiFI desc (ssid), in quick settings", description, descArg.getValue());
287    }
288
289    protected void verifyLastWifiIcon(boolean visible, int icon) {
290        ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
291
292        Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators(
293                anyBoolean(), iconArg.capture(), any(), anyBoolean(), anyBoolean(),
294                any(), anyBoolean());
295        IconState iconState = iconArg.getValue();
296        assertEquals("WiFi visible, in status bar", visible, iconState.visible);
297        assertEquals("WiFi signal, in status bar", icon, iconState.icon);
298    }
299}
300