diff --git a/src/com/android/settings/wifi/WifiConnectionPreferenceController.java b/src/com/android/settings/wifi/WifiConnectionPreferenceController.java index 12a6d143656..742edd196dd 100644 --- a/src/com/android/settings/wifi/WifiConnectionPreferenceController.java +++ b/src/com/android/settings/wifi/WifiConnectionPreferenceController.java @@ -17,22 +17,32 @@ package com.android.settings.wifi; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkScoreManager; +import android.net.wifi.WifiManager; import android.os.Bundle; -import android.util.FeatureFlagUtils; +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 androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.SubSettingLauncher; -import com.android.settings.wifi.details.WifiNetworkDetailsFragment; import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.AccessPointPreference; -import com.android.settingslib.wifi.WifiTracker; -import com.android.settingslib.wifi.WifiTrackerFactory; +import com.android.settingslib.wifi.WifiEntryPreference; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiPickerTracker; + +import java.time.Clock; +import java.time.ZoneOffset; // TODO(b/151133650): Replace AbstractPreferenceController with BasePreferenceController. /** @@ -40,21 +50,28 @@ import com.android.settingslib.wifi.WifiTrackerFactory; * controller class when there is a wifi connection present. */ public class WifiConnectionPreferenceController extends AbstractPreferenceController implements - WifiTracker.WifiListener { + WifiPickerTracker.WifiPickerTrackerCallback { private static final String TAG = "WifiConnPrefCtrl"; private static final String KEY = "active_wifi_connection"; + // Max age of tracked WifiEntries. + private static final long MAX_SCAN_AGE_MILLIS = 15_000; + // Interval between initiating WifiPickerTracker scans. + private static final long SCAN_INTERVAL_MILLIS = 10_000; + private UpdateListener mUpdateListener; private Context mPrefContext; private String mPreferenceGroupKey; private PreferenceGroup mPreferenceGroup; - private WifiTracker mWifiTracker; - private AccessPointPreference mPreference; - private AccessPointPreference.UserBadgeCache mBadgeCache; + @VisibleForTesting + public WifiPickerTracker mWifiPickerTracker; + private WifiEntryPreference mPreference; private int order; private int mMetricsCategory; + // Worker thread used for WifiPickerTracker work. + private HandlerThread mWorkerThread; /** * Used to notify a parent controller that this controller has changed in availability, or has @@ -82,16 +99,34 @@ public class WifiConnectionPreferenceController extends AbstractPreferenceContro super(context); mUpdateListener = updateListener; mPreferenceGroupKey = preferenceGroupKey; - mWifiTracker = WifiTrackerFactory.create(context, this, lifecycle, true /* includeSaved */, - true /* includeScans */); this.order = order; mMetricsCategory = metricsCategory; - mBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager()); + + 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(); + } + }; + mWifiPickerTracker = new WifiPickerTracker(lifecycle, 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 boolean isAvailable() { - return mWifiTracker.isConnected() && getCurrentAccessPoint() != null; + return mWifiPickerTracker.getConnectedWifiEntry() != null; } @Override @@ -107,88 +142,69 @@ public class WifiConnectionPreferenceController extends AbstractPreferenceContro update(); } - private AccessPoint getCurrentAccessPoint() { - for (AccessPoint accessPoint : mWifiTracker.getAccessPoints()) { - if (accessPoint.isActive()) { - return accessPoint; - } - } - return null; - } - - private void updatePreference(AccessPoint accessPoint) { + private void updatePreference(WifiEntry wifiEntry) { if (mPreference != null) { mPreferenceGroup.removePreference(mPreference); mPreference = null; } - if (accessPoint == null) { + if (wifiEntry == null || mPrefContext == null) { return; } - if (mPrefContext != null) { - mPreference = new AccessPointPreference(accessPoint, mPrefContext, mBadgeCache, - R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */); - mPreference.setKey(KEY); - mPreference.refresh(); - mPreference.setOrder(order); - if (FeatureFlagUtils.isEnabled(mPrefContext, FeatureFlagUtils.SETTINGS_WIFITRACKER2)) { - mPreference.setOnPreferenceClickListener(pref -> { - Bundle args = new Bundle(); - mPreference.getAccessPoint().saveWifiState(args); - new SubSettingLauncher(mPrefContext) - .setTitleRes(R.string.pref_title_network_details) - .setDestination(WifiNetworkDetailsFragment2.class.getName()) - .setArguments(args) - .setSourceMetricsCategory(mMetricsCategory) - .launch(); - return true; - }); - } else { - mPreference.setOnPreferenceClickListener(pref -> { - Bundle args = new Bundle(); - mPreference.getAccessPoint().saveWifiState(args); - new SubSettingLauncher(mPrefContext) - .setTitleRes(R.string.pref_title_network_details) - .setDestination(WifiNetworkDetailsFragment.class.getName()) - .setArguments(args) - .setSourceMetricsCategory(mMetricsCategory) - .launch(); - return true; - }); - } - mPreferenceGroup.addPreference(mPreference); - } + mPreference = new WifiEntryPreference(mPrefContext, wifiEntry); + mPreference.setKey(KEY); + mPreference.refresh(); + mPreference.setOrder(order); + mPreference.setOnPreferenceClickListener(pref -> { + final Bundle args = new Bundle(); + args.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY, + wifiEntry.getKey()); + new SubSettingLauncher(mPrefContext) + .setTitleRes(R.string.pref_title_network_details) + .setDestination(WifiNetworkDetailsFragment2.class.getName()) + .setArguments(args) + .setSourceMetricsCategory(mMetricsCategory) + .launch(); + return true; + }); + mPreferenceGroup.addPreference(mPreference); } private void update() { - AccessPoint connectedAccessPoint = null; - if (mWifiTracker.isConnected()) { - connectedAccessPoint = getCurrentAccessPoint(); - } - if (connectedAccessPoint == null) { + final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry(); + if (connectedWifiEntry == null) { updatePreference(null); } else { - if (mPreference == null || !mPreference.getAccessPoint().equals(connectedAccessPoint)) { - updatePreference(connectedAccessPoint); - } else if (mPreference != null) { - mPreference.refresh(); - } + if (mPreference == null || !mPreference.getWifiEntry().equals(connectedWifiEntry)) { + updatePreference(connectedWifiEntry); + } else if (mPreference != null) { + mPreference.refresh(); + } } mUpdateListener.onChildrenUpdated(); } + /** Called when the state of Wifi has changed. */ @Override - public void onWifiStateChanged(int state) { + public void onWifiStateChanged() { + update(); + } + + /** + * Update the results when data changes. + */ + @Override + public void onWifiEntriesChanged() { update(); } @Override - public void onConnectedChanged() { - update(); + public void onNumSavedSubscriptionsChanged() { + // Do nothing. } @Override - public void onAccessPointsChanged() { - update(); + public void onNumSavedNetworksChanged() { + // Do nothing. } } diff --git a/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java index 703731858c3..ea957c3e762 100644 --- a/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java @@ -29,12 +29,15 @@ import static org.mockito.Mockito.when; import android.content.Context; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; + import com.android.settings.wifi.WifiConnectionPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.AccessPointPreference; -import com.android.settingslib.wifi.WifiTracker; -import com.android.settingslib.wifi.WifiTrackerFactory; +import com.android.settingslib.wifi.WifiEntryPreference; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiPickerTracker; import org.junit.Before; import org.junit.Test; @@ -45,19 +48,12 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import java.util.ArrayList; -import java.util.Arrays; - -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - @RunWith(RobolectricTestRunner.class) public class WifiConnectionPreferenceControllerTest { private static final String KEY = "wifi_connection"; @Mock - WifiTracker mWifiTracker; + WifiPickerTracker mWifiPickerTracker; @Mock PreferenceScreen mScreen; @Mock @@ -74,7 +70,6 @@ public class WifiConnectionPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - WifiTrackerFactory.setTestingWifiTracker(mWifiTracker); mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory); @@ -83,49 +78,51 @@ public class WifiConnectionPreferenceControllerTest { mController = new WifiConnectionPreferenceController(mContext, mLifecycle, mUpdateListener, KEY, 0, 0); + mController.mWifiPickerTracker = mWifiPickerTracker; } @Test - public void isAvailable_noWiFiConnection_availableIsFalse() { - when(mWifiTracker.isConnected()).thenReturn(false); + public void isAvailable_noConnectedWifiEntry_availableIsFalse() { + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(null); + assertThat(mController.isAvailable()).isFalse(); } @Test - public void displayPreference_noWiFiConnection_noPreferenceAdded() { - when(mWifiTracker.isConnected()).thenReturn(false); - when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>()); + public void displayPreference_noConnectedWifiEntry_noPreferenceAdded() { + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(null); + mController.displayPreference(mScreen); + verify(mPreferenceCategory, never()).addPreference(any()); } @Test - public void displayPreference_hasWiFiConnection_preferenceAdded() { - when(mWifiTracker.isConnected()).thenReturn(true); - final AccessPoint accessPoint = mock(AccessPoint.class); - when(accessPoint.isActive()).thenReturn(true); - when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint)); + public void displayPreference_hasConnectedWifiEntry_preferenceAdded() { + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(wifiEntry); + mController.displayPreference(mScreen); - verify(mPreferenceCategory).addPreference(any(AccessPointPreference.class)); + verify(mPreferenceCategory).addPreference(any(WifiEntryPreference.class)); } @Test public void onConnectedChanged_wifiBecameDisconnected_preferenceRemoved() { - when(mWifiTracker.isConnected()).thenReturn(true); - final AccessPoint accessPoint = mock(AccessPoint.class); + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(wifiEntry); - when(accessPoint.isActive()).thenReturn(true); - when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint)); mController.displayPreference(mScreen); - final ArgumentCaptor captor = ArgumentCaptor.forClass( - AccessPointPreference.class); + final ArgumentCaptor captor = ArgumentCaptor.forClass( + WifiEntryPreference.class); verify(mPreferenceCategory).addPreference(captor.capture()); - final AccessPointPreference pref = captor.getValue(); + final WifiEntryPreference pref = captor.getValue(); - when(mWifiTracker.isConnected()).thenReturn(false); - when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>()); + // Become disconnected. + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(null); final int onUpdatedCountBefore = mOnChildUpdatedCount; - mController.onConnectedChanged(); + + mController.onWifiStateChanged(); + verify(mPreferenceCategory).removePreference(pref); assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1); } @@ -133,28 +130,24 @@ public class WifiConnectionPreferenceControllerTest { @Test public void onAccessPointsChanged_wifiBecameConnectedToDifferentAP_preferenceReplaced() { - when(mWifiTracker.isConnected()).thenReturn(true); - final AccessPoint accessPoint1 = mock(AccessPoint.class); - - when(accessPoint1.isActive()).thenReturn(true); - when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1)); + final WifiEntry wifiEntry1 = mock(WifiEntry.class); + when(wifiEntry1.getKey()).thenReturn("KEY_1"); + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(wifiEntry1); mController.displayPreference(mScreen); - final ArgumentCaptor captor = ArgumentCaptor.forClass( - AccessPointPreference.class); + final ArgumentCaptor captor = ArgumentCaptor.forClass( + WifiEntryPreference.class); - - final AccessPoint accessPoint2 = mock(AccessPoint.class); - when(accessPoint1.isActive()).thenReturn(false); - when(accessPoint2.isActive()).thenReturn(true); - when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1, accessPoint2)); + final WifiEntry wifiEntry2 = mock(WifiEntry.class); + when(wifiEntry1.getKey()).thenReturn("KEY_2"); + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(wifiEntry2); final int onUpdatedCountBefore = mOnChildUpdatedCount; - mController.onAccessPointsChanged(); + mController.onWifiEntriesChanged(); verify(mPreferenceCategory, times(2)).addPreference(captor.capture()); - final AccessPointPreference pref1 = captor.getAllValues().get(0); - final AccessPointPreference pref2 = captor.getAllValues().get(1); - assertThat(pref1.getAccessPoint()).isEqualTo(accessPoint1); - assertThat(pref2.getAccessPoint()).isEqualTo(accessPoint2); + final WifiEntryPreference pref1 = captor.getAllValues().get(0); + final WifiEntryPreference pref2 = captor.getAllValues().get(1); + assertThat(pref1.getWifiEntry()).isEqualTo(wifiEntry1); + assertThat(pref2.getWifiEntry()).isEqualTo(wifiEntry2); verify(mPreferenceCategory).removePreference(eq(pref1)); assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1); }