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

This commit is contained in:
Cosmo Hsieh
2018-12-18 06:15:35 +00:00
committed by Android (Google) Code Review
3 changed files with 213 additions and 101 deletions

View File

@@ -30,6 +30,7 @@ import android.os.Message;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.preference.internal.PreferenceImageView; 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.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE; import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.Utils; import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.wifi.AccessPoint; 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.ArrayList;
import java.util.List; 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. */ /** Message sent to us to stop scanning wifi and pop up timeout dialog. */
private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0; 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. */ /** Delayed time to stop scanning wifi. */
private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000; private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;
private List<AccessPoint> mAccessPointList; private List<AccessPoint> mAccessPointList;
private FilterWifiTracker mFilterWifiTracker;
private AccessPointAdapter mDialogAdapter; private AccessPointAdapter mDialogAdapter;
private NetworkRequestUserSelectionCallback mUserSelectionCallback; private NetworkRequestUserSelectionCallback mUserSelectionCallback;
@@ -159,6 +167,19 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
if (wifiManager != null) { if (wifiManager != null) {
wifiManager.unregisterNetworkRequestMatchCallback(this); wifiManager.unregisterNetworkRequestMatchCallback(this);
} }
if (mFilterWifiTracker != null) {
mFilterWifiTracker.onPause();
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mFilterWifiTracker != null) {
mFilterWifiTracker.onDestroy();
mFilterWifiTracker = null;
}
} }
@Override @Override
@@ -172,6 +193,11 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
} }
// Sets time-out to stop scanning. // Sets time-out to stop scanning.
mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS); 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() { private final Handler mHandler = new Handler() {
@@ -268,17 +294,33 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
@Override @Override
public void onMatch(List<ScanResult> scanResults) { public void onMatch(List<ScanResult> scanResults) {
// TODO(b/119846365): Checks if we could escalate the converting effort. mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
// Converts ScanResult to WifiConfiguration. renewAccessPointList(scanResults);
List<WifiConfiguration> wifiConfigurations = null;
final WifiManager wifiManager = getContext().getApplicationContext() notifyAdapterRefresh();
.getSystemService(WifiManager.class); }
if (wifiManager != null) {
wifiConfigurations = wifiManager.getAllMatchingWifiConfigs(scanResults); // 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;
} }
setUpAccessPointList(wifiConfigurations); // TODO(b/119846365): Checks if we could escalate the converting effort.
// Updates keys of scanResults into FilterWifiTracker for updating matched AccessPoints.
if (scanResults != null) {
mFilterWifiTracker.updateKeys(scanResults);
}
// Re-gets matched AccessPoints from WifiTracker.
final List<AccessPoint> list = getAccessPointList();
list.clear();
list.addAll(mFilterWifiTracker.getAccessPoints());
}
@VisibleForTesting
void notifyAdapterRefresh() {
if (getDialogAdapter() != null) { if (getDialogAdapter() != null) {
getDialogAdapter().notifyDataSetChanged(); getDialogAdapter().notifyDataSetChanged();
} }
@@ -286,48 +328,99 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
@Override @Override
public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) { public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
if (getDialogAdapter() != null) { // Dismisses current dialog, since connection is success.
updateAccessPointListItem(wificonfiguration); dismiss();
getDialogAdapter().notifyDataSetChanged();
}
} }
@Override @Override
public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) { public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) {
if (mDialogAdapter != null) { stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
updateAccessPointListItem(wificonfiguration);
getDialogAdapter().notifyDataSetChanged();
}
} }
private void updateAccessPointListItem(WifiConfiguration wificonfiguration) { private final class FilterWifiTracker {
if (wificonfiguration == null) { private final List<String> mAccessPointKeys;
return; 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); * Returns only AccessPoints whose key is in {@code mAccessPointKeys}.
// It is the same AccessPoint SSID, and should be replaced to update latest properties. *
if (accessPoint.matches(wificonfiguration)) { * @return List of matched AccessPoints.
accessPointList.set(i, new AccessPoint(getContext(), wificonfiguration)); */
break; 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;
}
}
}
return result;
}
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();
} }
} }
} }
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;
}
final List<AccessPoint> accessPointList = getAccessPointList();
accessPointList.clear();
for (WifiConfiguration config : wifiConfigurations) {
accessPointList.add(new AccessPoint(getContext(), config));
}
}
} }

View File

