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

Commit dc67f4d2 authored by Sundeep Ghuman's avatar Sundeep Ghuman
Browse files

Change WifiListenerWrapper to WifiListenExecutor.

The executor no longer instantiates it's on main thread handler, and
instead uses ThreadUtils.postOnMainThread.

Also clean up WifiTracker tests, since the custom Handlers have been
removed, and the broadcast receiver method is invoked directly in the
tests, it is no longer necessary to wait for handlers to finish processing
messages.

Although the only asynchronous source code (invocation of WifiListener
methods) is now mockable via WifiListenerExecutor injection,
CountDownLatches used in cases where verifying multiple mock invocations
would be confusing due to test setup behavior.

Bug: 68030053
Test: runtest --path
    frameworks/base/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java

Change-Id: I485c62d81ec2cdd3d53ed3e258ae6b40837cdc51
parent bcb5373c
Loading
Loading
Loading
Loading
+21 −18
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiNetworkScoreCache.CacheListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.SystemClock;
@@ -112,7 +111,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    private final ConnectivityManager mConnectivityManager;
    private final NetworkRequest mNetworkRequest;
    private final AtomicBoolean mConnected = new AtomicBoolean(false);
    private final WifiListener mListener;
    private final WifiListenerExecutor mListener;
    @VisibleForTesting Handler mWorkHandler;
    private HandlerThread mWorkThread;

