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

Commit 0c4214a2 authored by Cosmo Hsieh's avatar Cosmo Hsieh Committed by Android (Google) Code Review
Browse files

Merge "Add internal WifiTracker to get correct AccessPoint for WifiNetworkRequestDialog"

parents 17b0c03d 65c8d1df
Loading
Loading
Loading
Loading
+129 −36
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Message;
import android.widget.BaseAdapter;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.internal.PreferenceImageView;

@@ -46,7 +47,10 @@ import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.WifiTracker;
import com.android.settingslib.wifi.WifiTrackerFactory;

import java.util.ArrayList;
import java.util.List;
@@ -62,10 +66,14 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
    /** Message sent to us to stop scanning wifi and pop up timeout dialog. */
    private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0;

    /** Spec defines there should be 5 wifi ap on the list at most. */
    private static final int MAX_NUMBER_LIST_ITEM = 5;

    /** Delayed time to stop scanning wifi. */
    private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;

    private List<AccessPoint> mAccessPointList;
    private FilterWifiTracker mFilterWifiTracker;
    private AccessPointAdapter mDialogAdapter;
    private NetworkRequestUserSelectionCallback mUserSelectionCallback;

@@ -159,6 +167,19 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
        if (wifiManager != null) {
            wifiManager.unregisterNetworkRequestMatchCallback(this);
        }

        if (mFilterWifiTracker != null) {
            mFilterWifiTracker.onPause();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mFilterWifiTracker != null) {
            mFilterWifiTracker.onDestroy();
            mFilterWifiTracker = null;
        }
    }

    @Override
