| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.wifitrackerlib; |
| |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; |
| import static com.android.wifitrackerlib.TestUtils.BAD_RSSI; |
| import static com.android.wifitrackerlib.TestUtils.GOOD_LEVEL; |
| import static com.android.wifitrackerlib.TestUtils.GOOD_RSSI; |
| import static com.android.wifitrackerlib.TestUtils.buildScanResult; |
| import static com.android.wifitrackerlib.TestUtils.buildWifiConfiguration; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.anyLong; |
| import static org.mockito.Mockito.atLeast; |
| import static org.mockito.Mockito.atLeastOnce; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.when; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.res.Resources; |
| import android.net.ConnectivityManager; |
| import android.net.Network; |
| import android.net.NetworkCapabilities; |
| import android.net.NetworkInfo; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiEnterpriseConfig; |
| import android.net.wifi.WifiInfo; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.hotspot2.PasspointConfiguration; |
| import android.net.wifi.hotspot2.pps.Credential; |
| import android.net.wifi.hotspot2.pps.HomeSp; |
| import android.os.Handler; |
| import android.os.test.TestLooper; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.TelephonyManager; |
| import android.util.Pair; |
| |
| import androidx.lifecycle.Lifecycle; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Mock; |
| import org.mockito.Mockito; |
| import org.mockito.MockitoAnnotations; |
| import org.mockito.MockitoSession; |
| |
| import java.time.Clock; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.BitSet; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.stream.Collectors; |
| |
| public class WifiPickerTrackerTest { |
| |
| private static final long START_MILLIS = 123_456_789; |
| |
| private static final long MAX_SCAN_AGE_MILLIS = 15_000; |
| private static final long SCAN_INTERVAL_MILLIS = 10_000; |
| |
| @Mock private WifiTrackerInjector mInjector; |
| @Mock private Lifecycle mMockLifecycle; |
| @Mock private Context mMockContext; |
| @Mock private Resources mMockResources; |
| @Mock private WifiManager mMockWifiManager; |
| @Mock private ConnectivityManager mMockConnectivityManager; |
| @Mock private TelephonyManager mMockTelephonyManager; |
| @Mock private SubscriptionManager mMockSubscriptionManager; |
| @Mock private Clock mMockClock; |
| @Mock private WifiPickerTracker.WifiPickerTrackerCallback mMockCallback; |
| @Mock private WifiInfo mMockWifiInfo; |
| @Mock private NetworkInfo mMockNetworkInfo; |
| @Mock private Network mMockNetwork; |
| |
| private TestLooper mTestLooper; |
| |
| private final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = |
| ArgumentCaptor.forClass(BroadcastReceiver.class); |
| private final ArgumentCaptor<ConnectivityManager.NetworkCallback> |
| mNetworkCallbackCaptor = |
| ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); |
| private final ArgumentCaptor<ConnectivityManager.NetworkCallback> |
| mDefaultNetworkCallbackCaptor = |
| ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); |
| |
| private WifiPickerTracker createTestWifiPickerTracker() { |
| final Handler testHandler = new Handler(mTestLooper.getLooper()); |
| |
| return new WifiPickerTracker( |
| mInjector, |
| mMockLifecycle, |
| mMockContext, |
| mMockWifiManager, |
| mMockConnectivityManager, |
| testHandler, |
| testHandler, |
| mMockClock, |
| MAX_SCAN_AGE_MILLIS, |
| SCAN_INTERVAL_MILLIS, |
| mMockCallback); |
| } |
| |
| @Before |
| public void setUp() { |
| MockitoAnnotations.initMocks(this); |
| |
| mTestLooper = new TestLooper(); |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(new ArrayList<>()); |
| when(mMockWifiManager.getConnectionInfo()).thenReturn(mMockWifiInfo); |
| when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED); |
| when(mMockWifiManager.isWpa3SaeSupported()).thenReturn(true); |
| when(mMockWifiManager.isWpa3SuiteBSupported()).thenReturn(true); |
| when(mMockWifiManager.isEnhancedOpenSupported()).thenReturn(true); |
| when(mMockWifiManager.calculateSignalLevel(TestUtils.GOOD_RSSI)) |
| .thenReturn(TestUtils.GOOD_LEVEL); |
| when(mMockWifiManager.calculateSignalLevel(TestUtils.OKAY_RSSI)) |
| .thenReturn(TestUtils.OKAY_LEVEL); |
| when(mMockWifiManager.calculateSignalLevel(TestUtils.BAD_RSSI)) |
| .thenReturn(TestUtils.BAD_LEVEL); |
| when(mMockConnectivityManager.getNetworkInfo(any())).thenReturn(mMockNetworkInfo); |
| when(mMockClock.millis()).thenReturn(START_MILLIS); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID); |
| when(mMockWifiInfo.getRssi()).thenReturn(WifiInfo.INVALID_RSSI); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn( |
| NetworkInfo.DetailedState.DISCONNECTED); |
| when(mMockContext.getResources()).thenReturn(mMockResources); |
| when(mMockContext.getSystemService(TelephonyManager.class)) |
| .thenReturn(mMockTelephonyManager); |
| when(mMockContext.getSystemService(SubscriptionManager.class)) |
| .thenReturn(mMockSubscriptionManager); |
| when(mMockContext.getString(anyInt())).thenReturn(""); |
| } |
| |
| /** |
| * Tests that receiving a wifi state change broadcast updates getWifiState(). |
| */ |
| @Test |
| public void testWifiStateChangeBroadcast_updatesWifiState() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Set the wifi state to disabled |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED)); |
| |
| assertThat(wifiPickerTracker.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_DISABLED); |
| |
| // Change the wifi state to enabled |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED)); |
| |
| assertThat(wifiPickerTracker.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED); |
| } |
| |
| /** |
| * Tests that receiving a wifi state change broadcast notifies the listener. |
| */ |
| @Test |
| public void testWifiStateChangeBroadcast_notifiesListener() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiStateChanged(); |
| } |
| |
| /** |
| * Tests that a CONFIGURED_NETWORKS_CHANGED broadcast notifies the listener for |
| * numSavedNetworksChanged. |
| */ |
| @Test |
| public void testConfiguredNetworksChanged_notifiesListener() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| verify(mMockCallback, atLeastOnce()).onNumSavedNetworksChanged(); |
| } |
| |
| /** |
| * Tests that receiving a scan results available broadcast notifies the listener. |
| */ |
| @Test |
| public void testScanResultsAvailableAction_notifiesListener() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| } |
| |
| /** |
| * Tests that an empty list of WifiEntries is returned if no scans are available. |
| */ |
| @Test |
| public void testGetWifiEntries_noScans_emptyList() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(new ArrayList<>()); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| } |
| |
| |
| /** |
| * Tests that a StandardWifiEntry is returned by getWifiEntries() for each non-null, non-empty |
| * SSID/Security pair in the tracked scan results. |
| */ |
| @Test |
| public void testGetWifiEntries_wifiNetworkEntries_createdForEachSsidAndSecurityPair() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| final ScanResult openNetwork = buildScanResult("Open Network", "bssid0", START_MILLIS); |
| final ScanResult openNetworkDup = buildScanResult("Open Network", "bssid1", START_MILLIS); |
| final ScanResult secureNetwork = buildScanResult("Secure Network", "bssid2", START_MILLIS); |
| secureNetwork.capabilities = "EAP"; |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| openNetwork, |
| openNetworkDup, |
| secureNetwork, |
| // Ignore null and empty SSIDs |
| buildScanResult(null, "bssidNull", START_MILLIS), |
| buildScanResult("", "bssidEmpty", START_MILLIS))); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| List<String> seenTitles = new ArrayList<>(); |
| for (WifiEntry wifiEntry : wifiPickerTracker.getWifiEntries()) { |
| seenTitles.add(wifiEntry.getTitle()); |
| } |
| |
| assertThat(seenTitles).containsExactly("Open Network", "Secure Network"); |
| } |
| |
| /** |
| * Tests that old WifiEntries are timed out if their scans are older than the max scan age. |
| */ |
| @Test |
| public void testGetWifiEntries_wifiNetworkEntries_oldEntriesTimedOut() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Initial entries |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid0", "bssid0", START_MILLIS), |
| buildScanResult("ssid1", "bssid1", START_MILLIS), |
| buildScanResult("ssid2", "bssid2", START_MILLIS), |
| buildScanResult("ssid3", "bssid3", START_MILLIS), |
| buildScanResult("ssid4", "bssid4", START_MILLIS))); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| // Advance clock to max scan age. Entries should still be valid. |
| when(mMockClock.millis()).thenReturn(START_MILLIS + MAX_SCAN_AGE_MILLIS); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| assertThat(wifiPickerTracker.getWifiEntries()).isNotEmpty(); |
| |
| |
| // Advance the clock to time out old entries |
| when(mMockClock.millis()).thenReturn(START_MILLIS + MAX_SCAN_AGE_MILLIS + 1); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| // All entries timed out |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| } |
| |
| /** |
| * Tests that a failed scan will result in extending the max scan age by the scan interval. |
| * This is to allow the WifiEntry list to stay stable and not clear out if a single scan fails. |
| */ |
| @Test |
| public void testGetWifiEntries_wifiNetworkEntries_useOldEntriesOnFailedScan() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Initial entries |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid0", "bssid0", START_MILLIS), |
| buildScanResult("ssid1", "bssid1", START_MILLIS), |
| buildScanResult("ssid2", "bssid2", START_MILLIS), |
| buildScanResult("ssid3", "bssid3", START_MILLIS), |
| buildScanResult("ssid4", "bssid4", START_MILLIS))); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| final List<WifiEntry> previousEntries = wifiPickerTracker.getWifiEntries(); |
| |
| // Advance the clock to time out old entries and simulate failed scan |
| when(mMockClock.millis()) |
| .thenReturn(START_MILLIS + MAX_SCAN_AGE_MILLIS + SCAN_INTERVAL_MILLIS); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) |
| .putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)); |
| |
| // Failed scan should result in old WifiEntries still being shown |
| assertThat(previousEntries).containsExactlyElementsIn(wifiPickerTracker.getWifiEntries()); |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) |
| .putExtra(WifiManager.EXTRA_RESULTS_UPDATED, true)); |
| |
| // Successful scan should time out old entries. |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| } |
| |
| @Test |
| public void testGetWifiEntries_differentSsidSameBssid_returnsDifferentEntries() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| // Identical BSSID for 4 different SSIDs should return 4 entries. |
| buildScanResult("ssid0", "bssid0", START_MILLIS), |
| buildScanResult("ssid1", "bssid0", START_MILLIS), |
| buildScanResult("ssid2", "bssid0", START_MILLIS), |
| buildScanResult("ssid3", "bssid0", START_MILLIS), |
| // Another identical BSSID for 4 different SSIDs should return 4 more entries. |
| buildScanResult("ssid4", "bssid1", START_MILLIS), |
| buildScanResult("ssid5", "bssid1", START_MILLIS), |
| buildScanResult("ssid6", "bssid1", START_MILLIS), |
| buildScanResult("ssid7", "bssid1", START_MILLIS), |
| // Same SSID as the last for 2 different BSSIDs should not increase entries. |
| buildScanResult("ssid7", "bssid2", START_MILLIS), |
| buildScanResult("ssid7", "bssid3", START_MILLIS))); |
| |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| assertThat(wifiPickerTracker.getWifiEntries()).hasSize(8); |
| } |
| |
| /** |
| * Tests that a CONFIGURED_NETWORKS_CHANGED broadcast updates the correct WifiEntry from |
| * unsaved to saved. |
| */ |
| @Test |
| public void testGetWifiEntries_configuredNetworksChanged_unsavedToSaved() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| final WifiEntry entry = wifiPickerTracker.getWifiEntries().get(0); |
| |
| assertThat(entry.isSaved()).isFalse(); |
| |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| |
| assertThat(entry.isSaved()).isTrue(); |
| } |
| |
| /** |
| * Tests that a CONFIGURED_NETWORKS_CHANGED broadcast updates the correct WifiEntry from |
| * saved to unsaved. |
| */ |
| @Test |
| public void testGetWifiEntries_configuredNetworksChanged_savedToUnsaved() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| final WifiEntry entry = wifiPickerTracker.getWifiEntries().get(0); |
| |
| assertThat(entry.isSaved()).isTrue(); |
| |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.emptyList()); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| |
| assertThat(entry.isSaved()).isFalse(); |
| } |
| |
| /** |
| * Tests that getConnectedEntry() returns the connected WifiEntry if we start already connected |
| * to a network. |
| */ |
| @Test |
| public void testGetConnectedEntry_alreadyConnectedOnStart_returnsConnectedEntry() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isNotNull(); |
| } |
| |
| /** |
| * Tests that connecting to a network will update getConnectedEntry() to return the connected |
| * WifiEntry and remove that entry from getWifiEntries(). |
| */ |
| @Test |
| public void testGetConnectedEntry_connectToNetwork_returnsConnectedEntry() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| final WifiEntry entry = wifiPickerTracker.getWifiEntries().get(0); |
| |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isEqualTo(entry); |
| } |
| |
| /** |
| * Tests that disconnecting from a network will update getConnectedEntry() to return null. |
| */ |
| @Test |
| public void testGetConnectedEntry_disconnectFromNetwork_returnsNull() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockNetworkInfo.getDetailedState()) |
| .thenReturn(NetworkInfo.DetailedState.DISCONNECTED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isNull(); |
| } |
| |
| /** |
| * Tests that the wifi state changing to something other than WIFI_STATE_ENABLED will update |
| * getConnectedEntry() to return null. |
| */ |
| @Test |
| public void testGetConnectedEntry_wifiStateDisabled_returnsNull() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| when(mMockWifiManager.getWifiState()).thenReturn(WifiManager.WIFI_STATE_DISABLED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION)); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isNull(); |
| } |
| |
| /** |
| * Tests that a connected WifiEntry will return "Low quality" as the summary if Wifi is |
| * validated but cell is the default route. |
| */ |
| @Test |
| public void testGetConnectedEntry_wifiValidatedCellDefault_isLowQuality() { |
| final String summarySeparator = " / "; |
| final String lowQuality = "Low quality"; |
| final String[] wifiStatusArray = new String[]{"", "Scanning", "Connecting", |
| "Authenticating", "Obtaining IP address", "Connected"}; |
| when(mMockContext.getString(R.string.wifitrackerlib_summary_separator)) |
| .thenReturn(summarySeparator); |
| when(mMockContext.getString(R.string.wifi_connected_low_quality)).thenReturn(lowQuality); |
| when(mMockResources.getStringArray(R.array.wifitrackerlib_wifi_status)) |
| .thenReturn(wifiStatusArray); |
| |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config = new WifiConfiguration(); |
| config.SSID = "\"ssid\""; |
| config.networkId = 1; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiManager.getScanResults()).thenReturn(Arrays.asList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| when(mMockConnectivityManager.getNetworkInfo(any())).thenReturn(mMockNetworkInfo); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockConnectivityManager) |
| .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| // Set cellular to be the default network |
| mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, |
| new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build()); |
| |
| // Trigger a validation callback for the non-primary Wifi network. |
| MockitoSession session = mockitoSession().spyStatic(NonSdkApiWrapper.class).startMocking(); |
| try { |
| doReturn(false).when(() -> NonSdkApiWrapper.isPrimary(any())); |
| WifiInfo nonPrimaryWifiInfo = Mockito.mock(WifiInfo.class); |
| when(nonPrimaryWifiInfo.makeCopy(anyLong())).thenReturn(nonPrimaryWifiInfo); |
| NetworkCapabilities nonPrimaryCap = new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) |
| .setTransportInfo(nonPrimaryWifiInfo) |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) |
| .build(); |
| mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, nonPrimaryCap); |
| } finally { |
| session.finishMocking(); |
| } |
| |
| // Non-primary Wifi network validation should be ignored. |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getSummary()).isNotEqualTo(lowQuality); |
| |
| // Trigger a validation callback for the primary Wifi network. |
| WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class); |
| when(primaryWifiInfo.isPrimary()).thenReturn(true); |
| when(primaryWifiInfo.makeCopy(anyLong())).thenReturn(primaryWifiInfo); |
| NetworkCapabilities primaryCap = new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) |
| .setTransportInfo(primaryWifiInfo) |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) |
| .build(); |
| mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, primaryCap); |
| |
| // Cell default + primary network validation should trigger low quality |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getSummary()).isEqualTo(lowQuality); |
| } |
| |
| /** |
| * Tests that a PasspointWifiEntry is returned when Passpoint scans are visible. |
| */ |
| @Test |
| public void testGetWifiEntries_passpointInRange_returnsPasspointWifiEntry() { |
| final String passpointSsid = "passpointSsid"; |
| final String friendlyName = "friendlyName"; |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("fqdn"); |
| homeSp.setFriendlyName(friendlyName); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| final ScanResult passpointScan = |
| buildScanResult(passpointSsid, "bssid", START_MILLIS, GOOD_LEVEL); |
| when(mMockWifiManager.getScanResults()) |
| .thenReturn(Collections.singletonList(passpointScan)); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| final WifiConfiguration wifiConfig = spy(new WifiConfiguration()); |
| when(wifiConfig.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| final Map<Integer, List<ScanResult>> mapping = new HashMap<>(); |
| mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Collections.singletonList(passpointScan)); |
| List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> allMatchingWifiConfigs = |
| Collections.singletonList(new Pair<>(wifiConfig, mapping)); |
| when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(allMatchingWifiConfigs); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| // Only the Passpoint entry should be present. The corresponding StandardWifiEntry with |
| // matching SSID should be filtered out. |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(1); |
| final WifiEntry passpointEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(passpointEntry.isSubscription()).isTrue(); |
| assertThat(passpointEntry.getTitle()).isEqualTo(friendlyName); |
| } |
| |
| /** |
| * Tests that the same PasspointWifiEntry from getWifiEntries() is returned when it becomes the |
| * connected entry |
| */ |
| @Test |
| public void testGetWifiEntries_connectToPasspoint_returnsSamePasspointWifiEntry() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("fqdn"); |
| homeSp.setFriendlyName("friendlyName"); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| final WifiConfiguration wifiConfig = spy(new WifiConfiguration()); |
| when(wifiConfig.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| when(wifiConfig.isPasspoint()).thenReturn(true); |
| wifiConfig.networkId = 1; |
| final Map<Integer, List<ScanResult>> mapping = new HashMap<>(); |
| mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> allMatchingWifiConfigs = |
| Collections.singletonList(new Pair<>(wifiConfig, mapping)); |
| when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(allMatchingWifiConfigs); |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(wifiConfig)); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| assertThat(wifiPickerTracker.getWifiEntries()).isNotEmpty(); |
| final WifiEntry entry = wifiPickerTracker.getWifiEntries().get(0); |
| |
| when(mMockWifiInfo.isPasspointAp()).thenReturn(true); |
| when(mMockWifiInfo.getPasspointFqdn()).thenReturn("fqdn"); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isEqualTo(entry); |
| } |
| |
| /** |
| * Tests that a PasspointWifiEntry will disappear from getWifiEntries() once it is out of range. |
| */ |
| @Test |
| public void testGetWifiEntries_passpointOutOfRange_returnsNull() { |
| // Create conditions for one PasspointWifiEntry in getWifiEntries() |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("fqdn"); |
| homeSp.setFriendlyName("friendlyName"); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| final WifiConfiguration wifiConfig = spy(new WifiConfiguration()); |
| when(wifiConfig.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| final Map<Integer, List<ScanResult>> mapping = new HashMap<>(); |
| mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> allMatchingWifiConfigs = |
| Collections.singletonList(new Pair<>(wifiConfig, mapping)); |
| when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(allMatchingWifiConfigs); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Age out the scans and get out of range of Passpoint AP |
| when(mMockClock.millis()).thenReturn(START_MILLIS + MAX_SCAN_AGE_MILLIS + 1); |
| when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(new ArrayList<>()); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| // getWifiEntries() should be empty now |
| assertThat(wifiPickerTracker.getWifiEntries()).isEmpty(); |
| } |
| |
| /** |
| * Verifies that the WifiEntries returned in WifiPickerTracker.getWifiEntries() are returned in |
| * the order defined by the default WifiEntry.WIFI_PICKER_COMPARATOR. |
| */ |
| @Test |
| public void testGetWifiEntries_defaultSortingCriteria_returnsEntriesinCorrectOrder() { |
| List<ScanResult> currentScans = new ArrayList<>(); |
| List<WifiConfiguration> currentConfiguredNetworks = new ArrayList<>(); |
| |
| // Set up Passpoint entry |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn("fqdn"); |
| homeSp.setFriendlyName("friendlyName"); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| final WifiConfiguration wifiConfig = spy(new WifiConfiguration()); |
| when(wifiConfig.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| final Map<Integer, List<ScanResult>> mapping = new HashMap<>(); |
| mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> allMatchingWifiConfigs = |
| Collections.singletonList(new Pair<>(wifiConfig, mapping)); |
| when(mMockWifiManager.getAllMatchingWifiConfigs(any())).thenReturn(allMatchingWifiConfigs); |
| |
| // Set up saved entry |
| WifiConfiguration savedConfig = new WifiConfiguration(); |
| savedConfig.fromWifiNetworkSuggestion = false; |
| savedConfig.SSID = "\"ssid\""; |
| savedConfig.networkId = 1; |
| currentConfiguredNetworks.add(savedConfig); |
| currentScans.add(buildScanResult("ssid", "bssid", START_MILLIS)); |
| |
| // Set up suggestion entry |
| WifiConfiguration suggestionConfig = new WifiConfiguration(savedConfig); |
| suggestionConfig.networkId = 2; |
| suggestionConfig.creatorName = "creator1"; |
| suggestionConfig.carrierId = 1; |
| suggestionConfig.subscriptionId = 1; |
| suggestionConfig.fromWifiNetworkSuggestion = true; |
| currentConfiguredNetworks.add(suggestionConfig); |
| when(mMockWifiManager.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any())) |
| .thenReturn(Arrays.asList(suggestionConfig)); |
| |
| // Set up high level entry |
| currentScans.add(buildScanResult("high", "bssid", START_MILLIS, GOOD_RSSI)); |
| |
| // Set up low level entry with high priority title |
| String highPriorityTitle = "A"; |
| currentScans.add(buildScanResult(highPriorityTitle, "bssid", START_MILLIS, BAD_RSSI)); |
| |
| // Set up low level entry with low priority title |
| String lowPriorityTitle = "Z"; |
| currentScans.add(buildScanResult(lowPriorityTitle, "bssid", START_MILLIS, BAD_RSSI)); |
| |
| // Set up EAP-SIM entry without SIM |
| WifiConfiguration eapSimConfig = new WifiConfiguration(); |
| eapSimConfig.SSID = "\"eap-sim\""; |
| eapSimConfig.networkId = 3; |
| eapSimConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); |
| eapSimConfig.enterpriseConfig = mock(WifiEnterpriseConfig.class); |
| when(eapSimConfig.enterpriseConfig.isAuthenticationSimBased()).thenReturn(true); |
| currentConfiguredNetworks.add(eapSimConfig); |
| ScanResult eapSimScan = buildScanResult("eap-sim", "bssid", START_MILLIS, GOOD_RSSI); |
| eapSimScan.capabilities = "[EAP/SHA1]"; |
| currentScans.add(eapSimScan); |
| |
| // Set up WifiManager mocks |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(currentConfiguredNetworks); |
| when(mMockWifiManager.getScanResults()).thenReturn(currentScans); |
| |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| List<WifiEntry> entries = wifiPickerTracker.getWifiEntries(); |
| assertThat(entries.size()).isEqualTo(7); |
| // Subscription |
| assertThat(entries.get(0).isSubscription()).isTrue(); |
| // Saved |
| assertThat(entries.get(1).isSaved()).isTrue(); |
| // Suggestion |
| assertThat(entries.get(2).isSuggestion()).isTrue(); |
| // High level |
| assertThat(entries.get(3).getLevel()).isEqualTo(GOOD_LEVEL); |
| // High Title |
| assertThat(entries.get(4).getTitle()).isEqualTo(highPriorityTitle); |
| // Low Title |
| assertThat(entries.get(5).getTitle()).isEqualTo(lowPriorityTitle); |
| // Non-connectable |
| assertThat(entries.get(6).canConnect()).isEqualTo(false); |
| } |
| |
| /** |
| * Tests that multiple wifi entries are returned for multiple suggestions for the same network. |
| */ |
| @Test |
| public void testGetWifiEntries_multipleSuggestions_returnsMultipleEntries() { |
| WifiConfiguration savedConfig = new WifiConfiguration(); |
| savedConfig.fromWifiNetworkSuggestion = false; |
| savedConfig.SSID = "\"ssid\""; |
| savedConfig.networkId = 1; |
| WifiConfiguration suggestionConfig1 = new WifiConfiguration(savedConfig); |
| suggestionConfig1.networkId = 2; |
| suggestionConfig1.creatorName = "creator1"; |
| suggestionConfig1.carrierId = 1; |
| suggestionConfig1.subscriptionId = 1; |
| suggestionConfig1.fromWifiNetworkSuggestion = true; |
| WifiConfiguration suggestionConfig2 = new WifiConfiguration(savedConfig); |
| suggestionConfig2.networkId = 3; |
| suggestionConfig1.creatorName = "creator2"; |
| suggestionConfig1.carrierId = 2; |
| suggestionConfig1.subscriptionId = 2; |
| suggestionConfig2.fromWifiNetworkSuggestion = true; |
| // Initial entries |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(suggestionConfig1, suggestionConfig2)); |
| when(mMockWifiManager.getScanResults()).thenReturn(Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| when(mMockWifiManager.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any())) |
| .thenReturn(Arrays.asList(suggestionConfig1, suggestionConfig2)); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // 2 suggestion entries, no unsaved entry |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(2); |
| for (WifiEntry entry : wifiPickerTracker.getWifiEntries()) { |
| assertThat(entry.getTitle()).isEqualTo("ssid"); |
| } |
| assertThat(wifiPickerTracker.getWifiEntries().stream() |
| .filter(WifiEntry::isSuggestion) |
| .count()).isEqualTo(2); |
| |
| // Add a saved entry |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(savedConfig, suggestionConfig1, suggestionConfig2)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| |
| // Saved entry should appear alongside suggestions |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(3); |
| for (WifiEntry entry : wifiPickerTracker.getWifiEntries()) { |
| assertThat(entry.getTitle()).isEqualTo("ssid"); |
| } |
| assertThat(wifiPickerTracker.getWifiEntries().stream() |
| .filter(WifiEntry::isSuggestion) |
| .count()) |
| .isEqualTo(2); |
| assertThat(wifiPickerTracker.getWifiEntries().stream() |
| .filter(WifiEntry::isSaved) |
| .count()).isEqualTo(1); |
| } |
| |
| /** |
| * Tests that a suggestion entry is returned after a user shared suggestion config is added. |
| */ |
| @Test |
| public void testGetWifiEntries_userSharedSuggestionConfigAdded_returnsSuggestion() { |
| // Start out with non-saved network. |
| when(mMockWifiManager.getScanResults()).thenReturn(Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(1); |
| WifiEntry wifiEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(wifiEntry.getTitle()).isEqualTo("ssid"); |
| assertThat(wifiEntry.isSuggestion()).isFalse(); |
| |
| // Update configs with suggestion config. |
| WifiConfiguration suggestionConfig = new WifiConfiguration(); |
| suggestionConfig.SSID = "\"ssid\""; |
| suggestionConfig.networkId = 2; |
| suggestionConfig.creatorName = "creator1"; |
| suggestionConfig.carrierId = 1; |
| suggestionConfig.subscriptionId = 1; |
| suggestionConfig.fromWifiNetworkSuggestion = true; |
| when(mMockWifiManager.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any())) |
| .thenReturn(Arrays.asList(suggestionConfig)); |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(suggestionConfig)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| |
| // Non-saved network should turn into suggestion |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(1); |
| wifiEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(wifiEntry.getTitle()).isEqualTo("ssid"); |
| assertThat(wifiEntry.isSuggestion()).isTrue(); |
| } |
| |
| /** |
| * Tests that a suggestion entry is not returned after a non-shared suggestion config is added. |
| */ |
| @Test |
| public void testGetWifiEntries_nonSharedSuggestionConfigAdded_returnsNotSuggestion() { |
| // Start out with non-saved network. |
| when(mMockWifiManager.getScanResults()).thenReturn(Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(1); |
| WifiEntry wifiEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(wifiEntry.getTitle()).isEqualTo("ssid"); |
| assertThat(wifiEntry.isSuggestion()).isFalse(); |
| |
| // Update configs with non-shared suggestion config. |
| WifiConfiguration suggestionConfig = new WifiConfiguration(); |
| suggestionConfig.SSID = "\"ssid\""; |
| suggestionConfig.networkId = 2; |
| suggestionConfig.creatorName = "creator1"; |
| suggestionConfig.carrierId = 1; |
| suggestionConfig.subscriptionId = 1; |
| suggestionConfig.fromWifiNetworkSuggestion = true; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(suggestionConfig)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| |
| // Non-saved network should not turn into suggestion |
| assertThat(wifiPickerTracker.getWifiEntries().size()).isEqualTo(1); |
| wifiEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(wifiEntry.getTitle()).isEqualTo("ssid"); |
| assertThat(wifiEntry.isSuggestion()).isFalse(); |
| } |
| |
| /** |
| * Tests that a suggestion entry created before scan results are available will be updated to |
| * user shareable after scans become available. |
| */ |
| @Test |
| public void testGetWifiEntries_preConnectedSuggestion_becomesUserShareable() { |
| WifiConfiguration suggestionConfig = new WifiConfiguration(); |
| suggestionConfig.SSID = "\"ssid\""; |
| suggestionConfig.networkId = 1; |
| suggestionConfig.creatorName = "creator"; |
| suggestionConfig.carrierId = 1; |
| suggestionConfig.subscriptionId = 1; |
| suggestionConfig.fromWifiNetworkSuggestion = true; |
| // Initial entries |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(suggestionConfig)); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(suggestionConfig.networkId); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| WifiEntry suggestionEntry = wifiPickerTracker.getConnectedWifiEntry(); |
| assertThat(suggestionEntry).isNotNull(); |
| |
| // Update with user-shareable scan results for the suggestion |
| when(mMockWifiManager.getScanResults()).thenReturn(Collections.singletonList( |
| buildScanResult("ssid", "bssid", START_MILLIS))); |
| when(mMockWifiManager.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(any())) |
| .thenReturn(Arrays.asList(suggestionConfig)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| // Disconnect from network to verify its usershareability in the picker list |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| // Suggestion entry should be in picker list now |
| suggestionEntry = wifiPickerTracker.getWifiEntries().get(0); |
| assertThat(suggestionEntry.isSuggestion()).isTrue(); |
| } |
| |
| @Test |
| public void testGetConnectedEntry_alreadyConnectedToPasspoint_returnsPasspointEntry() { |
| final String fqdn = "fqdn"; |
| final String friendlyName = "friendlyName"; |
| final int networkId = 1; |
| // Create a passpoint configuration to match with the current network |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn(fqdn); |
| homeSp.setFriendlyName(friendlyName); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| // Create a wifi config to match the WifiInfo netId and unique id of the passpoint config |
| final WifiConfiguration config = Mockito.mock(WifiConfiguration.class); |
| config.SSID = "\"ssid\""; |
| config.networkId = networkId; |
| config.allowedKeyManagement = new BitSet(); |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); |
| config.subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| when(config.isPasspoint()).thenReturn(true); |
| when(config.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiInfo.isPasspointAp()).thenReturn(true); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(networkId); |
| when(mMockWifiInfo.getPasspointFqdn()).thenReturn(fqdn); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getTitle()).isEqualTo(friendlyName); |
| } |
| |
| @Test |
| public void testGetConnectedEntry_passpointWithoutScans_returnsPasspointEntry() { |
| final String fqdn = "fqdn"; |
| final String friendlyName = "friendlyName"; |
| final int networkId = 1; |
| // Create a passpoint configuration to match with the current network |
| final PasspointConfiguration passpointConfig = new PasspointConfiguration(); |
| final HomeSp homeSp = new HomeSp(); |
| homeSp.setFqdn(fqdn); |
| homeSp.setFriendlyName(friendlyName); |
| passpointConfig.setHomeSp(homeSp); |
| passpointConfig.setCredential(new Credential()); |
| when(mMockWifiManager.getPasspointConfigurations()) |
| .thenReturn(Collections.singletonList(passpointConfig)); |
| // Create a wifi config to match the WifiInfo netId and unique id of the passpoint config |
| final WifiConfiguration config = Mockito.mock(WifiConfiguration.class); |
| config.SSID = "\"ssid\""; |
| config.networkId = networkId; |
| config.allowedKeyManagement = new BitSet(); |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); |
| config.subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; |
| when(config.isPasspoint()).thenReturn(true); |
| when(config.getKey()).thenReturn(passpointConfig.getUniqueId()); |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Collections.singletonList(config)); |
| when(mMockWifiInfo.isPasspointAp()).thenReturn(true); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(networkId); |
| when(mMockWifiInfo.getPasspointFqdn()).thenReturn(fqdn); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Update with SCAN_RESULTS_AVAILABLE action while there are no scan results available yet. |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| verify(mMockCallback, atLeastOnce()).onWifiEntriesChanged(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isNotNull(); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getTitle()).isEqualTo(friendlyName); |
| } |
| |
| /** |
| * Tests that getConnectedEntry will return the correct network request if there are multiple |
| * active requests |
| */ |
| @Test |
| public void testGetConnectedEntry_multipleNetworkRequests_returnsConnectedRequest() { |
| final WifiConfiguration requestConfig1 = new WifiConfiguration(); |
| requestConfig1.SSID = "\"ssid1\""; |
| requestConfig1.networkId = 1; |
| requestConfig1.fromWifiNetworkSpecifier = true; |
| final WifiConfiguration requestConfig2 = new WifiConfiguration(); |
| requestConfig2.SSID = "\"ssid2\""; |
| requestConfig2.networkId = 2; |
| requestConfig2.fromWifiNetworkSpecifier = true; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(requestConfig1, requestConfig2)); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // WifiInfo has network id 1, so the connected entry should correspond to request 1 |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getSsid()).isEqualTo("ssid1"); |
| |
| when(mMockWifiInfo.getNetworkId()).thenReturn(2); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| // WifiInfo has network id 2, so the connected entry should correspond to request 2 |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().getSsid()).isEqualTo("ssid2"); |
| |
| when(mMockWifiInfo.getNetworkId()).thenReturn(-1); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| // WifiInfo matches no request configs, so the connected entry should be null |
| assertThat(wifiPickerTracker.getConnectedWifiEntry()).isNull(); |
| } |
| |
| /** |
| * Tests that SCAN_RESULTS_AVAILABLE_ACTION calls WifiManager#getMatchingOsuProviders() |
| */ |
| @Test |
| public void testScanResultsAvailableAction_callsGetMatchingOsuProviders() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); |
| |
| verify(mMockWifiManager, atLeastOnce()).getMatchingOsuProviders(any()); |
| } |
| |
| /** |
| * Tests that a connected MergedCarrierEntry is returned if the current WifiInfo has a matching |
| * subscription id. |
| */ |
| @Test |
| public void testGetMergedCarrierEntry_wifiInfoHasMatchingSubId_entryIsConnected() { |
| final int subId = 1; |
| when(mMockWifiInfo.isCarrierMerged()).thenReturn(true); |
| when(mMockWifiInfo.getSubscriptionId()).thenReturn(subId); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| final Intent intent = new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); |
| intent.putExtra("subscription", subId); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); |
| |
| assertThat(wifiPickerTracker.getMergedCarrierEntry().getConnectedState()) |
| .isEqualTo(WifiEntry.CONNECTED_STATE_CONNECTED); |
| } |
| |
| /** |
| * Tests that getMergedCarrierEntry returns a new MergedCarrierEntry with the correct |
| * subscription ID if the default subscription ID changes. |
| */ |
| @Test |
| public void testGetMergedCarrierEntry_subscriptionIdChanges_entryChanges() { |
| final int subId1 = 1; |
| final int subId2 = 2; |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| final Intent intent1 = |
| new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); |
| intent1.putExtra("subscription", subId1); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent1); |
| |
| final Intent intent2 = |
| new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); |
| intent2.putExtra("subscription", subId2); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent2); |
| |
| assertThat(wifiPickerTracker.getMergedCarrierEntry().getSubscriptionId()) |
| .isEqualTo(subId2); |
| } |
| |
| /** |
| * Tests that getWifiEntries returns separate WifiEntries for each security family for scans |
| * with the same SSID |
| */ |
| @Test |
| public void testGetWifiEntries_sameSsidDifferentSecurity_entriesMergedBySecurityFamily() { |
| final ArrayList scanList = new ArrayList(); |
| final String ssid = "ssid"; |
| final String bssid = "bssid"; |
| int bssidNum = 0; |
| for (String capabilities : Arrays.asList( |
| "", |
| "[OWE]", |
| "[OWE_TRANSITION]", |
| "[WEP]", |
| "[PSK]", |
| "[SAE]", |
| "[PSK][SAE]", |
| "[EAP/SHA1]", |
| "[RSN-EAP/SHA1+EAP/SHA256][MFPC]", |
| "[RSN-EAP/SHA256][MFPC][MFPR]", |
| "[RSN-SUITE_B_192][MFPR]" |
| )) { |
| final ScanResult scan = buildScanResult(ssid, bssid + bssidNum++, START_MILLIS); |
| scan.capabilities = capabilities; |
| scanList.add(scan); |
| } |
| when(mMockWifiManager.getScanResults()).thenReturn(scanList); |
| |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| |
| // Open/OWE, PSK/SAE, EAP/EAP-WPA3 should be merged to a single entry |
| List<WifiEntry> wifiEntries = wifiPickerTracker.getWifiEntries(); |
| assertThat(wifiEntries.size()).isEqualTo(5); |
| assertThat(wifiEntries.stream() |
| .map(entry -> entry.getSecurityTypes()) |
| .collect(Collectors.toList())) |
| .containsExactly( |
| Arrays.asList(WifiInfo.SECURITY_TYPE_OPEN, WifiInfo.SECURITY_TYPE_OWE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_WEP), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_PSK, WifiInfo.SECURITY_TYPE_SAE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP, |
| WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)); |
| |
| // Use a PSK config, EAP config, and Open config, and see that the security types returned |
| // for those grouped entries change to reflect the available configs. |
| WifiConfiguration openConfig = buildWifiConfiguration(ssid); |
| openConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); |
| openConfig.networkId = 1; |
| WifiConfiguration pskConfig = buildWifiConfiguration(ssid); |
| pskConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); |
| pskConfig.networkId = 2; |
| WifiConfiguration eapConfig = buildWifiConfiguration(ssid); |
| eapConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); |
| eapConfig.networkId = 3; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(openConfig, pskConfig, eapConfig)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| // Open/OWE becomes Open, PSK/SAE becomes PSK, EAP/EAP-WPA3 does not change since EAP config |
| // also works for EAP-WPA3. |
| wifiEntries = wifiPickerTracker.getWifiEntries(); |
| assertThat(wifiEntries.size()).isEqualTo(5); |
| assertThat(wifiEntries.stream() |
| .map(entry -> entry.getSecurityTypes()) |
| .collect(Collectors.toList())) |
| .containsExactly( |
| Arrays.asList(WifiInfo.SECURITY_TYPE_OPEN), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_WEP), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_PSK), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP, |
| WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)); |
| |
| // Use SAE config, EAP-WPA3 config, and OWE config |
| WifiConfiguration oweConfig = buildWifiConfiguration(ssid); |
| oweConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); |
| oweConfig.networkId = 1; |
| WifiConfiguration saeConfig = buildWifiConfiguration(ssid); |
| saeConfig.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); |
| saeConfig.networkId = 2; |
| WifiConfiguration eapWpa3Config = buildWifiConfiguration(ssid); |
| eapWpa3Config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE); |
| eapWpa3Config.networkId = 3; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(oweConfig, saeConfig, eapWpa3Config)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| // Open/OWE becomes OWE, PSK/SAE becomes SAE, EAP/EAP-WPA3 becomes EAP-WPA3 |
| wifiEntries = wifiPickerTracker.getWifiEntries(); |
| assertThat(wifiEntries.size()).isEqualTo(5); |
| assertThat(wifiEntries.stream() |
| .map(entry -> entry.getSecurityTypes()) |
| .collect(Collectors.toList())) |
| .containsExactly( |
| Arrays.asList(WifiInfo.SECURITY_TYPE_OWE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_WEP), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_SAE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)); |
| |
| // Now use configs for all the security types in the family |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()).thenReturn( |
| Arrays.asList(openConfig, oweConfig, pskConfig, saeConfig, eapConfig, |
| eapWpa3Config)); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION)); |
| mTestLooper.dispatchAll(); |
| |
| // All of the security types in the family should be returned. |
| wifiEntries = wifiPickerTracker.getWifiEntries(); |
| assertThat(wifiEntries.size()).isEqualTo(5); |
| assertThat(wifiEntries.stream() |
| .map(entry -> entry.getSecurityTypes()) |
| .collect(Collectors.toList())) |
| .containsExactly( |
| Arrays.asList(WifiInfo.SECURITY_TYPE_OPEN, WifiInfo.SECURITY_TYPE_OWE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_WEP), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_PSK, WifiInfo.SECURITY_TYPE_SAE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP, |
| WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE), |
| Arrays.asList(WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)); |
| } |
| |
| /** |
| * Tests that getNumSavedNetworks() returns the correct number of networks based on number of |
| * unique network IDs even for split configs which may have the same network ID but different |
| * security types. |
| */ |
| @Test |
| public void testGetNumSavedNetworks_splitConfigs_returnsNetworkIdCount() { |
| WifiConfiguration openConfig = buildWifiConfiguration("ssid"); |
| openConfig.networkId = 1; |
| // PSK + SAE split config with the same network ID |
| WifiConfiguration pskConfig = buildWifiConfiguration("ssid"); |
| pskConfig.setSecurityParams(WifiInfo.SECURITY_TYPE_PSK); |
| pskConfig.networkId = 2; |
| WifiConfiguration saeConfig = buildWifiConfiguration("ssid"); |
| saeConfig.setSecurityParams(WifiInfo.SECURITY_TYPE_SAE); |
| saeConfig.networkId = 2; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Arrays.asList(openConfig, pskConfig, saeConfig)); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| |
| // 1 open config + 2 split configs with same network ID should be treated as 2 networks. |
| assertThat(wifiPickerTracker.getNumSavedNetworks()).isEqualTo(2); |
| } |
| |
| /** |
| * Tests that the MergedCarrierEntry is the default network when it is connected and Wifi is |
| * the default network. |
| */ |
| @Test |
| public void testGetMergedCarrierEntry_wifiIsDefault_entryIsDefaultNetwork() { |
| final int subId = 1; |
| when(mMockWifiInfo.isCarrierMerged()).thenReturn(true); |
| when(mMockWifiInfo.getSubscriptionId()).thenReturn(subId); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| final Intent intent = new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); |
| intent.putExtra("subscription", subId); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| MergedCarrierEntry mergedCarrierEntry = wifiPickerTracker.getMergedCarrierEntry(); |
| assertThat(mergedCarrierEntry.getConnectedState()) |
| .isEqualTo(WifiEntry.CONNECTED_STATE_CONNECTED); |
| // Wifi isn't default yet, so isDefaultNetwork returns false |
| assertThat(mergedCarrierEntry.isDefaultNetwork()).isFalse(); |
| |
| mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, |
| new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build()); |
| |
| // Now Wifi is default, so isDefaultNetwork returns true |
| assertThat(mergedCarrierEntry.isDefaultNetwork()).isTrue(); |
| } |
| |
| /** |
| * Tests that the MergedCarrierEntry is the default network when it is connected and |
| * VCN-over-Wifi is the default network. |
| */ |
| @Test |
| public void testGetMergedCarrierEntry_vcnWifiIsDefault_entryIsDefaultNetwork() { |
| final int subId = 1; |
| when(mMockWifiInfo.isCarrierMerged()).thenReturn(true); |
| when(mMockWifiInfo.getSubscriptionId()).thenReturn(subId); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| final Intent intent = new Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); |
| intent.putExtra("subscription", subId); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| MergedCarrierEntry mergedCarrierEntry = wifiPickerTracker.getMergedCarrierEntry(); |
| assertThat(mergedCarrierEntry.getConnectedState()) |
| .isEqualTo(WifiEntry.CONNECTED_STATE_CONNECTED); |
| // Wifi isn't default yet, so isDefaultNetwork returns false |
| assertThat(mergedCarrierEntry.isDefaultNetwork()).isFalse(); |
| |
| MockitoSession session = mockitoSession().spyStatic(NonSdkApiWrapper.class).startMocking(); |
| try { |
| doReturn(true).when(() -> NonSdkApiWrapper.isVcnOverWifi(any())); |
| mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, |
| new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build()); |
| // Now VCN-over-Wifi is default, so isDefaultNetwork returns true |
| assertThat(mergedCarrierEntry.isDefaultNetwork()).isTrue(); |
| } finally { |
| session.finishMocking(); |
| } |
| } |
| |
| /** |
| * Tests that a MergedCarrierEntry is returned even if WifiPickerTracker hasn't been initialized |
| * via handleOnStart() yet. |
| */ |
| @Test |
| public void testGetMergedCarrierEntry_trackerNotInitialized_entryIsNotNull() { |
| final int subId = 1; |
| MockitoSession session = mockitoSession().spyStatic(SubscriptionManager.class) |
| .startMocking(); |
| try { |
| doReturn(subId).when(SubscriptionManager::getDefaultDataSubscriptionId); |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| MergedCarrierEntry mergedCarrierEntry = wifiPickerTracker.getMergedCarrierEntry(); |
| assertThat(mergedCarrierEntry).isNotNull(); |
| } finally { |
| session.finishMocking(); |
| } |
| } |
| |
| /** |
| * Tests that roaming from one network to another will update the new network as the default |
| * network if the default route did not change away from Wifi during the roam. This happens if |
| * the new network was switched to via MBB. |
| */ |
| @Test |
| public void testGetConnectedEntry_roamedButDefaultRouteDidNotChange_entryIsDefaultNetwork() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| final WifiConfiguration config1 = new WifiConfiguration(); |
| config1.SSID = "\"ssid1\""; |
| config1.networkId = 1; |
| final WifiConfiguration config2 = new WifiConfiguration(); |
| config2.SSID = "\"ssid2\""; |
| config2.networkId = 2; |
| when(mMockWifiManager.getPrivilegedConfiguredNetworks()) |
| .thenReturn(Arrays.asList(config1, config2)); |
| when(mMockWifiInfo.getNetworkId()).thenReturn(1); |
| when(mMockWifiInfo.getRssi()).thenReturn(-50); |
| when(mMockNetworkInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| // Set the default route to wifi |
| mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(mMockNetwork, |
| new NetworkCapabilities.Builder() |
| .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) |
| .build()); |
| WifiEntry connectedEntry = wifiPickerTracker.getConnectedWifiEntry(); |
| assertThat(connectedEntry.getWifiConfiguration()).isEqualTo(config1); |
| assertThat(connectedEntry.isDefaultNetwork()).isTrue(); |
| |
| // Connect to new network but don't change the default route |
| when(mMockWifiInfo.getNetworkId()).thenReturn(2); |
| mBroadcastReceiverCaptor.getValue().onReceive(mMockContext, |
| new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION) |
| .putExtra(WifiManager.EXTRA_NETWORK_INFO, mMockNetworkInfo)); |
| |
| // Verify that the newly connected network is still marked as the default network |
| connectedEntry = wifiPickerTracker.getConnectedWifiEntry(); |
| assertThat(connectedEntry.getWifiConfiguration()).isEqualTo(config2); |
| assertThat(wifiPickerTracker.getConnectedWifiEntry().isDefaultNetwork()).isTrue(); |
| } |
| |
| /** |
| * Verifies that the BroadcastReceiver and network callbacks are unregistered by the onStop() |
| * worker thread runnable. |
| */ |
| @Test |
| public void testBroadcastReceiverAndNetworkCallbacks_onStopRunnable_unregistersCallbacks() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| |
| wifiPickerTracker.onStop(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).unregisterReceiver(mBroadcastReceiverCaptor.getValue()); |
| verify(mMockConnectivityManager).unregisterNetworkCallback( |
| mDefaultNetworkCallbackCaptor.getValue()); |
| verify(mMockConnectivityManager).unregisterNetworkCallback( |
| mDefaultNetworkCallbackCaptor.getValue()); |
| } |
| |
| /** |
| * Verifies that the BroadcastReceiver and network callbacks are unregistered by onDestroyed(). |
| */ |
| @Test |
| public void testBroadcastReceiverAndNetworkCallbacks_onDestroyed_unregistersCallbacks() { |
| final WifiPickerTracker wifiPickerTracker = createTestWifiPickerTracker(); |
| wifiPickerTracker.onStart(); |
| mTestLooper.dispatchAll(); |
| verify(mMockContext).registerReceiver(mBroadcastReceiverCaptor.capture(), |
| any(), any(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerSystemDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| verify(mMockConnectivityManager, atLeast(0)).registerDefaultNetworkCallback( |
| mDefaultNetworkCallbackCaptor.capture(), any()); |
| |
| wifiPickerTracker.onStop(); |
| wifiPickerTracker.onDestroyed(); |
| verify(mMockContext).unregisterReceiver(mBroadcastReceiverCaptor.getValue()); |
| verify(mMockConnectivityManager).unregisterNetworkCallback( |
| mDefaultNetworkCallbackCaptor.getValue()); |
| verify(mMockConnectivityManager).unregisterNetworkCallback( |
| mDefaultNetworkCallbackCaptor.getValue()); |
| } |
| } |