@@ -178,7 +177,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    @Deprecated
    public WifiTracker(Context context, WifiListener wifiListener,
            boolean includeSaved, boolean includeScans) {
        this(context, wifiListener,
        this(context, new WifiListenerExecutor(wifiListener),
                context.getSystemService(WifiManager.class),
                context.getSystemService(ConnectivityManager.class),
                context.getSystemService(NetworkScoreManager.class),
@@ -189,7 +188,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    // calling apps once IC window is complete
    public WifiTracker(Context context, WifiListener wifiListener,
            @NonNull Lifecycle lifecycle, boolean includeSaved, boolean includeScans) {
        this(context, wifiListener,
        this(context, new WifiListenerExecutor(wifiListener),
                context.getSystemService(WifiManager.class),
                context.getSystemService(ConnectivityManager.class),
                context.getSystemService(NetworkScoreManager.class),
@@ -198,13 +197,13 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    }

    @VisibleForTesting
    WifiTracker(Context context, WifiListener wifiListener,
    WifiTracker(Context context, WifiListenerExecutor wifiListenerExecutor,
            WifiManager wifiManager, ConnectivityManager connectivityManager,
            NetworkScoreManager networkScoreManager,
            IntentFilter filter) {
        mContext = context;
        mWifiManager = wifiManager;
        mListener = new WifiListenerWrapper(wifiListener);
        mListener = wifiListenerExecutor;
        mConnectivityManager = connectivityManager;

        // check if verbose logging developer option has been turned on or off
@@ -776,6 +775,8 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
                        || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
                    updateAccessPoints();
                } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
                    // TODO(sghuman): Refactor these methods so they cannot result in duplicate
                    // onAccessPointsChanged updates being called from this intent.
                    NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                    updateNetworkInfo(info);
                    updateAccessPoints();
@@ -886,19 +887,16 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    }

    /**
     * Wraps the given {@link WifiListener} instance and executes it's methods on the Main Thread.
     * Wraps the given {@link WifiListener} instance and executes its methods on the Main Thread.
     *
     * <p>This mechanism allows us to no longer need a separate MainHandler and WorkHandler, which
     * were previously both performing work, while avoiding errors which occur from executing
     * callbacks which manipulate UI elements from a different thread than the MainThread.
     * <p>Also logs all callbacks invocations when verbose logging is enabled.
     */
    private static class WifiListenerWrapper implements WifiListener {
    @VisibleForTesting
    public static class WifiListenerExecutor implements WifiListener {

        private final Handler mHandler;
        private final WifiListener mDelegatee;

        public WifiListenerWrapper(WifiListener listener) {
            mHandler = new Handler(Looper.getMainLooper());
        public WifiListenerExecutor(WifiListener listener) {
            mDelegatee = listener;
        }

@@ -908,7 +906,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
                Log.i(TAG,
                        String.format("Invoking onWifiStateChanged callback with state %d", state));
            }
            mHandler.post(() -> mDelegatee.onWifiStateChanged(state));
            ThreadUtils.postOnMainThread(() -> mDelegatee.onWifiStateChanged(state));
        }

        @Override
@@ -916,7 +914,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
            if (isVerboseLoggingEnabled()) {
                Log.i(TAG, "Invoking onConnectedChanged callback");
            }
            mHandler.post(() -> mDelegatee.onConnectedChanged());
            ThreadUtils.postOnMainThread(() -> mDelegatee.onConnectedChanged());
        }

        @Override
@@ -924,10 +922,15 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
            if (isVerboseLoggingEnabled()) {
                Log.i(TAG, "Invoking onAccessPointsChanged callback");
            }
            mHandler.post(() -> mDelegatee.onAccessPointsChanged());
            ThreadUtils.postOnMainThread(() -> mDelegatee.onAccessPointsChanged());
        }
    }

    /**
     * WifiListener interface that defines callbacks indicating state changes in WifiTracker.
     *
     * <p>All callbacks are invoked on the MainThread.
     */
    public interface WifiListener {
        /**
         * Called when the state of Wifi has changed, the state will be one of
@@ -958,7 +961,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
    }

    /**
     * Invokes {@link WifiListenerWrapper#onAccessPointsChanged()} if {@link #mStaleScanResults}
     * Invokes {@link WifiListenerExecutor#onAccessPointsChanged()} if {@link #mStaleScanResults}
     * is false.
     */
    private void conditionallyNotifyListeners() {
+44 −85
Original line number Diff line number Diff line
@@ -21,16 +21,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.content.Context;
@@ -56,7 +55,6 @@ import android.os.HandlerThread;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

@@ -78,7 +76,6 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

// TODO(sghuman): Change these to robolectric tests b/35766684.

@@ -138,7 +135,7 @@ public class WifiTrackerTest {
    @Mock private RssiCurve mockBadgeCurve1;
    @Mock private RssiCurve mockBadgeCurve2;
    @Mock private WifiManager mockWifiManager;
    @Mock private WifiTracker.WifiListener mockWifiListener;
    @Mock private WifiTracker.WifiListenerExecutor mockWifiListenerExecutor;

    private final List<NetworkKey> mRequestedKeys = new ArrayList<>();

@@ -150,6 +147,7 @@ public class WifiTrackerTest {

    private int mOriginalScoringUiSettingValue;

    @SuppressWarnings("VisibleForTests")
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -200,17 +198,14 @@ public class WifiTrackerTest {
                    }
                }).when(mockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());

        doAnswer(
                new Answer<Void>() {
                  @Override
                  public Void answer (InvocationOnMock invocation) throws Throwable {
        // We use a latch to detect callbacks as Tracker initialization state often invokes
        // callbacks
        doAnswer(invocation -> {
                    if (mAccessPointsChangedLatch != null) {
                      mAccessPointsChangedLatch.countDown();
                    }

                    return null;
                  }
                }).when(mockWifiListener).onAccessPointsChanged();
                }).when(mockWifiListenerExecutor).onAccessPointsChanged();

        // Turn on Scoring UI features
        mOriginalScoringUiSettingValue = Settings.Global.getInt(
@@ -268,8 +263,7 @@ public class WifiTrackerTest {
            tracker.mReceiver.onReceive(mContext, intent);
        }

        sendScanResultsAndProcess(tracker);
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        sendScanResults(tracker);

        return tracker;
    }
@@ -277,7 +271,7 @@ public class WifiTrackerTest {
    private WifiTracker createMockedWifiTracker() {
        final WifiTracker wifiTracker = new WifiTracker(
                mContext,
                mockWifiListener,
                mockWifiListenerExecutor,
                mockWifiManager,
                mockConnectivityManager,
                mockNetworkScoreManager,
@@ -288,26 +282,19 @@ public class WifiTrackerTest {

    private void startTracking(WifiTracker tracker)  throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        mScannerHandler.post(new Runnable() {
            @Override
            public void run() {
        mScannerHandler.post(() -> {
                tracker.onStart();
                latch.countDown();
            }
        });
        assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
    }

    private void sendScanResultsAndProcess(WifiTracker tracker) throws InterruptedException {
        mAccessPointsChangedLatch = new CountDownLatch(1);
    private void sendScanResults(WifiTracker tracker) throws InterruptedException {
        Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        tracker.mReceiver.onReceive(mContext, i);

        assertTrue("Latch timed out",
                mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
    }

    private void updateScores() {
    private void sendUpdatedScores() throws InterruptedException {
        Bundle attr1 = new Bundle();
        attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve1);
        ScoredNetwork sc1 =
@@ -353,12 +340,8 @@ public class WifiTrackerTest {

    private void waitForHandlersToProcessCurrentlyEnqueuedMessages(WifiTracker tracker)
            throws InterruptedException {
        // TODO(sghuman): This should no longer be necessary in a single work handler model

        CountDownLatch workerLatch = new CountDownLatch(1);
        tracker.mWorkHandler.post(() -> {
            workerLatch.countDown();
        });
        tracker.mWorkHandler.post(() -> workerLatch.countDown());
        assertTrue("Latch timed out while waiting for WorkerHandler",
                workerLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
    }
@@ -378,7 +361,6 @@ public class WifiTrackerTest {
        Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
        tracker.mReceiver.onReceive(mContext, intent);
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
    }

    @Test
@@ -467,7 +449,7 @@ public class WifiTrackerTest {
            throws InterruptedException {
        // Start the tracker and inject the initial scan results and then stop tracking
        WifiTracker tracker =  createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);
        tracker.onStop();

        assertThat(mScoreCacheCaptor.getValue().getScoredNetwork(NETWORK_KEY_1)).isNotNull();
@@ -478,19 +460,18 @@ public class WifiTrackerTest {
            throws InterruptedException {
        WifiTracker tracker = createMockedWifiTracker();
        startTracking(tracker);
        sendScanResultsAndProcess(tracker);
        sendScanResults(tracker);

        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);
    }

    private void updateScoresAndWaitForAccessPointsChangedCallback(WifiTracker tracker)
    private void updateScoresAndWaitForCacheListenerToProcess(WifiTracker tracker)
            throws InterruptedException {
        // Updating scores can happen together or one after the other, so the latch countdown is set
        // to 2.
        mAccessPointsChangedLatch = new CountDownLatch(1);
        updateScores();
        assertTrue("onAccessPointChanged was not called after updating scores",
            mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
        // Scores are updated via the cache listener hence we need to wait for the work handler
        // to finish before proceeding.
        sendUpdatedScores();

        // Ensure the work handler has processed the scores inside the cache listener of WifiTracker
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
    }

@@ -502,7 +483,7 @@ public class WifiTrackerTest {
        assertEquals(aps.get(0).getSsidStr(), SSID_1);
        assertEquals(aps.get(1).getSsidStr(), SSID_2);

        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);

        aps = tracker.getAccessPoints();
        assertTrue(aps.size() == 2);
@@ -524,7 +505,7 @@ public class WifiTrackerTest {
        assertEquals(aps.get(0).getSsidStr(), SSID_1);
        assertEquals(aps.get(1).getSsidStr(), SSID_2);

        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);

        aps = tracker.getAccessPoints();
        assertTrue(aps.size() == 2);
@@ -532,12 +513,11 @@ public class WifiTrackerTest {
        assertEquals(aps.get(1).getSsidStr(), SSID_2);
    }

    @FlakyTest
    @Test
    public void scoreCacheUpdateScoresShouldInsertSpeedIntoAccessPoint()
            throws InterruptedException {
        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);

        List<AccessPoint> aps = tracker.getAccessPoints();

@@ -554,7 +534,7 @@ public class WifiTrackerTest {
    public void scoreCacheUpdateMeteredShouldUpdateAccessPointMetering()
            throws InterruptedException {
        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);

        List<AccessPoint> aps = tracker.getAccessPoints();

@@ -576,7 +556,7 @@ public class WifiTrackerTest {
                0 /* disabled */);

        WifiTracker tracker = createTrackerWithImmediateBroadcastsAndInjectInitialScanResults();
        updateScoresAndWaitForAccessPointsChangedCallback(tracker);
        updateScoresAndWaitForCacheListenerToProcess(tracker);

        List<AccessPoint> aps = tracker.getAccessPoints();

@@ -614,7 +594,7 @@ public class WifiTrackerTest {
                .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2(), newResult));

        mRequestScoresLatch = new CountDownLatch(1);
        sendScanResultsAndProcess(tracker);
        sendScanResults(tracker);
        assertTrue(mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));

        assertEquals(1, mRequestedKeys.size());
@@ -633,7 +613,7 @@ public class WifiTrackerTest {
        // Verify listener is unregistered so updating a score does not throw an error by posting
        // a message to the dead work handler
        mWorkerThread.quit();
        updateScores();
        sendUpdatedScores();
    }

    /**
@@ -679,21 +659,14 @@ public class WifiTrackerTest {
        WifiInfo info = new WifiInfo(CONNECTED_AP_1_INFO);
        info.setRssi(newRssi);

        CountDownLatch latch = new CountDownLatch(1);

        // Once the new info has been fetched, we need to wait for the access points to be copied
        mAccessPointsChangedLatch = new CountDownLatch(1);
        doAnswer(invocation -> {
                    latch.countDown();
                    return info;
                }).when(mockWifiManager).getConnectionInfo();
        doAnswer(invocation -> info).when(mockWifiManager).getConnectionInfo();

        tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.RSSI_CHANGED_ACTION));
        assertTrue("New connection info never retrieved",
                latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));

        assertTrue("onAccessPointsChanged never called",
                mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));

        assertThat(tracker.getAccessPoints().get(0).getRssi()).isEqualTo(newRssi);
    }

@@ -716,7 +689,8 @@ public class WifiTrackerTest {
        verify(mockWifiManager, times(1)).getConfiguredNetworks();
        verify(mockConnectivityManager).getNetworkInfo(any(Network.class));

        verify(mockWifiListener, never()).onAccessPointsChanged(); // mStaleAccessPoints is true
        // mStaleAccessPoints is true
        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
        assertThat(tracker.getAccessPoints().size()).isEqualTo(2);
        assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
    }
@@ -748,18 +722,11 @@ public class WifiTrackerTest {
        } catch (InterruptedException e) {}
        tracker.onStop();

        // TODO(sghuman): Delete these in a following CL, no longer necessary (should be
        // invoked 0 times)
        verify(mockWifiListener, atMost(1)).onAccessPointsChanged();
        verify(mockWifiListener, atMost(1)).onConnectedChanged();
        verify(mockWifiListener, atMost(1)).onWifiStateChanged(anyInt());

        lock.countDown();
        assertTrue("Latch timed out", latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));

        assertThat(tracker.mWorkHandler.hasMessagesOrCallbacks()).isFalse();
        // In case the method was already executing
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        assertThat(tracker.mWorkHandler.hasMessagesOrCallbacks()).isFalse();

        assertThat(executed.get()).isFalse();
    }
@@ -769,10 +736,8 @@ public class WifiTrackerTest {
            throws Exception {
        WifiTracker tracker = createMockedWifiTracker();
        startTracking(tracker);
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);

        tracker.onStop();
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);

        startTracking(tracker);

@@ -782,11 +747,10 @@ public class WifiTrackerTest {
        tracker.mReceiver.onReceive(
                mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));

        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);

        verify(mockWifiListener, never()).onAccessPointsChanged();
        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();

        sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
        sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
    }

    @Test
@@ -794,7 +758,6 @@ public class WifiTrackerTest {
            throws Exception {
        WifiTracker tracker = createMockedWifiTracker();
        startTracking(tracker);
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);

        tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
        tracker.mReceiver.onReceive(
@@ -802,10 +765,9 @@ public class WifiTrackerTest {
        tracker.mReceiver.onReceive(
                mContext, new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION));

        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        verify(mockWifiListener, never()).onAccessPointsChanged();
        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();

        sendScanResultsAndProcess(tracker); // verifies onAccessPointsChanged is invoked
        sendScanResults(tracker); // verifies onAccessPointsChanged is invoked
    }

    @Test
@@ -813,11 +775,10 @@ public class WifiTrackerTest {
        WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();

        when(mockWifiManager.isWifiEnabled()).thenReturn(false);

        mAccessPointsChangedLatch = new CountDownLatch(1);
        tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));

        assertTrue(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));

        assertThat(tracker.getAccessPoints()).isEmpty();
    }
@@ -825,7 +786,7 @@ public class WifiTrackerTest {
    @Test
    public void onConnectedChangedCallback_shouldNotBeInvokedWhenNoStateChange() throws Exception {
        WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
        verify(mockWifiListener, times(1)).onConnectedChanged();
        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();

        NetworkInfo networkInfo = new NetworkInfo(
                ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -835,14 +796,13 @@ public class WifiTrackerTest {
        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
        tracker.mReceiver.onReceive(mContext, intent);

        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        verify(mockWifiListener, times(1)).onConnectedChanged();
        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();
    }

    @Test
    public void onConnectedChangedCallback_shouldBeInvokedWhenStateChanges() throws Exception {
        WifiTracker tracker = createTrackerWithScanResultsAndAccessPoint1Connected();
        verify(mockWifiListener, times(1)).onConnectedChanged();
        verify(mockWifiListenerExecutor, times(1)).onConnectedChanged();

        NetworkInfo networkInfo = new NetworkInfo(
                ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
@@ -853,9 +813,8 @@ public class WifiTrackerTest {
        intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
        tracker.mReceiver.onReceive(mContext, intent);

        waitForHandlersToProcessCurrentlyEnqueuedMessages(tracker);
        assertThat(tracker.isConnected()).isFalse();
        verify(mockWifiListener, times(2)).onConnectedChanged();
        verify(mockWifiListenerExecutor, times(2)).onConnectedChanged();
    }

    @Test