diff options
| author | 2021-01-12 17:39:40 +0000 | |
|---|---|---|
| committer | 2021-01-12 17:39:40 +0000 | |
| commit | 2cc4d5ece19c89852814912e55b14798db1fcef7 (patch) | |
| tree | f4359abfe3e7a30960b40079501cf84919347d82 | |
| parent | 829a1454db3e15436c80e5a984552f6236d331da (diff) | |
| parent | 4d2758609cade0a6d8616493818ef5940c09402e (diff) | |
Merge "Migrate to WifiPickerTracker"
7 files changed, 490 insertions, 60 deletions
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index a06bb931771f..e036d87f2492 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -78,6 +78,7 @@ <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/> + <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"/> <!-- Physical hardware --> <uses-permission android:name="android.permission.MANAGE_USB" /> <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" /> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 4d89dea7cb70..19eac77136c6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -54,6 +54,7 @@ import com.android.systemui.statusbar.policy.NetworkController.AccessPointContro import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.WifiIcons; +import com.android.wifitrackerlib.WifiEntry; import java.util.List; @@ -80,12 +81,13 @@ public class WifiTile extends QSTileImpl<SignalState> { StatusBarStateController statusBarStateController, ActivityStarter activityStarter, QSLogger qsLogger, - NetworkController networkController + NetworkController networkController, + AccessPointController accessPointController ) { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mController = networkController; - mWifiController = mController.getAccessPointController(); + mWifiController = accessPointController; mDetailAdapter = (WifiDetailAdapter) createDetailAdapter(); mController.observe(getLifecycle(), mSignalCallback); } @@ -325,7 +327,7 @@ public class WifiTile extends QSTileImpl<SignalState> { NetworkController.AccessPointController.AccessPointCallback, QSDetailItems.Callback { private QSDetailItems mItems; - private AccessPoint[] mAccessPoints; + private WifiEntry[] mAccessPoints; @Override public CharSequence getTitle() { @@ -366,8 +368,8 @@ public class WifiTile extends QSTileImpl<SignalState> { } @Override - public void onAccessPointsChanged(final List<AccessPoint> accessPoints) { - mAccessPoints = accessPoints.toArray(new AccessPoint[accessPoints.size()]); + public void onAccessPointsChanged(final List<WifiEntry> accessPoints) { + mAccessPoints = accessPoints.toArray(new WifiEntry[accessPoints.size()]); filterUnreachableAPs(); updateItems(); @@ -376,15 +378,15 @@ public class WifiTile extends QSTileImpl<SignalState> { /** Filter unreachable APs from mAccessPoints */ private void filterUnreachableAPs() { int numReachable = 0; - for (AccessPoint ap : mAccessPoints) { - if (ap.isReachable()) numReachable++; + for (WifiEntry ap : mAccessPoints) { + if (isWifiEntryReachable(ap)) numReachable++; } if (numReachable != mAccessPoints.length) { - AccessPoint[] unfiltered = mAccessPoints; - mAccessPoints = new AccessPoint[numReachable]; + WifiEntry[] unfiltered = mAccessPoints; + mAccessPoints = new WifiEntry[numReachable]; int i = 0; - for (AccessPoint ap : unfiltered) { - if (ap.isReachable()) mAccessPoints[i++] = ap; + for (WifiEntry ap : unfiltered) { + if (isWifiEntryReachable(ap)) mAccessPoints[i++] = ap; } } } @@ -397,8 +399,8 @@ public class WifiTile extends QSTileImpl<SignalState> { @Override public void onDetailItemClick(Item item) { if (item == null || item.tag == null) return; - final AccessPoint ap = (AccessPoint) item.tag; - if (!ap.isActive()) { + final WifiEntry ap = (WifiEntry) item.tag; + if (ap.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) { if (mWifiController.connect(ap)) { mHost.collapsePanels(); } @@ -442,12 +444,12 @@ public class WifiTile extends QSTileImpl<SignalState> { if (mAccessPoints != null) { items = new Item[mAccessPoints.length]; for (int i = 0; i < mAccessPoints.length; i++) { - final AccessPoint ap = mAccessPoints[i]; + final WifiEntry ap = mAccessPoints[i]; final Item item = new Item(); item.tag = ap; item.iconResId = mWifiController.getIcon(ap); item.line1 = ap.getSsid(); - item.line2 = ap.isActive() ? ap.getSummary() : null; + item.line2 = ap.getSummary(); item.icon2 = ap.getSecurity() != AccessPoint.SECURITY_NONE ? R.drawable.qs_ic_wifi_lock : -1; @@ -457,4 +459,8 @@ public class WifiTile extends QSTileImpl<SignalState> { mItems.setItems(items); } } + + private static boolean isWifiEntryReachable(WifiEntry ap) { + return ap.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java index 53d02280a03b..ab58286859cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java @@ -16,25 +16,47 @@ package com.android.systemui.statusbar.policy; -import android.app.ActivityManager; import android.content.Context; import android.content.Intent; -import android.net.wifi.WifiManager.ActionListener; +import android.net.ConnectivityManager; +import android.net.NetworkScoreManager; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.SimpleClock; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.util.IndentingPrintWriter; import android.util.Log; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.WifiTracker; -import com.android.settingslib.wifi.WifiTracker.WifiListener; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.settings.UserTracker; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiPickerTracker; import java.io.PrintWriter; +import java.time.Clock; +import java.time.ZoneOffset; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.concurrent.Executor; + +import javax.inject.Inject; public class AccessPointControllerImpl - implements NetworkController.AccessPointController, WifiListener { + implements NetworkController.AccessPointController, + WifiPickerTracker.WifiPickerTrackerCallback, LifecycleOwner { private static final String TAG = "AccessPointController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -44,24 +66,51 @@ public class AccessPointControllerImpl private static final int[] ICONS = WifiIcons.WIFI_FULL_ICONS; - private final Context mContext; private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>(); - private final WifiTracker mWifiTracker; private final UserManager mUserManager; + private final Executor mMainExecutor; + + private @Nullable WifiPickerTracker mWifiPickerTracker; + private WifiPickerTrackerFactory mWifiPickerTrackerFactory; + + private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); private int mCurrentUser; - public AccessPointControllerImpl(Context context) { - mContext = context; - mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - mWifiTracker = new WifiTracker(context, this, false, true); - mCurrentUser = ActivityManager.getCurrentUser(); + public AccessPointControllerImpl( + UserManager userManager, + UserTracker userTracker, + Executor mainExecutor, + WifiPickerTrackerFactory wifiPickerTrackerFactory + ) { + mUserManager = userManager; + mCurrentUser = userTracker.getUserId(); + mMainExecutor = mainExecutor; + mWifiPickerTrackerFactory = wifiPickerTrackerFactory; + mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.CREATED)); + } + + /** + * Initializes the controller. + * + * Will create a WifiPickerTracker associated to this controller. + */ + public void init() { + if (mWifiPickerTracker == null) { + mWifiPickerTracker = mWifiPickerTrackerFactory.create(this.getLifecycle(), this); + } + } + + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifecycle; } @Override protected void finalize() throws Throwable { + mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.DESTROYED)); super.finalize(); - mWifiTracker.onDestroy(); } public boolean canConfigWifi() { @@ -79,7 +128,7 @@ public class AccessPointControllerImpl if (DEBUG) Log.d(TAG, "addCallback " + callback); mCallbacks.add(callback); if (mCallbacks.size() == 1) { - mWifiTracker.onStart(); + mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.STARTED)); } } @@ -89,37 +138,59 @@ public class AccessPointControllerImpl if (DEBUG) Log.d(TAG, "removeCallback " + callback); mCallbacks.remove(callback); if (mCallbacks.isEmpty()) { - mWifiTracker.onStop(); + mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.CREATED)); } } @Override public void scanForAccessPoints() { - fireAcccessPointsCallback(mWifiTracker.getAccessPoints()); + if (mWifiPickerTracker == null) { + fireAcccessPointsCallback(Collections.emptyList()); + return; + } + List<WifiEntry> entries = mWifiPickerTracker.getWifiEntries(); + WifiEntry connectedEntry = mWifiPickerTracker.getConnectedWifiEntry(); + if (connectedEntry != null) { + entries.add(0, connectedEntry); + } + fireAcccessPointsCallback(entries); } @Override - public int getIcon(AccessPoint ap) { + public int getIcon(WifiEntry ap) { int level = ap.getLevel(); - return ICONS[level >= 0 ? level : 0]; + return ICONS[Math.max(0, level)]; } - public boolean connect(AccessPoint ap) { + /** + * Connects to a {@link WifiEntry} if it's saved or does not require security. + * + * If the entry is not saved and requires security, will trigger + * {@link AccessPointCallback#onSettingsActivityTriggered}. + * @param ap + * @return {@code true} if {@link AccessPointCallback#onSettingsActivityTriggered} is triggered + */ + public boolean connect(WifiEntry ap) { if (ap == null) return false; - if (DEBUG) Log.d(TAG, "connect networkId=" + ap.getConfig().networkId); + if (DEBUG) { + if (ap.getWifiConfiguration() != null) { + Log.d(TAG, "connect networkId=" + ap.getWifiConfiguration().networkId); + } else { + Log.d(TAG, "connect to unsaved network " + ap.getTitle()); + } + } if (ap.isSaved()) { - mWifiTracker.getManager().connect(ap.getConfig().networkId, mConnectListener); + ap.connect(mConnectCallback); } else { // Unknown network, need to add it. - if (ap.getSecurity() != AccessPoint.SECURITY_NONE) { + if (ap.getSecurity() != WifiEntry.SECURITY_NONE) { Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); - intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsidStr()); + intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsid()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); fireSettingsIntentCallback(intent); return true; } else { - ap.generateOpenNetworkConfig(); - mWifiTracker.getManager().connect(ap.getConfig(), mConnectListener); + ap.connect(mConnectCallback); } } return false; @@ -131,39 +202,129 @@ public class AccessPointControllerImpl } } - private void fireAcccessPointsCallback(List<AccessPoint> aps) { + private void fireAcccessPointsCallback(List<WifiEntry> aps) { for (AccessPointCallback callback : mCallbacks) { callback.onAccessPointsChanged(aps); } } public void dump(PrintWriter pw) { - mWifiTracker.dump(pw); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw); + ipw.println("AccessPointControllerImpl:"); + ipw.increaseIndent(); + ipw.println("Callbacks: " + Arrays.toString(mCallbacks.toArray())); + ipw.println("WifiPickerTracker: " + mWifiPickerTracker.toString()); + if (mWifiPickerTracker != null && !mCallbacks.isEmpty()) { + ipw.println("Connected: " + mWifiPickerTracker.getConnectedWifiEntry()); + ipw.println("Other wifi entries: " + + Arrays.toString(mWifiPickerTracker.getWifiEntries().toArray())); + } else if (mWifiPickerTracker != null) { + ipw.println("WifiPickerTracker not started, cannot get reliable entries"); + } + ipw.decreaseIndent(); } @Override - public void onWifiStateChanged(int state) { + public void onWifiStateChanged() { + scanForAccessPoints(); } @Override - public void onConnectedChanged() { - fireAcccessPointsCallback(mWifiTracker.getAccessPoints()); + public void onWifiEntriesChanged() { + scanForAccessPoints(); } @Override - public void onAccessPointsChanged() { - fireAcccessPointsCallback(mWifiTracker.getAccessPoints()); + public void onNumSavedNetworksChanged() { + // Do nothing } - private final ActionListener mConnectListener = new ActionListener() { - @Override - public void onSuccess() { - if (DEBUG) Log.d(TAG, "connect success"); - } + @Override + public void onNumSavedSubscriptionsChanged() { + // Do nothing + } + private final WifiEntry.ConnectCallback mConnectCallback = new WifiEntry.ConnectCallback() { @Override - public void onFailure(int reason) { - if (DEBUG) Log.d(TAG, "connect failure reason=" + reason); + public void onConnectResult(int status) { + if (status == CONNECT_STATUS_SUCCESS) { + if (DEBUG) Log.d(TAG, "connect success"); + } else { + if (DEBUG) Log.d(TAG, "connect failure reason=" + status); + } } }; + + /** + * Factory for creating {@link WifiPickerTracker}. + * + * Uses the same time intervals as the Settings page for Wifi. + */ + @SysUISingleton + public static class WifiPickerTrackerFactory { + + // 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 final Context mContext; + private final @Nullable WifiManager mWifiManager; + private final ConnectivityManager mConnectivityManager; + private final NetworkScoreManager mNetworkScoreManager; + private final Handler mMainHandler; + private final Handler mWorkerHandler; + private final Clock mClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.elapsedRealtime(); + } + }; + + @Inject + public WifiPickerTrackerFactory( + Context context, + @Nullable WifiManager wifiManager, + ConnectivityManager connectivityManager, + NetworkScoreManager networkScoreManager, + @Main Handler mainHandler, + @Background Handler workerHandler + ) { + mContext = context; + mWifiManager = wifiManager; + mConnectivityManager = connectivityManager; + mNetworkScoreManager = networkScoreManager; + mMainHandler = mainHandler; + mWorkerHandler = workerHandler; + } + + /** + * Create a {@link WifiPickerTracker} + * + * @param lifecycle + * @param listener + * @return a new {@link WifiPickerTracker} or {@code null} if {@link WifiManager} is null. + */ + public @Nullable WifiPickerTracker create( + Lifecycle lifecycle, + WifiPickerTracker.WifiPickerTrackerCallback listener + ) { + if (mWifiManager == null) { + return null; + } + return new WifiPickerTracker( + lifecycle, + mContext, + mWifiManager, + mConnectivityManager, + mNetworkScoreManager, + mMainHandler, + mWorkerHandler, + mClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + listener + ); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index f92860b70116..b012dc4c7159 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -21,9 +21,9 @@ import android.content.Intent; import android.telephony.SubscriptionInfo; import com.android.settingslib.net.DataUsageController; -import com.android.settingslib.wifi.AccessPoint; import com.android.systemui.demomode.DemoMode; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.wifitrackerlib.WifiEntry; import java.util.List; @@ -123,12 +123,12 @@ public interface NetworkController extends CallbackController<SignalCallback>, D void addAccessPointCallback(AccessPointCallback callback); void removeAccessPointCallback(AccessPointCallback callback); void scanForAccessPoints(); - int getIcon(AccessPoint ap); - boolean connect(AccessPoint ap); + int getIcon(WifiEntry ap); + boolean connect(WifiEntry ap); boolean canConfigWifi(); public interface AccessPointCallback { - void onAccessPointsChanged(List<AccessPoint> accessPoints); + void onAccessPointsChanged(List<WifiEntry> accessPoints); void onSettingsActivityTriggered(Intent settingsIntent); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index e41996604c99..5f5a83c5c50c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -187,6 +187,7 @@ public class NetworkControllerImpl extends BroadcastReceiver TelephonyManager telephonyManager, @Nullable WifiManager wifiManager, NetworkScoreManager networkScoreManager, + AccessPointControllerImpl accessPointController, DemoModeController demoModeController) { this(context, connectivityManager, telephonyManager, @@ -194,7 +195,7 @@ public class NetworkControllerImpl extends BroadcastReceiver networkScoreManager, SubscriptionManager.from(context), Config.readConfig(context), bgLooper, new CallbackHandler(), - new AccessPointControllerImpl(context), + accessPointController, new DataUsageController(context), new SubscriptionDefaults(), deviceProvisionedController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index 914105fdc4c4..069b4051af50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -16,6 +16,12 @@ package com.android.systemui.statusbar.policy.dagger; +import android.os.UserManager; + +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.policy.AccessPointControllerImpl; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.BluetoothControllerImpl; import com.android.systemui.statusbar.policy.CastController; @@ -45,8 +51,11 @@ import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.ZenModeControllerImpl; +import java.util.concurrent.Executor; + import dagger.Binds; import dagger.Module; +import dagger.Provides; /** Dagger Module for code in the statusbar.policy package. */ @@ -109,4 +118,27 @@ public interface StatusBarPolicyModule { @Binds ZenModeController provideZenModeController(ZenModeControllerImpl controllerImpl); + /** */ + @Binds + NetworkController.AccessPointController provideAccessPointController( + AccessPointControllerImpl accessPointControllerImpl); + + /** */ + @SysUISingleton + @Provides + static AccessPointControllerImpl provideAccessPointControllerImpl( + UserManager userManager, + UserTracker userTracker, + @Main Executor mainExecutor, + AccessPointControllerImpl.WifiPickerTrackerFactory wifiPickerTrackerFactory + ) { + AccessPointControllerImpl controller = new AccessPointControllerImpl( + userManager, + userTracker, + mainExecutor, + wifiPickerTrackerFactory + ); + controller.init(); + return controller; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/AccessPointControllerImplTest.kt new file mode 100644 index 000000000000..4068f93f5ee3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/AccessPointControllerImplTest.kt @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2020 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.systemui.statusbar.policy + +import android.os.UserManager +import android.test.suitebuilder.annotation.SmallTest +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.lifecycle.Lifecycle +import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.mockito.capture +import com.android.wifitrackerlib.WifiEntry +import com.android.wifitrackerlib.WifiPickerTracker +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyList +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations +import java.util.concurrent.Executor + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@RunWithLooper(setAsMainLooper = true) +class AccessPointControllerImplTest : SysuiTestCase() { + + @Mock + private lateinit var userManager: UserManager + @Mock + private lateinit var userTracker: UserTracker + @Mock + private lateinit var wifiPickerTrackerFactory: + AccessPointControllerImpl.WifiPickerTrackerFactory + @Mock + private lateinit var wifiPickerTracker: WifiPickerTracker + @Mock + private lateinit var callback: NetworkController.AccessPointController.AccessPointCallback + @Mock + private lateinit var otherCallback: NetworkController.AccessPointController.AccessPointCallback + @Mock + private lateinit var wifiEntryConnected: WifiEntry + @Mock + private lateinit var wifiEntryOther: WifiEntry + @Captor + private lateinit var wifiEntryListCaptor: ArgumentCaptor<List<WifiEntry>> + + private val instantExecutor = Executor { it.run() } + private lateinit var controller: AccessPointControllerImpl + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + `when`(wifiPickerTrackerFactory.create(any(), any())).thenReturn(wifiPickerTracker) + + `when`(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntryConnected) + `when`(wifiPickerTracker.wifiEntries).thenReturn(ArrayList<WifiEntry>().apply { + add(wifiEntryOther) + }) + + controller = AccessPointControllerImpl( + userManager, + userTracker, + instantExecutor, + wifiPickerTrackerFactory + ) + + controller.init() + } + + @Test + fun testInitialLifecycleStateCreated() { + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) + } + + @Test + fun testLifecycleStartedAfterFirstCallback() { + controller.addAccessPointCallback(callback) + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) + } + + @Test + fun testLifecycleBackToCreatedAfterRemovingOnlyCallback() { + controller.addAccessPointCallback(callback) + controller.removeAccessPointCallback(callback) + + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) + } + + @Test + fun testLifecycleStillStartedAfterRemovingSecondCallback() { + controller.addAccessPointCallback(callback) + controller.addAccessPointCallback(otherCallback) + controller.removeAccessPointCallback(callback) + + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) + } + + @Test + fun testScanForAccessPointsTriggersCallbackWithEntriesInOrder() { + controller.addAccessPointCallback(callback) + controller.scanForAccessPoints() + + verify(callback).onAccessPointsChanged(capture(wifiEntryListCaptor)) + + assertThat(wifiEntryListCaptor.value).containsExactly(wifiEntryConnected, wifiEntryOther) + } + + @Test + fun testOnWifiStateChangedTriggersCallbackWithEntriesInOrder() { + controller.addAccessPointCallback(callback) + controller.onWifiStateChanged() + + verify(callback).onAccessPointsChanged(capture(wifiEntryListCaptor)) + + assertThat(wifiEntryListCaptor.value).containsExactly(wifiEntryConnected, wifiEntryOther) + } + + @Test + fun testOnWifiEntriesChangedTriggersCallbackWithEntriesInOrder() { + controller.addAccessPointCallback(callback) + controller.onWifiEntriesChanged() + + verify(callback).onAccessPointsChanged(capture(wifiEntryListCaptor)) + + assertThat(wifiEntryListCaptor.value).containsExactly(wifiEntryConnected, wifiEntryOther) + } + + @Test + fun testOnNumSavedNetworksChangedDoesntTriggerCallback() { + controller.addAccessPointCallback(callback) + controller.onNumSavedNetworksChanged() + + verify(callback, never()).onAccessPointsChanged(anyList()) + } + + @Test + fun testOnNumSavedSubscriptionsChangedDoesntTriggerCallback() { + controller.addAccessPointCallback(callback) + controller.onNumSavedSubscriptionsChanged() + + verify(callback, never()).onAccessPointsChanged(anyList()) + } + + @Test + fun testReturnEmptyListWhenNoWifiPickerTracker() { + `when`(wifiPickerTrackerFactory.create(any(), any())).thenReturn(null) + val otherController = AccessPointControllerImpl( + userManager, + userTracker, + instantExecutor, + wifiPickerTrackerFactory + ) + otherController.init() + + otherController.addAccessPointCallback(callback) + otherController.scanForAccessPoints() + + verify(callback).onAccessPointsChanged(capture(wifiEntryListCaptor)) + + assertThat(wifiEntryListCaptor.value).isEmpty() + } + + @Test + fun connectToNullEntry() { + controller.addAccessPointCallback(callback) + + assertThat(controller.connect(null)).isFalse() + + verify(callback, never()).onSettingsActivityTriggered(any()) + } + + @Test + fun connectToSavedWifiEntry() { + controller.addAccessPointCallback(callback) + `when`(wifiEntryOther.isSaved).thenReturn(true) + + assertThat(controller.connect(wifiEntryOther)).isFalse() + + verify(wifiEntryOther).connect(any()) + verify(callback, never()).onSettingsActivityTriggered(any()) + } + + @Test + fun connectToSecuredNotSavedWifiEntry() { + controller.addAccessPointCallback(callback) + `when`(wifiEntryOther.isSaved).thenReturn(false) + `when`(wifiEntryOther.security).thenReturn(WifiEntry.SECURITY_EAP) + + // True means we will launch WifiSettings + assertThat(controller.connect(wifiEntryOther)).isTrue() + + verify(wifiEntryOther, never()).connect(any()) + verify(callback).onSettingsActivityTriggered(any()) + } + + @Test + fun connectToNotSecuredNotSavedWifiEntry() { + controller.addAccessPointCallback(callback) + `when`(wifiEntryOther.isSaved).thenReturn(false) + `when`(wifiEntryOther.security).thenReturn(WifiEntry.SECURITY_NONE) + + assertThat(controller.connect(wifiEntryOther)).isFalse() + + verify(wifiEntryOther).connect(any()) + verify(callback, never()).onSettingsActivityTriggered(any()) + } +}
\ No newline at end of file |