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

Commit 88074f36 authored by Alex Kingsborough's avatar Alex Kingsborough
Browse files

Make instant hotspot multi user

Change-Id: If9921497d7b29955720a82f22f77b86c61857ad6
Bug: 371586248
Test: Manually connect to hotspot via Quick Settings
Test: atest passing for all affected unittest files
Flag: com.android.systemui.multiuser_wifi_picker_tracker_support
parent 66883bf0
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,16 @@ flag {
    bug: "302578396"
    bug: "302578396"
}
}


flag {
   name: "multiuser_wifi_picker_tracker_support"
   namespace: "systemui"
   description: "Adds WifiPickerTracker support for multiple users to support when HSUM is enabled."
   bug: "371586248"
   metadata {
        purpose: PURPOSE_BUGFIX
   }
}

flag {
flag {
   name: "udfps_view_performance"
   name: "udfps_view_performance"
   namespace: "systemui"
   namespace: "systemui"
+50 −35
Original line number Original line Diff line number Diff line
@@ -16,18 +16,22 @@


package com.android.systemui.statusbar.connectivity
package com.android.systemui.statusbar.connectivity


import android.content.Context
import android.os.UserHandle
import android.os.UserManager
import android.os.UserManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import android.platform.test.annotations.EnableFlags
import androidx.test.filters.SmallTest
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableLooper.RunWithLooper
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.capture
import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiPickerTracker
import com.android.wifitrackerlib.WifiPickerTracker
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
@@ -35,36 +39,28 @@ import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyList
import org.mockito.ArgumentMatchers.anyList
import org.mockito.Captor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoAnnotations
import java.util.concurrent.Executor
import org.mockito.kotlin.any
import org.mockito.kotlin.mock


@SmallTest
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@RunWithLooper(setAsMainLooper = true)
class AccessPointControllerImplTest : SysuiTestCase() {
class AccessPointControllerImplTest : SysuiTestCase() {


    @Mock
    @Mock private lateinit var userManager: UserManager
    private lateinit var userManager: UserManager
    @Mock private lateinit var userTracker: UserTracker
    @Mock
    @Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
    private lateinit var userTracker: UserTracker
    @Mock private lateinit var wifiPickerTracker: WifiPickerTracker
    @Mock
    @Mock private lateinit var callback: AccessPointController.AccessPointCallback
    private lateinit var wifiPickerTrackerFactory:
    @Mock private lateinit var otherCallback: AccessPointController.AccessPointCallback
            WifiPickerTrackerFactory
    @Mock private lateinit var wifiEntryConnected: WifiEntry
    @Mock
    @Mock private lateinit var wifiEntryOther: WifiEntry
    private lateinit var wifiPickerTracker: WifiPickerTracker
    @Captor private lateinit var wifiEntryListCaptor: ArgumentCaptor<List<WifiEntry>>
    @Mock
    private lateinit var callback: AccessPointController.AccessPointCallback
    @Mock
    private lateinit var otherCallback: 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 val instantExecutor = Executor { it.run() }
    private lateinit var controller: AccessPointControllerImpl
    private lateinit var controller: AccessPointControllerImpl
@@ -72,18 +68,20 @@ class AccessPointControllerImplTest : SysuiTestCase() {
    @Before
    @Before
    fun setUp() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        MockitoAnnotations.initMocks(this)
        `when`(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(wifiPickerTracker)
        `when`(wifiPickerTrackerFactory.create(any(), any(), any(), any()))
            .thenReturn(wifiPickerTracker)


        `when`(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntryConnected)
        `when`(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntryConnected)
        `when`(wifiPickerTracker.wifiEntries).thenReturn(ArrayList<WifiEntry>().apply {
        `when`(wifiPickerTracker.wifiEntries)
            add(wifiEntryOther)
            .thenReturn(ArrayList<WifiEntry>().apply { add(wifiEntryOther) })
        })


        controller = AccessPointControllerImpl(
        controller =
            AccessPointControllerImpl(
                mContext,
                userManager,
                userManager,
                userTracker,
                userTracker,
                instantExecutor,
                instantExecutor,
                wifiPickerTrackerFactory
                wifiPickerTrackerFactory,
            )
            )


        controller.init()
        controller.init()
@@ -183,12 +181,14 @@ class AccessPointControllerImplTest : SysuiTestCase() {


    @Test
    @Test
    fun testReturnEmptyListWhenNoWifiPickerTracker() {
    fun testReturnEmptyListWhenNoWifiPickerTracker() {
        `when`(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(null)
        `when`(wifiPickerTrackerFactory.create(any(), any(), any(), any())).thenReturn(null)
        val otherController = AccessPointControllerImpl(
        val otherController =
            AccessPointControllerImpl(
                mContext,
                userManager,
                userManager,
                userTracker,
                userTracker,
                instantExecutor,
                instantExecutor,
                wifiPickerTrackerFactory
                wifiPickerTrackerFactory,
            )
            )
        otherController.init()
        otherController.init()


@@ -244,4 +244,19 @@ class AccessPointControllerImplTest : SysuiTestCase() {
        verify(wifiEntryOther).connect(any())
        verify(wifiEntryOther).connect(any())
        verify(callback, never()).onSettingsActivityTriggered(any())
        verify(callback, never()).onSettingsActivityTriggered(any())
    }
    }

    @Test
    @EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT)
    fun switchUsers() {
        val primaryUserMockContext = mock<Context>()
        mContext.prepareCreateContextAsUser(UserHandle.of(PRIMARY_USER_ID), primaryUserMockContext)
        controller.onUserSwitched(PRIMARY_USER_ID)
        // Create is expected to be called once when the test starts and a second time when the user
        // is switched.
        verify(wifiPickerTrackerFactory, times(2)).create(any(), any(), any(), any())
    }

    private companion object {
        private const val PRIMARY_USER_ID = 1
    }
}
}
+7 −6
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoMod
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.kotlinArgumentCaptor
@@ -71,6 +72,7 @@ class WifiRepositorySwitcherTest : SysuiTestCase() {
    private val demoModelFlow = MutableStateFlow<FakeWifiEventModel?>(null)
    private val demoModelFlow = MutableStateFlow<FakeWifiEventModel?>(null)


    private val mainExecutor = FakeExecutor(FakeSystemClock())
    private val mainExecutor = FakeExecutor(FakeSystemClock())
    private val userRepository = FakeUserRepository()


    private val testDispatcher = UnconfinedTestDispatcher()
    private val testDispatcher = UnconfinedTestDispatcher()
    private val testScope = TestScope(testDispatcher)
    private val testScope = TestScope(testDispatcher)
@@ -82,10 +84,13 @@ class WifiRepositorySwitcherTest : SysuiTestCase() {
        // Never start in demo mode
        // Never start in demo mode
        whenever(demoModeController.isInDemoMode).thenReturn(false)
        whenever(demoModeController.isInDemoMode).thenReturn(false)


        whenever(wifiPickerTrackerFactory.create(any(), any(), any())).thenReturn(wifiPickerTracker)
        whenever(wifiPickerTrackerFactory.create(any(), any(), any(), any()))
            .thenReturn(wifiPickerTracker)


        realImpl =
        realImpl =
            WifiRepositoryImpl(
            WifiRepositoryImpl(
                mContext,
                userRepository,
                testScope.backgroundScope,
                testScope.backgroundScope,
                mainExecutor,
                mainExecutor,
                testDispatcher,
                testDispatcher,
@@ -97,11 +102,7 @@ class WifiRepositorySwitcherTest : SysuiTestCase() {


        whenever(demoModeWifiDataSource.wifiEvents).thenReturn(demoModelFlow)
        whenever(demoModeWifiDataSource.wifiEvents).thenReturn(demoModelFlow)


        demoImpl =
        demoImpl = DemoWifiRepository(demoModeWifiDataSource, testScope.backgroundScope)
            DemoWifiRepository(
                demoModeWifiDataSource,
                testScope.backgroundScope,
            )


        underTest =
        underTest =
            WifiRepositorySwitcher(
            WifiRepositorySwitcher(
+24 −1
Original line number Original line Diff line number Diff line
@@ -16,6 +16,9 @@


package com.android.systemui.statusbar.connectivity;
package com.android.systemui.statusbar.connectivity;


import static com.android.systemui.Flags.multiuserWifiPickerTrackerSupport;

import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
@@ -65,13 +68,16 @@ public class AccessPointControllerImpl implements AccessPointController,
    private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
    private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);


    private int mCurrentUser;
    private int mCurrentUser;
    private Context mContext;


    public AccessPointControllerImpl(
    public AccessPointControllerImpl(
            Context context,
            UserManager userManager,
            UserManager userManager,
            UserTracker userTracker,
            UserTracker userTracker,
            Executor mainExecutor,
            Executor mainExecutor,
            WifiPickerTrackerFactory wifiPickerTrackerFactory
            WifiPickerTrackerFactory wifiPickerTrackerFactory
    ) {
    ) {
        mContext = context;
        mUserManager = userManager;
        mUserManager = userManager;
        mUserTracker = userTracker;
        mUserTracker = userTracker;
        mCurrentUser = userTracker.getUserId();
        mCurrentUser = userTracker.getUserId();
@@ -87,7 +93,11 @@ public class AccessPointControllerImpl implements AccessPointController,
     */
     */
    public void init() {
    public void init() {
        if (mWifiPickerTracker == null) {
        if (mWifiPickerTracker == null) {
            mWifiPickerTracker = mWifiPickerTrackerFactory.create(this.getLifecycle(), this, TAG);
            // We are creating the WifiPickerTracker during init to make sure we have one
            // available at all times however we expect this to be recreated very quickly
            // with a user-specific context in onUserSwitched.
            mWifiPickerTracker =
                mWifiPickerTrackerFactory.create(mContext, this.getLifecycle(), this, TAG);
        }
        }
    }
    }


@@ -116,6 +126,19 @@ public class AccessPointControllerImpl implements AccessPointController,


    void onUserSwitched(int newUserId) {
    void onUserSwitched(int newUserId) {
        mCurrentUser = newUserId;
        mCurrentUser = newUserId;
        // Return early if multiuser support is not enabled.
        if (!multiuserWifiPickerTrackerSupport()) {
            return;
        }

        if (mWifiPickerTracker != null) {
            mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.CREATED));
        }
        Context context = mContext.createContextAsUser(UserHandle.of(newUserId), /* flags= */ 0);
        mWifiPickerTracker = mWifiPickerTrackerFactory.create(context, mLifecycle, this, TAG);
        if (!mCallbacks.isEmpty()) {
            mMainExecutor.execute(() -> mLifecycle.setCurrentState(Lifecycle.State.STARTED));
        }
    }
    }


    @Override
    @Override
+12 −3
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.net.wifi.WifiManager
import android.os.Handler
import android.os.Handler
import android.os.SimpleClock
import android.os.SimpleClock
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle
import com.android.systemui.Flags.multiuserWifiPickerTrackerSupport
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.util.concurrency.ThreadFactory
import com.android.systemui.util.concurrency.ThreadFactory
@@ -41,7 +42,7 @@ import javax.inject.Inject
class WifiPickerTrackerFactory
class WifiPickerTrackerFactory
@Inject
@Inject
constructor(
constructor(
    private val context: Context,
    private val applicationContext: Context,
    private val wifiManager: WifiManager?,
    private val wifiManager: WifiManager?,
    private val connectivityManager: ConnectivityManager,
    private val connectivityManager: ConnectivityManager,
    private val systemClock: SystemClock,
    private val systemClock: SystemClock,
@@ -64,16 +65,23 @@ constructor(
     * @return a new [WifiPickerTracker] or null if [WifiManager] is null.
     * @return a new [WifiPickerTracker] or null if [WifiManager] is null.
     */
     */
    fun create(
    fun create(
        userContext: Context,
        lifecycle: Lifecycle,
        lifecycle: Lifecycle,
        listener: WifiPickerTrackerCallback,
        listener: WifiPickerTrackerCallback,
        name: String,
        name: String,
    ): WifiPickerTracker? {
    ): WifiPickerTracker? {
        return if (wifiManager == null) {
        return if (wifiManager == null) {
            null
            null
        } else
        } else {
            val contextToUse =
                if (multiuserWifiPickerTrackerSupport()) {
                    userContext
                } else {
                    applicationContext
                }
            WifiPickerTracker(
            WifiPickerTracker(
                lifecycle,
                lifecycle,
                context,
                contextToUse,
                wifiManager,
                wifiManager,
                connectivityManager,
                connectivityManager,
                mainHandler,
                mainHandler,
@@ -87,6 +95,7 @@ constructor(
                listener,
                listener,
            )
            )
        }
        }
    }


    companion object {
    companion object {
        /** Max age of tracked WifiEntries. */
        /** Max age of tracked WifiEntries. */
Loading