@@ -172,6 +193,11 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
        }
        // Sets time-out to stop scanning.
        mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);

        if (mFilterWifiTracker == null) {
            mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
        }
        mFilterWifiTracker.onResume();
    }

    private final Handler mHandler = new Handler() {
@@ -268,17 +294,33 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp

    @Override
    public void onMatch(List<ScanResult> scanResults) {
        mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
        renewAccessPointList(scanResults);

        notifyAdapterRefresh();
    }

    // Updates internal AccessPoint list from WifiTracker. scanResults are used to update key list
    // of AccessPoint, and could be null if there is no necessary to update key list.
    private void renewAccessPointList(List<ScanResult> scanResults) {
        if (mFilterWifiTracker == null) {
            return;
        }

        // TODO(b/119846365): Checks if we could escalate the converting effort.
        // Converts ScanResult to WifiConfiguration.
        List<WifiConfiguration> wifiConfigurations = null;
        final WifiManager wifiManager = getContext().getApplicationContext()
                .getSystemService(WifiManager.class);
        if (wifiManager != null) {
            wifiConfigurations = wifiManager.getAllMatchingWifiConfigs(scanResults);
        // Updates keys of scanResults into FilterWifiTracker for updating matched AccessPoints.
        if (scanResults != null) {
            mFilterWifiTracker.updateKeys(scanResults);
        }

        setUpAccessPointList(wifiConfigurations);
        // Re-gets matched AccessPoints from WifiTracker.
        final List<AccessPoint> list = getAccessPointList();
        list.clear();
        list.addAll(mFilterWifiTracker.getAccessPoints());
    }

    @VisibleForTesting
    void notifyAdapterRefresh() {
        if (getDialogAdapter() != null) {
            getDialogAdapter().notifyDataSetChanged();
        }
@@ -286,48 +328,99 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp

    @Override
    public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
        if (getDialogAdapter() != null) {
            updateAccessPointListItem(wificonfiguration);
            getDialogAdapter().notifyDataSetChanged();
        }
        // Dismisses current dialog, since connection is success.
        dismiss();
    }

    @Override
    public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) {
        if (mDialogAdapter != null) {
            updateAccessPointListItem(wificonfiguration);
            getDialogAdapter().notifyDataSetChanged();
        }
        stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
    }

    private void updateAccessPointListItem(WifiConfiguration wificonfiguration) {
        if (wificonfiguration == null) {
            return;
    private final class FilterWifiTracker {
        private final List<String> mAccessPointKeys;
        private final WifiTracker mWifiTracker;

        public FilterWifiTracker(Context context, Lifecycle lifecycle) {
            mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
                    lifecycle, /* includeSaved */ true, /* includeScans */ true);
            mAccessPointKeys = new ArrayList<>();
        }

        final List<AccessPoint> accessPointList = getAccessPointList();
        final int accessPointListSize = accessPointList.size();
        /**
         * Updates key list from input. {@code onMatch()} may be called in multi-times according
         * wifi scanning result, so needs patchwork here.
         */
        public void updateKeys(List<ScanResult> scanResults) {
            for (ScanResult scanResult : scanResults) {
                final String key = AccessPoint.getKey(scanResult);
                if (!mAccessPointKeys.contains(key)) {
                    mAccessPointKeys.add(key);
                }
            }
        }

        for (int i = 0; i < accessPointListSize; i++) {
            AccessPoint accessPoint = accessPointList.get(i);
            // It is the same AccessPoint SSID, and should be replaced to update latest properties.
            if (accessPoint.matches(wificonfiguration)) {
                accessPointList.set(i, new AccessPoint(getContext(), wificonfiguration));
        /**
         * Returns only AccessPoints whose key is in {@code mAccessPointKeys}.
         *
         * @return List of matched AccessPoints.
         */
        public List<AccessPoint> getAccessPoints() {
            final List<AccessPoint> allAccessPoints = mWifiTracker.getAccessPoints();
            final List<AccessPoint> result = new ArrayList<>();

            // The order should be kept, because order means wifi score (sorting in WifiTracker).
            int count = 0;
            for (AccessPoint accessPoint : allAccessPoints) {
                final String key = accessPoint.getKey();
                if (mAccessPointKeys.contains(key)) {
                    result.add(accessPoint);

                    count++;
                    // Limits how many count of items could show.
                    if (count >= MAX_NUMBER_LIST_ITEM) {
                        break;
                    }
                }
            }

    private void setUpAccessPointList(List<WifiConfiguration> wifiConfigurations) {
        // Grants for zero size input, since maybe current wifi is off or somethings are wrong.
        if (wifiConfigurations == null) {
            return;
            return result;
        }

        final List<AccessPoint> accessPointList = getAccessPointList();
        accessPointList.clear();
        for (WifiConfiguration config : wifiConfigurations) {
            accessPointList.add(new AccessPoint(getContext(), config));
        private WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() {

            @Override
            public void onWifiStateChanged(int state) {
                notifyAdapterRefresh();
            }

            @Override
            public void onConnectedChanged() {
                notifyAdapterRefresh();
            }

            @Override
            public void onAccessPointsChanged() {
                notifyAdapterRefresh();
            }
        };

        public void onDestroy() {
            if (mWifiTracker != null) {
                mWifiTracker.onDestroy();
            }
        }

        public void onResume() {
            if (mWifiTracker != null) {
                mWifiTracker.onStart();
            }
        }

        public void onPause() {
            if (mWifiTracker != null) {
                mWifiTracker.onStop();
            }
        }
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -18,9 +18,13 @@ package com.android.settings.wifi;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;

import androidx.appcompat.app.AlertDialog;

import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settingslib.wifi.WifiTracker;
import com.android.settingslib.wifi.WifiTrackerFactory;

import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +38,10 @@ public class NetworkRequestDialogActivityTest {

    @Test
    public void LaunchActivity_shouldShowNetworkRequestDialog() {
        // Mocks fake WifiTracker, in case of exception in NetworkRequestDialogFragment.onResume().
        WifiTracker wifiTracker = mock(WifiTracker.class);
        WifiTrackerFactory.setTestingWifiTracker(wifiTracker);

        Robolectric.setupActivity(NetworkRequestDialogActivity.class);

        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+73 −62
Original line number Diff line number Diff line
@@ -51,6 +51,10 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

import com.android.settingslib.wifi.WifiTracker;
import com.android.settingslib.wifi.WifiTrackerFactory;

import org.robolectric.shadows.ShadowLooper;

@RunWith(RobolectricTestRunner.class)
@@ -58,16 +62,21 @@ import org.robolectric.shadows.ShadowLooper;
public class NetworkRequestDialogFragmentTest {

    private static final String KEY_SSID = "key_ssid";
    private static final String KEY_SECURITY = "key_security";

    private FragmentActivity mActivity;
    private NetworkRequestDialogFragment networkRequestDialogFragment;
    private Context mContext;
    private WifiTracker mWifiTracker;

    @Before
    public void setUp() {
        mActivity = Robolectric.setupActivity(FragmentActivity.class);
        networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
        mContext = spy(RuntimeEnvironment.application);

        mWifiTracker = mock(WifiTracker.class);
        WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
    }

    @Test
@@ -140,71 +149,47 @@ public class NetworkRequestDialogFragmentTest {
    }

    @Test
    public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() {
        List<AccessPoint> accessPointList = spy(new ArrayList<>());
        Bundle bundle = new Bundle();
        bundle.putString(KEY_SSID, "Test AP 1");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 2");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 3");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 4");
        accessPointList.add(new AccessPoint(mContext, bundle));

    public void updateAccessPointList_onUserSelectionConnectSuccess_shouldCloseTheDialog() {
        List<AccessPoint> accessPointList = createAccessPointList();
        when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
        networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(alertDialog.isShowing()).isTrue();

        // Test if config would update list.
        WifiConfiguration config = new WifiConfiguration();
        config.SSID = "Test AP 3";
        networkRequestDialogFragment.onUserSelectionConnectSuccess(config);

        AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
        verify(accessPointList, times(1)).set(2, verifyAccessPoint);
        assertThat(alertDialog.isShowing()).isFalse();
    }

    @Test
    public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() {
        List<AccessPoint> accessPointList = spy(new ArrayList<>());
        Bundle bundle = new Bundle();
        bundle.putString(KEY_SSID, "Test AP 1");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 2");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 3");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 4");
        accessPointList.add(new AccessPoint(mContext, bundle));
    public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallTimeoutDialog() {
        FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
        FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
        List<AccessPoint> accessPointList = createAccessPointList();
        when(spyFakeFragment.getAccessPointList()).thenReturn(accessPointList);
        spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);

        when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
        networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
        AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
        assertThat(alertDialog.isShowing()).isTrue();

        // Test if config would update list.
        WifiConfiguration config = new WifiConfiguration();
        config.SSID = "Test AP 3";
        networkRequestDialogFragment.onUserSelectionConnectFailure(config);
        fakeFragment.onUserSelectionConnectFailure(config);

        AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
        verify(accessPointList, times(1)).set(2, verifyAccessPoint);
        assertThat(fakeFragment.bCalledStopAndPop).isTrue();
    }

    @Test
    public void onUserSelectionCallbackRegistration_shouldCallSelect() {
        List<AccessPoint> accessPointList = spy(new ArrayList<>());
        Bundle bundle = new Bundle();
        bundle.putString(KEY_SSID, "Test AP 1");
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 2");
        accessPointList.add(new AccessPoint(mContext, bundle));

        bundle.putString(KEY_SSID, "Test AP 3");
        AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
    public void onUserSelectionCallbackRegistration_onClick_shouldCallSelect() {
        // Assert.
        final int indexClickItem = 3;
        List<AccessPoint> accessPointList = createAccessPointList();
        AccessPoint clickedAccessPoint = accessPointList.get(indexClickItem);
        clickedAccessPoint.generateOpenNetworkConfig();
        accessPointList.add(clickedAccessPoint);

        bundle.putString(KEY_SSID, "Test AP 4");
        accessPointList.add(new AccessPoint(mContext, bundle));
        when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);

        NetworkRequestUserSelectionCallback selectionCallback = mock(
@@ -212,40 +197,66 @@ public class NetworkRequestDialogFragmentTest {
        AlertDialog dialog = mock(AlertDialog.class);
        networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);

        networkRequestDialogFragment.onClick(dialog, 2);
        // Act.
        networkRequestDialogFragment.onClick(dialog, indexClickItem);

        // Check.
        verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
    }

    @Test
    public void onMatch_shouldUpdatedList() {
        // Prepares WifiManager.
        // Assert.
        when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
        Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
        when(mContext.getApplicationContext()).thenReturn(applicationContext);
        WifiManager wifiManager = mock(WifiManager.class);
        when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
        networkRequestDialogFragment.onResume();

        List<AccessPoint> accessPointList = createAccessPointList();
        when(mWifiTracker.getAccessPoints()).thenReturn(accessPointList);

        List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
        WifiConfiguration config = new WifiConfiguration();
        final String SSID_AP1 = "Test AP 1";
        config.SSID = SSID_AP1;
        wifiConfigurationList.add(config);
        config = new WifiConfiguration();
        final String SSID_AP2 = "Test AP 2";
        config.SSID = SSID_AP2;
        wifiConfigurationList.add(config);

        // Prepares callback converted data.
        List<ScanResult> scanResults = new ArrayList<>();
        when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList);

        ScanResult scanResult = new ScanResult();
        scanResult.SSID = SSID_AP1;
        scanResult.capabilities = "WEP";
        scanResults.add(scanResult);
        scanResult = new ScanResult();
        scanResult.SSID = SSID_AP2;
        scanResult.capabilities = "WEP";
        scanResults.add(scanResult);

        // Act.
        networkRequestDialogFragment.onMatch(scanResults);

        List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList();
        assertThat(accessPointList).isNotEmpty();
        assertThat(accessPointList.size()).isEqualTo(2);
        assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1);
        assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2);
        // Check.
        List<AccessPoint> returnList = networkRequestDialogFragment.getAccessPointList();
        assertThat(returnList).isNotEmpty();
        assertThat(returnList.size()).isEqualTo(2);
        assertThat(returnList.get(0).getSsid()).isEqualTo(SSID_AP1);
        assertThat(returnList.get(1).getSsid()).isEqualTo(SSID_AP2);
    }

    private List<AccessPoint> createAccessPointList() {
        List<AccessPoint> accessPointList = spy(new ArrayList<>());
        Bundle bundle = new Bundle();
        bundle.putString(KEY_SSID, "Test AP 1");
        bundle.putInt(KEY_SECURITY, 1);
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 2");
        bundle.putInt(KEY_SECURITY, 1);
        accessPointList.add(new AccessPoint(mContext, bundle));
        bundle.putString(KEY_SSID, "Test AP 3");
        bundle.putInt(KEY_SECURITY, 2);
        AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
        accessPointList.add(clickedAccessPoint);
        bundle.putString(KEY_SSID, "Test AP 4");
        bundle.putInt(KEY_SECURITY, 0);
        accessPointList.add(new AccessPoint(mContext, bundle));

        return accessPointList;
    }
}