1 /* 2 * Copyright (C) 2017 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 package com.android.settings.wifi; 17 18 import static android.support.test.InstrumentationRegistry.getInstrumentation; 19 import static android.support.test.espresso.Espresso.onView; 20 import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; 21 import static android.support.test.espresso.assertion.ViewAssertions.matches; 22 import static android.support.test.espresso.matcher.ViewMatchers.Visibility.VISIBLE; 23 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; 24 import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility; 25 import static android.support.test.espresso.matcher.ViewMatchers.withId; 26 import static android.support.test.espresso.matcher.ViewMatchers.withText; 27 28 import static com.google.common.truth.Truth.assertThat; 29 30 import static org.hamcrest.Matchers.allOf; 31 import static org.hamcrest.Matchers.not; 32 import static org.hamcrest.Matchers.startsWith; 33 import static org.mockito.Mockito.atMost; 34 import static org.mockito.Mockito.times; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.when; 37 38 import android.app.Activity; 39 import android.app.Fragment; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.net.ConnectivityManager; 43 import android.net.NetworkInfo; 44 import android.net.wifi.WifiConfiguration; 45 import android.net.wifi.WifiInfo; 46 import android.net.wifi.WifiManager; 47 import android.net.wifi.WifiSsid; 48 import android.provider.Settings; 49 import android.support.test.InstrumentationRegistry; 50 import android.support.test.rule.ActivityTestRule; 51 import android.support.test.runner.AndroidJUnit4; 52 53 import com.android.settings.Settings.WifiSettingsActivity; 54 import com.android.settingslib.utils.ThreadUtils; 55 import com.android.settingslib.wifi.AccessPoint; 56 import com.android.settingslib.wifi.TestAccessPointBuilder; 57 import com.android.settingslib.wifi.WifiTracker; 58 import com.android.settingslib.wifi.WifiTracker.WifiListener; 59 import com.android.settingslib.wifi.WifiTrackerFactory; 60 61 import com.google.common.collect.Lists; 62 63 import org.junit.Before; 64 import org.junit.Ignore; 65 import org.junit.Rule; 66 import org.junit.Test; 67 import org.junit.runner.RunWith; 68 import org.mockito.Mock; 69 import org.mockito.MockitoAnnotations; 70 71 import java.util.List; 72 73 @RunWith(AndroidJUnit4.class) 74 public class WifiSettingsUiTest { 75 private static final String TEST_SSID = "\"Test Ssid\""; 76 private static final String TEST_UNQUOTED_SSID = "Test Ssid"; 77 private static final String TEST_BSSID = "0a:08:5c:67:89:00"; 78 private static final int TEST_RSSI = 123; 79 private static final int TEST_NETWORK_ID = 1; 80 81 // Keys used to lookup resources by name (see the resourceId/resourceString helper methods). 82 private static final String ID = "id"; 83 private static final String STRING = "string"; 84 private static final String WIFI_CONFIGURE_SETTINGS_PREFERENCE_TITLE = 85 "wifi_configure_settings_preference_title"; 86 private static final String WIFI_SAVED_ACCESS_POINTS_LABEL = "wifi_saved_access_points_label"; 87 private static final String WIFI_EMPTY_LIST_WIFI_OFF = "wifi_empty_list_wifi_off"; 88 private static final String WIFI_DISPLAY_STATUS_CONNECTED = "wifi_display_status_connected"; 89 private static final String WIFI_PASSWORD = "wifi_password"; 90 private static final String WIFI_SHOW_PASSWORD = "wifi_show_password"; 91 private static final String PASSWORD_LAYOUT = "password_layout"; 92 private static final String PASSWORD = "password"; 93 94 @Mock 95 private WifiTracker mWifiTracker; 96 @Mock 97 private WifiManager mWifiManager; 98 private Context mContext; 99 private WifiListener mWifiListener; 100 101 @Rule 102 public ActivityTestRule<WifiSettingsActivity> mActivityRule = 103 new ActivityTestRule<>(WifiSettingsActivity.class, true); 104 105 @Before setUp()106 public void setUp() { 107 MockitoAnnotations.initMocks(this); 108 mContext = InstrumentationRegistry.getTargetContext(); 109 WifiTrackerFactory.setTestingWifiTracker(mWifiTracker); 110 when(mWifiTracker.getManager()).thenReturn(mWifiManager); 111 } 112 113 /** 114 * Helper to get around the problem that directly accessing settings resource id's from 115 * com.android.settings.R via R.(type).(name) (eg R.id.password or 116 * R.string.wifi_configure_settings_preference_title) may not work due to mismatched resource 117 * ids. See b/37714546 and b/63546650. 118 */ resourceId(String type, String name)119 private int resourceId(String type, String name) { 120 return mContext.getResources().getIdentifier(name, type, mContext.getPackageName()); 121 } 122 123 /** Similar to {@link #resourceId}, but for accessing R.string.<name> values. */ resourceString(String name)124 private String resourceString(String name) { 125 return mContext.getResources().getString(resourceId(STRING, name)); 126 } 127 setupConnectedAccessPoint()128 private void setupConnectedAccessPoint() { 129 WifiConfiguration config = new WifiConfiguration(); 130 config.SSID = TEST_SSID; 131 config.BSSID = TEST_BSSID; 132 config.networkId = TEST_NETWORK_ID; 133 WifiInfo wifiInfo = new WifiInfo(); 134 wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_UNQUOTED_SSID)); 135 wifiInfo.setBSSID(TEST_BSSID); 136 wifiInfo.setRssi(TEST_RSSI); 137 wifiInfo.setNetworkId(TEST_NETWORK_ID); 138 NetworkInfo networkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, null, null); 139 networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); 140 AccessPoint accessPoint = new AccessPoint(mContext, config); 141 accessPoint.update(config, wifiInfo, networkInfo); 142 143 assertThat(accessPoint.getSsidStr()).isEqualTo(TEST_UNQUOTED_SSID); 144 assertThat(accessPoint.getBssid()).isEqualTo(TEST_BSSID); 145 assertThat(accessPoint.getNetworkInfo()).isNotNull(); 146 assertThat(accessPoint.isActive()).isTrue(); 147 assertThat(accessPoint.getSettingsSummary()).isEqualTo( 148 resourceString(WIFI_DISPLAY_STATUS_CONNECTED)); 149 150 when(mWifiTracker.getAccessPoints()).thenReturn( 151 Lists.asList(accessPoint, new AccessPoint[]{})); 152 } 153 154 /** Launch the activity via an Intent with a String extra. */ launchActivity(String extraName, String extraValue)155 private void launchActivity(String extraName, String extraValue) { 156 Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); 157 if (extraName != null && extraValue != null) { 158 intent.putExtra(extraName, extraValue); 159 } 160 mActivityRule.launchActivity(intent); 161 162 verify(mWifiTracker).getManager(); 163 164 List<Fragment> fragments = mActivityRule.getActivity().getFragmentManager().getFragments(); 165 assertThat(fragments.size()).isEqualTo(1); 166 mWifiListener = (WifiSettings) fragments.get(0); 167 assertThat(mWifiListener).isNotNull(); 168 } 169 170 /** Helper to launch the activity with no extra. */ launchActivity()171 private void launchActivity() { 172 launchActivity(null, null); 173 } 174 setWifiState(int wifiState)175 private void setWifiState(int wifiState) { 176 when(mWifiManager.getWifiState()).thenReturn(wifiState); 177 when(mWifiManager.isWifiEnabled()).thenReturn(wifiState == WifiManager.WIFI_STATE_ENABLED); 178 } 179 callOnWifiStateChanged(int state)180 private void callOnWifiStateChanged(int state) { 181 mActivityRule.getActivity().getMainThreadHandler() 182 .post(() -> mWifiListener.onWifiStateChanged(state)); 183 } 184 185 @Test launchActivityShouldSucceed()186 public void launchActivityShouldSucceed() { 187 launchActivity(); 188 } 189 190 @Test shouldShowWifiPreferences()191 public void shouldShowWifiPreferences() { 192 launchActivity(); 193 194 onView(withText(resourceId(STRING, WIFI_CONFIGURE_SETTINGS_PREFERENCE_TITLE))).check( 195 matches(isDisplayed())); 196 } 197 198 @Test noSavedNetworks_wifiEnabled_shouldNotShowSavedNetworksButton()199 public void noSavedNetworks_wifiEnabled_shouldNotShowSavedNetworksButton() { 200 setWifiState(WifiManager.WIFI_STATE_ENABLED); 201 when(mWifiTracker.getNumSavedNetworks()).thenReturn(0); 202 203 launchActivity(); 204 205 onView(withText(resourceId(STRING, WIFI_SAVED_ACCESS_POINTS_LABEL))).check( 206 matches(not(isDisplayed()))); 207 } 208 209 @Test noSavedNetworks_wifiDisabled_shouldNotShowSavedNetworksButton()210 public void noSavedNetworks_wifiDisabled_shouldNotShowSavedNetworksButton() { 211 setWifiState(WifiManager.WIFI_STATE_DISABLED); 212 when(mWifiTracker.getNumSavedNetworks()).thenReturn(0); 213 214 launchActivity(); 215 216 onView(withText(resourceId(STRING, WIFI_SAVED_ACCESS_POINTS_LABEL))).check( 217 doesNotExist()); 218 } 219 220 @Test savedNetworksExist_shouldShowSavedNetworksButton()221 public void savedNetworksExist_shouldShowSavedNetworksButton() { 222 setWifiState(WifiManager.WIFI_STATE_ENABLED); 223 when(mWifiTracker.getNumSavedNetworks()).thenReturn(1); 224 225 launchActivity(); 226 227 onView(allOf(withText(resourceId(STRING, WIFI_SAVED_ACCESS_POINTS_LABEL)), 228 withEffectiveVisibility(VISIBLE))).check(matches(isDisplayed())); 229 } 230 231 @Test onDisableWifi_seeOffMessage()232 public void onDisableWifi_seeOffMessage() { 233 setWifiState(WifiManager.WIFI_STATE_DISABLED); 234 235 launchActivity(); 236 callOnWifiStateChanged(WifiManager.WIFI_STATE_DISABLED); 237 238 onView(withText(startsWith(resourceString(WIFI_EMPTY_LIST_WIFI_OFF)))).check( 239 matches(isDisplayed())); 240 } 241 242 @Test onEnableWifi_shouldNotSeeOffMessage()243 public void onEnableWifi_shouldNotSeeOffMessage() { 244 setWifiState(WifiManager.WIFI_STATE_ENABLED); 245 246 launchActivity(); 247 callOnWifiStateChanged(WifiManager.WIFI_STATE_ENABLED); 248 249 onView(withText(startsWith(resourceString(WIFI_EMPTY_LIST_WIFI_OFF)))).check( 250 doesNotExist()); 251 } 252 253 @Test onConnected_shouldSeeConnectedMessage()254 public void onConnected_shouldSeeConnectedMessage() { 255 setWifiState(WifiManager.WIFI_STATE_ENABLED); 256 setupConnectedAccessPoint(); 257 when(mWifiTracker.isConnected()).thenReturn(true); 258 259 launchActivity(); 260 261 onView(withText(resourceString(WIFI_DISPLAY_STATUS_CONNECTED))).check( 262 matches(isDisplayed())); 263 } 264 265 @Test changingSecurityStateOnApShouldNotCauseMultipleListItems()266 public void changingSecurityStateOnApShouldNotCauseMultipleListItems() { 267 setWifiState(WifiManager.WIFI_STATE_ENABLED); 268 TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext) 269 .setSsid(TEST_SSID) 270 .setSecurity(AccessPoint.SECURITY_NONE) 271 .setRssi(TEST_RSSI); 272 AccessPoint open = builder.build(); 273 274 builder.setSecurity(AccessPoint.SECURITY_EAP); 275 AccessPoint eap = builder.build(); 276 277 builder.setSecurity(AccessPoint.SECURITY_WEP); 278 AccessPoint wep = builder.build(); 279 280 // Return a different security state each time getAccessPoints is invoked 281 when(mWifiTracker.getAccessPoints()) 282 .thenReturn(Lists.newArrayList(open)) 283 .thenReturn(Lists.newArrayList(eap)) 284 .thenReturn(Lists.newArrayList(wep)); 285 286 launchActivity(); 287 288 onView(withText(TEST_SSID)).check(matches(isDisplayed())); 289 290 ThreadUtils.postOnMainThread(() -> mWifiListener.onAccessPointsChanged()); 291 onView(withText(TEST_SSID)).check(matches(isDisplayed())); 292 293 ThreadUtils.postOnMainThread(() -> mWifiListener.onAccessPointsChanged()); 294 onView(withText(TEST_SSID)).check(matches(isDisplayed())); 295 } 296 297 @Test wrongPasswordSavedNetwork()298 public void wrongPasswordSavedNetwork() { 299 setWifiState(WifiManager.WIFI_STATE_ENABLED); 300 301 // Set up an AccessPoint that is disabled due to incorrect password. 302 WifiConfiguration config = new WifiConfiguration(); 303 config.SSID = TEST_SSID; 304 config.BSSID = TEST_BSSID; 305 config.networkId = TEST_NETWORK_ID; 306 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 307 308 WifiConfiguration.NetworkSelectionStatus selectionStatus = 309 new WifiConfiguration.NetworkSelectionStatus(); 310 selectionStatus.setNetworkSelectionDisableReason( 311 WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD); 312 selectionStatus.setNetworkSelectionStatus( 313 WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED); 314 config.setNetworkSelectionStatus(selectionStatus); 315 316 WifiInfo wifiInfo = new WifiInfo(); 317 wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_UNQUOTED_SSID)); 318 wifiInfo.setBSSID(TEST_BSSID); 319 wifiInfo.setRssi(TEST_RSSI); 320 wifiInfo.setNetworkId(TEST_NETWORK_ID); 321 AccessPoint accessPoint = new AccessPoint(mContext, config); 322 accessPoint.update(config, wifiInfo, null); 323 324 // Make sure we've set up our access point correctly. 325 assertThat(accessPoint.getSsidStr()).isEqualTo(TEST_UNQUOTED_SSID); 326 assertThat(accessPoint.getBssid()).isEqualTo(TEST_BSSID); 327 assertThat(accessPoint.isActive()).isFalse(); 328 assertThat(accessPoint.getConfig()).isNotNull(); 329 WifiConfiguration.NetworkSelectionStatus networkStatus = 330 accessPoint.getConfig().getNetworkSelectionStatus(); 331 assertThat(networkStatus).isNotNull(); 332 assertThat(networkStatus.isNetworkEnabled()).isFalse(); 333 assertThat(networkStatus.getNetworkSelectionDisableReason()).isEqualTo( 334 WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD); 335 336 when(mWifiTracker.getAccessPoints()).thenReturn(Lists.newArrayList(accessPoint)); 337 launchActivity(WifiSettings.EXTRA_START_CONNECT_SSID, accessPoint.getSsidStr()); 338 339 // Make sure that the password dialog is visible. 340 onView(withText(resourceId(STRING, WIFI_PASSWORD))).check(matches(isDisplayed())); 341 onView(withText(resourceId(STRING, WIFI_SHOW_PASSWORD))).check(matches(isDisplayed())); 342 onView(withId(resourceId(ID, PASSWORD_LAYOUT))).check(matches(isDisplayed())); 343 onView(withId(resourceId(ID, PASSWORD))).check(matches(isDisplayed())); 344 } 345 346 @Ignore("b/73796195") 347 @Test onConnectedChanged_shouldNotFetchAPs()348 public void onConnectedChanged_shouldNotFetchAPs() { 349 setWifiState(WifiManager.WIFI_STATE_ENABLED); 350 when(mWifiTracker.isConnected()).thenReturn(true); 351 352 launchActivity(); 353 354 verify(mWifiTracker, times(1)).getAccessPoints(); 355 onView(withText(WIFI_DISPLAY_STATUS_CONNECTED)).check(matches(isDisplayed())); 356 357 // Invoke onConnectedChanged 358 when(mWifiTracker.isConnected()).thenReturn(false); 359 mWifiListener.onConnectedChanged(); 360 361 // Verify no additional call to getAccessPoints 362 getInstrumentation().waitForIdleSync(); 363 verify(mWifiTracker, times(1)).getAccessPoints(); 364 } 365 } 366