@@ -18,9 +18,13 @@ package com.android.settings.wifi;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; 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.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -34,6 +38,10 @@ public class NetworkRequestDialogActivityTest {
@Test @Test
public void LaunchActivity_shouldShowNetworkRequestDialog() { 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); Robolectric.setupActivity(NetworkRequestDialogActivity.class);
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();

View File

@@ -51,6 +51,10 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import com.android.settingslib.wifi.WifiTracker;
import com.android.settingslib.wifi.WifiTrackerFactory;
import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowLooper;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@@ -58,16 +62,21 @@ import org.robolectric.shadows.ShadowLooper;
public class NetworkRequestDialogFragmentTest { public class NetworkRequestDialogFragmentTest {
private static final String KEY_SSID = "key_ssid"; private static final String KEY_SSID = "key_ssid";
private static final String KEY_SECURITY = "key_security";
private FragmentActivity mActivity; private FragmentActivity mActivity;
private NetworkRequestDialogFragment networkRequestDialogFragment; private NetworkRequestDialogFragment networkRequestDialogFragment;
private Context mContext; private Context mContext;
private WifiTracker mWifiTracker;
@Before @Before
public void setUp() { public void setUp() {
mActivity = Robolectric.setupActivity(FragmentActivity.class); mActivity = Robolectric.setupActivity(FragmentActivity.class);
networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance()); networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mWifiTracker = mock(WifiTracker.class);
WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
} }
@Test @Test
@@ -140,71 +149,47 @@ public class NetworkRequestDialogFragmentTest {
} }
@Test @Test
public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() { public void updateAccessPointList_onUserSelectionConnectSuccess_shouldCloseTheDialog() {
List<AccessPoint> accessPointList = spy(new ArrayList<>()); List<AccessPoint> accessPointList = createAccessPointList();
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));
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(alertDialog.isShowing()).isTrue();
// Test if config would update list. // Test if config would update list.
WifiConfiguration config = new WifiConfiguration(); WifiConfiguration config = new WifiConfiguration();
config.SSID = "Test AP 3"; config.SSID = "Test AP 3";
networkRequestDialogFragment.onUserSelectionConnectSuccess(config); networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); assertThat(alertDialog.isShowing()).isFalse();
verify(accessPointList, times(1)).set(2, verifyAccessPoint);
} }
@Test @Test
public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() { public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallTimeoutDialog() {
List<AccessPoint> accessPointList = spy(new ArrayList<>()); FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
Bundle bundle = new Bundle(); FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
bundle.putString(KEY_SSID, "Test AP 1"); List<AccessPoint> accessPointList = createAccessPointList();
accessPointList.add(new AccessPoint(mContext, bundle)); when(spyFakeFragment.getAccessPointList()).thenReturn(accessPointList);
bundle.putString(KEY_SSID, "Test AP 2"); spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
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));
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null); assertThat(alertDialog.isShowing()).isTrue();
// Test if config would update list. // Test if config would update list.
WifiConfiguration config = new WifiConfiguration(); WifiConfiguration config = new WifiConfiguration();
config.SSID = "Test AP 3"; config.SSID = "Test AP 3";
networkRequestDialogFragment.onUserSelectionConnectFailure(config); fakeFragment.onUserSelectionConnectFailure(config);
AccessPoint verifyAccessPoint = new AccessPoint(mContext, config); assertThat(fakeFragment.bCalledStopAndPop).isTrue();
verify(accessPointList, times(1)).set(2, verifyAccessPoint);
} }
@Test @Test
public void onUserSelectionCallbackRegistration_shouldCallSelect() { public void onUserSelectionCallbackRegistration_onClick_shouldCallSelect() {
List<AccessPoint> accessPointList = spy(new ArrayList<>()); // Assert.
Bundle bundle = new Bundle(); final int indexClickItem = 3;
bundle.putString(KEY_SSID, "Test AP 1"); List<AccessPoint> accessPointList = createAccessPointList();
accessPointList.add(new AccessPoint(mContext, bundle)); AccessPoint clickedAccessPoint = accessPointList.get(indexClickItem);
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);
clickedAccessPoint.generateOpenNetworkConfig(); clickedAccessPoint.generateOpenNetworkConfig();
accessPointList.add(clickedAccessPoint);
bundle.putString(KEY_SSID, "Test AP 4");
accessPointList.add(new AccessPoint(mContext, bundle));
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList); when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
NetworkRequestUserSelectionCallback selectionCallback = mock( NetworkRequestUserSelectionCallback selectionCallback = mock(
@@ -212,40 +197,66 @@ public class NetworkRequestDialogFragmentTest {
AlertDialog dialog = mock(AlertDialog.class); AlertDialog dialog = mock(AlertDialog.class);
networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback); networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);
networkRequestDialogFragment.onClick(dialog, 2); // Act.
networkRequestDialogFragment.onClick(dialog, indexClickItem);
// Check.
verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig()); verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
} }
@Test @Test
public void onMatch_shouldUpdatedList() { public void onMatch_shouldUpdatedList() {
// Prepares WifiManager. // Assert.
when(networkRequestDialogFragment.getContext()).thenReturn(mContext); when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext()); Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
when(mContext.getApplicationContext()).thenReturn(applicationContext); when(mContext.getApplicationContext()).thenReturn(applicationContext);
WifiManager wifiManager = mock(WifiManager.class); WifiManager wifiManager = mock(WifiManager.class);
when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager); 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"; final String SSID_AP1 = "Test AP 1";
config.SSID = SSID_AP1;
wifiConfigurationList.add(config);
config = new WifiConfiguration();
final String SSID_AP2 = "Test AP 2"; final String SSID_AP2 = "Test AP 2";
config.SSID = SSID_AP2;
wifiConfigurationList.add(config);
// Prepares callback converted data.
List<ScanResult> scanResults = new ArrayList<>(); 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); networkRequestDialogFragment.onMatch(scanResults);
List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList(); // Check.
assertThat(accessPointList).isNotEmpty(); List<AccessPoint> returnList = networkRequestDialogFragment.getAccessPointList();
assertThat(accessPointList.size()).isEqualTo(2); assertThat(returnList).isNotEmpty();
assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1); assertThat(returnList.size()).isEqualTo(2);
assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2); 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;
} }
} }