Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4411d8d4 authored by Quang Luong's avatar Quang Luong Committed by Android (Google) Code Review
Browse files

Merge "Added unit tests for Passpoint/Osu integration in WifiTracker"

parents dfe4c235 da49e822
Loading
Loading
Loading
Loading
+71 −61
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import com.android.internal.util.CollectionUtils;
import com.android.settingslib.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -566,9 +567,6 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro

                AccessPoint accessPoint =
                        getCachedOrCreate(entry.getValue(), cachedAccessPoints);
                if (mLastInfo != null && mLastNetworkInfo != null) {
                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                }

                // Update the matching config if there is one, to populate saved network info
                accessPoint.update(configsByKey.get(entry.getKey()));
@@ -578,68 +576,20 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro

            List<ScanResult> cachedScanResults = new ArrayList<>(mScanResultCache.values());

            // Add a unique Passpoint R1 AccessPoint for each Passpoint profile's FQDN.
            List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans =
                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults);
            Set<String> seenFQDNs = new ArraySet<>();
            for (Pair<WifiConfiguration,
                    Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
                WifiConfiguration config = pairing.first;

                List<ScanResult> scanResults = new ArrayList<>();

                List<ScanResult> homeScans =
                        pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
                List<ScanResult> roamingScans =
                        pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);

                if (homeScans == null) {
                    homeScans = new ArrayList<>();
                }
                if (roamingScans == null) {
                    roamingScans = new ArrayList<>();
                }

                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
                if (!homeScans.isEmpty()) {
                    scanResults.addAll(homeScans);
                } else {
                    scanResults.addAll(roamingScans);
                }

                if (seenFQDNs.add(config.FQDN)) {
                    int bestRssi = Integer.MIN_VALUE;
                    for (ScanResult result : scanResults) {
                        if (result.level >= bestRssi) {
                            bestRssi = result.level;
                            config.SSID = AccessPoint.convertToQuotedString(result.SSID);
                        }
                    }
            // Add a unique Passpoint AccessPoint for each Passpoint profile's FQDN.
            accessPoints.addAll(updatePasspointAccessPoints(
                    mWifiManager.getAllMatchingWifiConfigs(cachedScanResults), cachedAccessPoints));

                    AccessPoint accessPoint =
                            getCachedOrCreatePasspoint(scanResults, cachedAccessPoints, config);
                    accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                    accessPoints.add(accessPoint);
                }
            }
            // Add OSU Provider AccessPoints
            accessPoints.addAll(updateOsuAccessPoints(
                    mWifiManager.getMatchingOsuProviders(cachedScanResults), cachedAccessPoints));

            // Add Passpoint OSU Provider AccessPoints
            Map<OsuProvider, List<ScanResult>> providersAndScans =
                    mWifiManager.getMatchingOsuProviders(cachedScanResults);
            Set<OsuProvider> alreadyProvisioned = mWifiManager
                    .getMatchingPasspointConfigsForOsuProviders(
                            providersAndScans.keySet()).keySet();
            for (OsuProvider provider : providersAndScans.keySet()) {
                if (!alreadyProvisioned.contains(provider)) {
                    AccessPoint accessPointOsu =
                            getCachedOrCreateOsu(providersAndScans.get(provider),
                                    cachedAccessPoints, provider);
                    accessPointOsu.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                    accessPoints.add(accessPointOsu);
            if (mLastInfo != null && mLastNetworkInfo != null) {
                for (AccessPoint ap : accessPoints) {
                    ap.update(connectionConfig, mLastInfo, mLastNetworkInfo);
                }
            }


            // If there were no scan results, create an AP for the currently connected network (if
            // it exists).
            if (accessPoints.isEmpty() && connectionConfig != null) {
@@ -686,7 +636,67 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    }

    @VisibleForTesting
    AccessPoint getCachedOrCreate(
    List<AccessPoint> updatePasspointAccessPoints(
            List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> passpointConfigsAndScans,
            List<AccessPoint> accessPointCache) {
        List<AccessPoint> accessPoints = new ArrayList<>();

        Set<String> seenFQDNs = new ArraySet<>();
        for (Pair<WifiConfiguration,
                Map<Integer, List<ScanResult>>> pairing : passpointConfigsAndScans) {
            WifiConfiguration config = pairing.first;
            if (seenFQDNs.add(config.FQDN)) {
                List<ScanResult> apScanResults = new ArrayList<>();

                List<ScanResult> homeScans =
                        pairing.second.get(WifiManager.PASSPOINT_HOME_NETWORK);
                List<ScanResult> roamingScans =
                        pairing.second.get(WifiManager.PASSPOINT_ROAMING_NETWORK);

                // TODO(b/118705403): Differentiate home network vs roaming network for summary info
                if (!CollectionUtils.isEmpty(homeScans)) {
                    apScanResults.addAll(homeScans);
                } else if (!CollectionUtils.isEmpty(roamingScans)) {
                    apScanResults.addAll(roamingScans);
                }

                int bestRssi = Integer.MIN_VALUE;
                for (ScanResult result : apScanResults) {
                    if (result.level >= bestRssi) {
                        bestRssi = result.level;
                        config.SSID = AccessPoint.convertToQuotedString(result.SSID);
                    }
                }

                AccessPoint accessPoint =
                        getCachedOrCreatePasspoint(apScanResults, accessPointCache, config);
                accessPoints.add(accessPoint);
            }
        }
        return accessPoints;
    }

    @VisibleForTesting
    List<AccessPoint> updateOsuAccessPoints(
            Map<OsuProvider, List<ScanResult>> providersAndScans,
            List<AccessPoint> accessPointCache) {
        List<AccessPoint> accessPoints = new ArrayList<>();

        Set<OsuProvider> alreadyProvisioned = mWifiManager
                .getMatchingPasspointConfigsForOsuProviders(
                        providersAndScans.keySet()).keySet();
        for (OsuProvider provider : providersAndScans.keySet()) {
            if (!alreadyProvisioned.contains(provider)) {
                AccessPoint accessPointOsu =
                        getCachedOrCreateOsu(providersAndScans.get(provider),
                                accessPointCache, provider);
                accessPoints.add(accessPointOsu);
            }
        }
        return accessPoints;
    }

    private AccessPoint getCachedOrCreate(
            List<ScanResult> scanResults,
            List<AccessPoint> cache) {
        AccessPoint accessPoint = getCachedByKey(cache, AccessPoint.getKey(scanResults.get(0)));
+235 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -48,11 +49,15 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiSsid;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.Pair;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -74,7 +79,10 @@ import org.mockito.stubbing.Answer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -94,6 +102,8 @@ public class WifiTrackerTest {
    private static final int RSSI_1 = -30;
    private static final byte SCORE_1 = 10;
    private static final int BADGE_1 = AccessPoint.Speed.MODERATE;
    private static final String FQDN_1 = "fqdn1";
    private static final String PROVIDER_FRIENDLY_NAME_1 = "providerFriendlyName1";

    private static final String SSID_2 = "ssid2";
    private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
@@ -102,6 +112,8 @@ public class WifiTrackerTest {
    private static final int RSSI_2 = -30;
    private static final byte SCORE_2 = 15;
    private static final int BADGE_2 = AccessPoint.Speed.FAST;
    private static final String FQDN_2 = "fqdn2";
    private static final String PROVIDER_FRIENDLY_NAME_2 = "providerFriendlyName2";

    private static final String SSID_3 = "ssid3";
    private static final String BSSID_3 = "CC:00:00:00:00:00";
@@ -271,6 +283,61 @@ public class WifiTrackerTest {
                0 /* microsecond timestamp */);
    }

    private static WifiConfiguration buildPasspointConfiguration(String fqdn, String friendlyName) {
        WifiConfiguration config = spy(new WifiConfiguration());
        config.FQDN = fqdn;
        config.providerFriendlyName = friendlyName;
        when(config.isPasspoint()).thenReturn(true);
        return config;
    }

    private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
            createPasspointMatchingWifiConfigsWithDuplicates() {
        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
                new ArrayList<>();
        Map<Integer, List<ScanResult>> mapping = new HashMap<>();

        mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, Arrays.asList(buildScanResult1()));

        WifiConfiguration passpointConfig1 =
                buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1);
        WifiConfiguration passpointConfig2 =
                buildPasspointConfiguration(FQDN_2, PROVIDER_FRIENDLY_NAME_2);

        matchingList.add(new Pair(passpointConfig1, mapping));
        matchingList.add(new Pair(passpointConfig1, mapping));
        matchingList.add(new Pair(passpointConfig2, mapping));
        matchingList.add(new Pair(passpointConfig2, mapping));

        return matchingList;
    }

    private List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>>
            createPasspointMatchingWifiConfigWithScanResults(
            List<ScanResult> homeList, List<ScanResult> roamingList) {
        List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> matchingList =
                new ArrayList<>();
        Map<Integer, List<ScanResult>> mapping = new HashMap<>();

        if (homeList != null) {
            mapping.put(WifiManager.PASSPOINT_HOME_NETWORK, homeList);
        }
        if (roamingList != null) {
            mapping.put(WifiManager.PASSPOINT_ROAMING_NETWORK, roamingList);
        }

        matchingList.add(new Pair(buildPasspointConfiguration(FQDN_1, PROVIDER_FRIENDLY_NAME_1),
                mapping));

        return matchingList;
    }

    private static OsuProvider buildOsuProvider(String friendlyName) {
        Map<String, String> friendlyNames = new HashMap<>();
        friendlyNames.put("en", friendlyName);
        return new OsuProvider(null, friendlyNames, null, null, null, null, null);
    }

    private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
                    Intent ... intents)
            throws InterruptedException {
@@ -926,4 +993,172 @@ public class WifiTrackerTest {
        assertThat(tracker.getAccessPoints().get(0).getBssid()).isEqualTo(BSSID_1);
        assertThat(tracker.getAccessPoints().get(1).getBssid()).isEqualTo(BSSID_2);
    }

    /**
     * Verifies that updatePasspointAccessPoints will only return AccessPoints whose
     * isPasspoint() evaluates as true.
     */
    @Test
    public void updatePasspointAccessPoints_returnedAccessPointsArePasspoint() {
        WifiTracker tracker = createMockedWifiTracker();

        List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
                createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());

        assertTrue(passpointAccessPoints.size() != 0);
        for (AccessPoint ap : passpointAccessPoints) {
            assertTrue(ap.isPasspoint());
        }
    }

    /**
     * Verifies that updatePasspointAccessPoints will return the same amount of AccessPoints as
     * unique WifiConfigurations, even if duplicate FQDNs exist.
     */
    @Test
    public void updatePasspointAccessPoints_ignoresDuplicateFQDNs() {
        WifiTracker tracker = createMockedWifiTracker();

        // Process matching list of four configs with two duplicate FQDNs.
        List<AccessPoint> passpointAccessPoints = tracker.updatePasspointAccessPoints(
                createPasspointMatchingWifiConfigsWithDuplicates(), new ArrayList<>());

        // Should have 2 APs with unique FQDNs, ignoring the 2 duplicate FQDNs.
        assertThat(passpointAccessPoints).hasSize(2);

        Set<String> fqdns = new ArraySet<>(Arrays.asList(FQDN_1, FQDN_2));

        assertTrue(fqdns.remove(passpointAccessPoints.get(0).getConfig().FQDN));
        assertTrue(fqdns.remove(passpointAccessPoints.get(1).getConfig().FQDN));
    }

    /**
     * Verifies that updatePasspointAccessPoints will return matching cached APs and update their
     * scan results instead of creating new APs.
     */
    @Test
    public void updatePasspointAccessPoints_usesCachedAccessPoints() {
        WifiTracker tracker = createMockedWifiTracker();

        ScanResult result = buildScanResult1();

        List<AccessPoint> passpointAccessPointsFirstUpdate = tracker.updatePasspointAccessPoints(
                createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
                        null), new ArrayList<>());
        List<AccessPoint> cachedAccessPoints = new ArrayList<>(passpointAccessPointsFirstUpdate);

        int prevRssi = result.level;
        int newRssi = prevRssi + 10;
        result.level = newRssi;

        List<AccessPoint> passpointAccessPointsSecondUpdate = tracker.updatePasspointAccessPoints(
                createPasspointMatchingWifiConfigWithScanResults(Arrays.asList(result),
                        null), cachedAccessPoints);

        // Verify second update AP is the same object as the first update AP
        assertThat(passpointAccessPointsFirstUpdate.get(0))
                .isSameAs(passpointAccessPointsSecondUpdate.get(0));
        // Verify second update AP has the average of the first and second update RSSIs
        assertThat(passpointAccessPointsSecondUpdate.get(0).getRssi())
                .isEqualTo((prevRssi + newRssi) / 2);
    }

    /**
     * Verifies that updateOsuAccessPoints will only return AccessPoints whose
     * isOsuProvider() evaluates as true.
     */
    @Test
    public void updateOsuAccessPoints_returnedAccessPointsAreOsuProviders() {
        WifiTracker tracker = createMockedWifiTracker();

        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
        providersAndScans.put(
                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
        providersAndScans.put(
                buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));

        List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
                providersAndScans, new ArrayList<>());

        assertThat(osuAccessPoints).hasSize(2);
        for (AccessPoint ap: osuAccessPoints) {
            assertThat(ap.isOsuProvider()).isTrue();
        }
    }

    /**
     * Verifies that updateOsuAccessPoints will not return Osu AccessPoints for already provisioned
     * networks
     */
    @Test
    public void updateOsuAccessPoints_doesNotReturnAlreadyProvisionedOsuAccessPoints() {
        WifiTracker tracker = createMockedWifiTracker();

        // Start with two Osu Providers
        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
        providersAndScans.put(
                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(buildScanResult1()));
        providersAndScans.put(
                buildOsuProvider(PROVIDER_FRIENDLY_NAME_2), Arrays.asList(buildScanResult2()));

        // First update
        List<AccessPoint> osuAccessPoints = tracker.updateOsuAccessPoints(
                providersAndScans, new ArrayList<>());

        // Make sure both Osu Providers' APs are returned
        assertThat(osuAccessPoints).hasSize(2);
        List<String> friendlyNames = Arrays.asList(
                osuAccessPoints.get(0).getTitle(), osuAccessPoints.get(1).getTitle());
        assertThat(friendlyNames)
                .containsExactly(PROVIDER_FRIENDLY_NAME_1, PROVIDER_FRIENDLY_NAME_2);

        // Simulate Osu Provider 1 being provisioned
        Map<OsuProvider, PasspointConfiguration> matchingPasspointConfigForOsuProvider =
                new HashMap<>();
        matchingPasspointConfigForOsuProvider.put(buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), null);
        when(mockWifiManager.getMatchingPasspointConfigsForOsuProviders(any())).thenReturn(
                matchingPasspointConfigForOsuProvider);

        // Second update
        osuAccessPoints = tracker.updateOsuAccessPoints(
                providersAndScans, new ArrayList<>());

        // Returned AP should only be for Osu Provider 2
        assertThat(osuAccessPoints).hasSize(1);
        assertThat(osuAccessPoints.get(0).getTitle()).isEqualTo(PROVIDER_FRIENDLY_NAME_2);
    }

    /**
     * Verifies that updateOsuAccessPoints will return matching cached APs and update their
     * scan results instead of creating new APs.
     */
    @Test
    public void updateOsuAccessPoints_usesCachedAccessPoints() {
        WifiTracker tracker = createMockedWifiTracker();

        ScanResult result = buildScanResult1();

        Map<OsuProvider, List<ScanResult>> providersAndScans = new HashMap<>();
        providersAndScans.put(
                buildOsuProvider(PROVIDER_FRIENDLY_NAME_1), Arrays.asList(result));

        List<AccessPoint> osuAccessPointsFirstUpdate = tracker.updateOsuAccessPoints(
                providersAndScans, new ArrayList<>());
        List<AccessPoint> cachedAccessPoints = new ArrayList<>(osuAccessPointsFirstUpdate);

        // New RSSI for second update
        int prevRssi = result.level;
        int newRssi = prevRssi + 10;
        result.level = newRssi;

        List<AccessPoint> osuAccessPointsSecondUpdate = tracker.updateOsuAccessPoints(
                providersAndScans, cachedAccessPoints);

        // Verify second update AP is the same object as the first update AP
        assertTrue(osuAccessPointsFirstUpdate.get(0)
                == osuAccessPointsSecondUpdate.get(0));
        // Verify second update AP has the average of the first and second update RSSIs
        assertThat(osuAccessPointsSecondUpdate.get(0).getRssi())
                .isEqualTo((prevRssi + newRssi) / 2);
    }
}