diff --git a/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2.java b/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2.java index 3b8eb27ada3..3b735fa7214 100644 --- a/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2.java +++ b/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2.java @@ -17,7 +17,6 @@ package com.android.settings.wifi.savedaccesspoints2; import android.content.Context; -import android.net.wifi.WifiManager; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -25,13 +24,11 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import com.android.settings.core.BasePreferenceController; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.AccessPointPreference; -import com.android.settingslib.wifi.AccessPointPreference.UserBadgeCache; -import com.android.settingslib.wifi.WifiSavedConfigUtils; +import com.android.settingslib.wifi.WifiEntryPreference; +import com.android.wifitrackerlib.WifiEntry; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * Controller that manages a PreferenceGroup, which contains a list of saved access points. @@ -39,17 +36,13 @@ import java.util.stream.Collectors; public class SavedAccessPointsPreferenceController2 extends BasePreferenceController implements Preference.OnPreferenceClickListener { - protected final WifiManager mWifiManager; - private final UserBadgeCache mUserBadgeCache; private PreferenceGroup mPreferenceGroup; private SavedAccessPointsWifiSettings2 mHost; @VisibleForTesting - List mAccessPoints; + List mWifiEntries = new ArrayList<>(); public SavedAccessPointsPreferenceController2(Context context, String preferenceKey) { super(context, preferenceKey); - mUserBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager()); - mWifiManager = context.getSystemService(WifiManager.class); } /** @@ -62,43 +55,39 @@ public class SavedAccessPointsPreferenceController2 extends BasePreferenceContro @Override public int getAvailabilityStatus() { - return mAccessPoints.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + return mWifiEntries.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @Override public void displayPreference(PreferenceScreen screen) { mPreferenceGroup = screen.findPreference(getPreferenceKey()); - refreshSavedAccessPoints(); updatePreference(); super.displayPreference(screen); } + void displayPreference(PreferenceScreen screen, List wifiEntries) { + if (wifiEntries == null || wifiEntries.isEmpty()) { + mWifiEntries.clear(); + } else { + mWifiEntries = wifiEntries; + } + + displayPreference(screen); + } + @Override public boolean onPreferenceClick(Preference preference) { if (mHost != null) { - final Preference preferenceInGroup = - mPreferenceGroup.findPreference(preference.getKey()); - mHost.showWifiPage((AccessPointPreference) preferenceInGroup); + mHost.showWifiPage(preference.getKey(), preference.getTitle()); } return false; } - protected void refreshSavedAccessPoints() { - mAccessPoints = WifiSavedConfigUtils.getAllConfigs(mContext, mWifiManager).stream() - .filter(accessPoint -> !accessPoint.isPasspointConfig()) - .sorted(SavedNetworkComparator2.INSTANCE) - .collect(Collectors.toList()); - } - private void updatePreference() { mPreferenceGroup.removeAll(); - for (AccessPoint accessPoint : mAccessPoints) { - final String key = accessPoint.getKey(); - - final AccessPointPreference preference = new AccessPointPreference(accessPoint, - mContext, mUserBadgeCache, true /* forSavedNetworks */); - preference.setKey(key); - preference.setIcon(null); + for (WifiEntry wifiEntry : mWifiEntries) { + final WifiEntryPreference preference = new WifiEntryPreference(mContext, wifiEntry); + preference.setKey(wifiEntry.getKey()); preference.setOnPreferenceClickListener(this); mPreferenceGroup.addPreference(preference); diff --git a/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2.java b/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2.java index a1b7733043b..e094051ccd4 100644 --- a/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2.java +++ b/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2.java @@ -16,12 +16,22 @@ package com.android.settings.wifi.savedaccesspoints2; -import android.annotation.Nullable; import android.app.settings.SettingsEnums; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkScoreManager; +import android.net.wifi.WifiManager; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Process; +import android.os.SimpleClock; +import android.os.SystemClock; +import android.text.TextUtils; +import android.util.Log; -import androidx.annotation.VisibleForTesting; +import androidx.annotation.NonNull; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -29,22 +39,29 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.AccessPointPreference; +import com.android.wifitrackerlib.SavedNetworkTracker; + +import java.time.Clock; +import java.time.ZoneOffset; /** * UI to manage saved networks/access points. */ -public class SavedAccessPointsWifiSettings2 extends DashboardFragment { +public class SavedAccessPointsWifiSettings2 extends DashboardFragment + implements SavedNetworkTracker.SavedNetworkTrackerCallback { private static final String TAG = "SavedAccessPoints2"; - @VisibleForTesting - Bundle mAccessPointSavedState; - private AccessPoint mSelectedAccessPoint; + // Key of a Bundle to save/restore the selected WifiEntry + static final String KEY_KEY = "key_key"; - // Instance state key - private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state"; + // Max age of tracked WifiEntries + private static final long MAX_SCAN_AGE_MILLIS = 15_000; + // Interval between initiating SavedNetworkTracker scans + private static final long SCAN_INTERVAL_MILLIS = 10_000; + + private SavedNetworkTracker mSavedNetworkTracker; + private HandlerThread mWorkerThread; @Override public int getMetricsCategory() { @@ -64,73 +81,90 @@ public class SavedAccessPointsWifiSettings2 extends DashboardFragment { @Override public void onAttach(Context context) { super.onAttach(context); - use(SavedAccessPointsPreferenceController2.class) - .setHost(this); - use(SubscribedAccessPointsPreferenceController2.class) - .setHost(this); + use(SavedAccessPointsPreferenceController2.class).setHost(this); + use(SubscribedAccessPointsPreferenceController2.class).setHost(this); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (savedInstanceState != null) { - if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) { - mAccessPointSavedState = - savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE); - } else { - mAccessPointSavedState = null; + + final Context context = getContext(); + mWorkerThread = new HandlerThread(TAG + + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", + Process.THREAD_PRIORITY_BACKGROUND); + mWorkerThread.start(); + final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.elapsedRealtime(); } - } + }; + mSavedNetworkTracker = new SavedNetworkTracker(getSettingsLifecycle(), context, + context.getSystemService(WifiManager.class), + context.getSystemService(ConnectivityManager.class), + context.getSystemService(NetworkScoreManager.class), + new Handler(Looper.getMainLooper()), + mWorkerThread.getThreadHandler(), + elapsedRealtimeClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + this); } @Override public void onStart() { super.onStart(); - if (mAccessPointSavedState != null) { - final PreferenceScreen screen = getPreferenceScreen(); - use(SavedAccessPointsPreferenceController2.class).displayPreference(screen); - use(SubscribedAccessPointsPreferenceController2.class).displayPreference(screen); - } + + onSavedWifiEntriesChanged(); + onSubscriptionWifiEntriesChanged(); + } + + @Override + public void onDestroy() { + mWorkerThread.quit(); + + super.onDestroy(); } /** - * Shows {@link WifiNetworkDetailsFragment2} for assigned {@link AccessPointPreference}. + * Shows {@link WifiNetworkDetailsFragment2} for assigned key of {@link WifiEntry}. */ - public void showWifiPage(@Nullable AccessPointPreference accessPoint) { + public void showWifiPage(@NonNull String key, CharSequence title) { removeDialog(WifiSettings.WIFI_DIALOG_ID); - if (accessPoint != null) { - // Save the access point and edit mode - mSelectedAccessPoint = accessPoint.getAccessPoint(); - } else { - // No access point is selected. Clear saved state. - mSelectedAccessPoint = null; - mAccessPointSavedState = null; + if (TextUtils.isEmpty(key)) { + Log.e(TAG, "Not able to show WifiEntry of an empty key"); + return; } - if (mSelectedAccessPoint == null) { - mSelectedAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState); - } - final Bundle savedState = new Bundle(); - mSelectedAccessPoint.saveWifiState(savedState); + final Bundle bundle = new Bundle(); + bundle.putString(KEY_KEY, key); new SubSettingLauncher(getContext()) - .setTitleText(mSelectedAccessPoint.getTitle()) + .setTitleText(title) .setDestination(WifiNetworkDetailsFragment2.class.getName()) - .setArguments(savedState) + .setArguments(bundle) .setSourceMetricsCategory(getMetricsCategory()) .launch(); } @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - // If the dialog is showing (indicated by the existence of mSelectedAccessPoint), then we - // save its state. - if (mSelectedAccessPoint != null) { - mAccessPointSavedState = new Bundle(); - mSelectedAccessPoint.saveWifiState(mAccessPointSavedState); - outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState); - } + public void onWifiStateChanged() { + // Do nothing. + } + + @Override + public void onSavedWifiEntriesChanged() { + final PreferenceScreen screen = getPreferenceScreen(); + use(SavedAccessPointsPreferenceController2.class) + .displayPreference(screen, mSavedNetworkTracker.getSavedWifiEntries()); + } + + @Override + public void onSubscriptionWifiEntriesChanged() { + final PreferenceScreen screen = getPreferenceScreen(); + use(SubscribedAccessPointsPreferenceController2.class) + .displayPreference(screen, mSavedNetworkTracker.getSubscriptionWifiEntries()); } } diff --git a/src/com/android/settings/wifi/savedaccesspoints2/SavedNetworkComparator2.java b/src/com/android/settings/wifi/savedaccesspoints2/SavedNetworkComparator2.java deleted file mode 100644 index 8388531d794..00000000000 --- a/src/com/android/settings/wifi/savedaccesspoints2/SavedNetworkComparator2.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.settings.wifi.savedaccesspoints2; - -import android.icu.text.Collator; - -import com.android.settingslib.wifi.AccessPoint; - -import java.util.Comparator; - -/** - * For {@link AccessPoint} sorting before desplaying. - */ -public final class SavedNetworkComparator2 { - public static final Comparator INSTANCE = - new Comparator() { - final Collator mCollator = Collator.getInstance(); - - @Override - public int compare(AccessPoint ap1, AccessPoint ap2) { - return mCollator.compare( - nullToEmpty(ap1.getTitle()), nullToEmpty(ap2.getTitle())); - } - - private String nullToEmpty(String string) { - return (string == null) ? "" : string; - } - }; -} diff --git a/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2.java b/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2.java index 00ae2218686..88984581816 100644 --- a/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2.java +++ b/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2.java @@ -18,10 +18,6 @@ package com.android.settings.wifi.savedaccesspoints2; import android.content.Context; -import com.android.settingslib.wifi.WifiSavedConfigUtils; - -import java.util.stream.Collectors; - /** * Controller that manages a PreferenceGroup, which contains a list of subscribed access points. */ @@ -31,12 +27,4 @@ public class SubscribedAccessPointsPreferenceController2 extends public SubscribedAccessPointsPreferenceController2(Context context, String preferenceKey) { super(context, preferenceKey); } - - @Override - protected void refreshSavedAccessPoints() { - mAccessPoints = WifiSavedConfigUtils.getAllConfigs(mContext, mWifiManager).stream() - .filter(accessPoint -> accessPoint.isPasspointConfig()) - .sorted(SavedNetworkComparator2.INSTANCE) - .collect(Collectors.toList()); - } } diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2Test.java index 6be9852be90..f50021ba33e 100644 --- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsPreferenceController2Test.java @@ -21,24 +21,18 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.os.Bundle; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; -import com.android.settings.testutils.shadow.ShadowAccessPoint; -import com.android.settings.testutils.shadow.ShadowWifiManager; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.AccessPointPreference; +import com.android.settingslib.wifi.WifiEntryPreference; +import com.android.wifitrackerlib.WifiEntry; import org.junit.Before; import org.junit.Test; @@ -48,13 +42,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; @RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowWifiManager.class}) public class SavedAccessPointsPreferenceController2Test { @Mock @@ -63,7 +56,6 @@ public class SavedAccessPointsPreferenceController2Test { private PreferenceCategory mPreferenceCategory; private Context mContext; - private WifiManager mWifiManager; private SavedAccessPointsWifiSettings2 mSettings; private SavedAccessPointsPreferenceController2 mController; @@ -71,7 +63,6 @@ public class SavedAccessPointsPreferenceController2Test { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mWifiManager = mContext.getSystemService(WifiManager.class); mSettings = spy(new SavedAccessPointsWifiSettings2()); mController = spy(new SavedAccessPointsPreferenceController2(mContext, "test_key")); mController.setHost(mSettings); @@ -83,46 +74,33 @@ public class SavedAccessPointsPreferenceController2Test { @Test public void getAvailability_noSavedAccessPoint_shouldNotAvailable() { - mController.mAccessPoints = new ArrayList<>(); + mController.mWifiEntries = new ArrayList<>(); assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } @Test public void getAvailability_oneSavedAccessPoint_shouldAvailable() { - final AccessPoint accessPoint = new AccessPoint(mContext, new Bundle() /* savedState */); - mController.mAccessPoints = new ArrayList(Arrays.asList(accessPoint)); + final WifiEntry mockWifiEntry = mock(WifiEntry.class); + mController.mWifiEntries = Arrays.asList(mockWifiEntry); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test - @Config(shadows = ShadowAccessPoint.class) - public void displayPreference_oneAccessPoint_shouldListNonSubscribedAPs() { - final WifiConfiguration config = new WifiConfiguration(); - config.SSID = "SSID"; - config.BSSID = "BSSID"; - config.networkId = 2; - mWifiManager.addNetwork(config); + public void displayPreference_oneAccessPoint_shouldListIt() { + final String title = "ssid_title"; + final WifiEntry mockWifiEntry = mock(WifiEntry.class); + when(mockWifiEntry.getTitle()).thenReturn(title); + final ArgumentCaptor captor = + ArgumentCaptor.forClass(WifiEntryPreference.class); - final ArgumentCaptor captor = - ArgumentCaptor.forClass(AccessPointPreference.class); - mController.displayPreference(mPreferenceScreen); + mController.displayPreference(mPreferenceScreen, Arrays.asList(mockWifiEntry)); verify(mPreferenceCategory).addPreference(captor.capture()); - final AccessPointPreference pref = captor.getValue(); - assertThat(pref.getTitle()).isEqualTo(config.SSID); - } - - @Test - @Config(shadows = ShadowAccessPoint.class) - public void displayPreference_onePasspoint_shouldNotListSubscribedAPs() { - mWifiManager.addOrUpdatePasspointConfiguration( - SubscribedAccessPointsPreferenceController2Test.createMockPasspointConfiguration()); - - mController.displayPreference(mPreferenceScreen); - - verify(mPreferenceCategory, never()).addPreference(any(AccessPointPreference.class)); + final List prefs = captor.getAllValues(); + assertThat(prefs.size()).isEqualTo(1); + assertThat(prefs.get(0).getTitle()).isEqualTo(title); } } diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2Test.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2Test.java deleted file mode 100644 index 2ce5d441c91..00000000000 --- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SubscribedAccessPointsPreferenceController2Test.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.settings.wifi.savedaccesspoints2; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiManager; -import android.net.wifi.hotspot2.PasspointConfiguration; -import android.net.wifi.hotspot2.pps.HomeSp; - -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.settings.testutils.shadow.ShadowAccessPoint; -import com.android.settings.testutils.shadow.ShadowWifiManager; -import com.android.settingslib.wifi.AccessPointPreference; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowWifiManager.class}) -public class SubscribedAccessPointsPreferenceController2Test { - - @Mock - private PreferenceScreen mPreferenceScreen; - @Mock - private PreferenceCategory mPreferenceCategory; - - private Context mContext; - private WifiManager mWifiManager; - private SavedAccessPointsWifiSettings2 mSettings; - private SubscribedAccessPointsPreferenceController2 mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mWifiManager = mContext.getSystemService(WifiManager.class); - mSettings = spy(new SavedAccessPointsWifiSettings2()); - mController = spy(new SubscribedAccessPointsPreferenceController2(mContext, "test_key")); - mController.setHost(mSettings); - - when(mPreferenceScreen.findPreference(mController.getPreferenceKey())) - .thenReturn(mPreferenceCategory); - when(mPreferenceCategory.getContext()).thenReturn(mContext); - } - - @Test - @Config(shadows = ShadowAccessPoint.class) - public void displayPreference_oneAccessPoint_shouldNotListNonSubscribedAPs() { - final WifiConfiguration config = new WifiConfiguration(); - config.SSID = "SSID"; - config.BSSID = "BSSID"; - config.networkId = 2; - mWifiManager.addNetwork(config); - - mController.displayPreference(mPreferenceScreen); - - verify(mPreferenceCategory, never()).addPreference(any(AccessPointPreference.class)); - } - - @Test - @Config(shadows = ShadowAccessPoint.class) - public void displayPreference_onePasspoint_shouldListSubscribedAPs() { - mWifiManager.addOrUpdatePasspointConfiguration(createMockPasspointConfiguration()); - - mController.displayPreference(mPreferenceScreen); - - final ArgumentCaptor captor = - ArgumentCaptor.forClass(AccessPointPreference.class); - verify(mPreferenceCategory).addPreference(captor.capture()); - - final AccessPointPreference pref = captor.getValue(); - assertThat(pref.getTitle()).isEqualTo("TESTPASSPOINT"); - } - - public static PasspointConfiguration createMockPasspointConfiguration() { - final PasspointConfiguration config = new PasspointConfiguration(); - final HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("FQDN"); - homeSp.setFriendlyName("TESTPASSPOINT"); - config.setHomeSp(homeSp); - return config; - } -}