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

Commit ababec02 authored by Behnam Heydarshahi's avatar Behnam Heydarshahi Committed by Android (Google) Code Review
Browse files

Merge "Use main thread when creating internet signal icon" into main

parents 82f3a959 f7f4bab7
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -58,13 +58,16 @@ import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupReposi
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@TestableLooper.RunWithLooper
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class InternetTileDataInteractorTest : SysuiTestCase() {
@@ -141,6 +144,7 @@ class InternetTileDataInteractorTest : SysuiTestCase() {
        underTest =
            InternetTileDataInteractor(
                context,
                testScope.coroutineContext,
                testScope.backgroundScope,
                airplaneModeRepository,
                connectivityRepository,
@@ -433,8 +437,44 @@ class InternetTileDataInteractorTest : SysuiTestCase() {
                .isEqualTo(expectedCd)
        }

    /**
     * We expect a RuntimeException because [underTest] instantiates a SignalDrawable on the
     * provided context, and so the SignalDrawable constructor attempts to instantiate a Handler()
     * on the mentioned context. Since that context does not have a looper assigned to it, the
     * handler instantiation will throw a RuntimeException.
     *
     * TODO(b/338068066): Robolectric behavior differs in that it does not throw the exception
     * So either we should make Robolectric behvase similar to the device test, or change this
     * test to look for a different signal than the exception, when run by Robolectric. For now
     * we just assume the test is not Robolectric.
     */
    @Test(expected = java.lang.RuntimeException::class)
    fun mobileDefault_usesNetworkNameAndIcon_throwsRunTimeException() =
        testScope.runTest {
            assumeFalse(isRobolectricTest());

            collectLastValue(underTest.tileData(testUser, flowOf(DataUpdateTrigger.InitialRequest)))

            connectivityRepository.setMobileConnected()
            mobileConnectionsRepository.mobileIsDefault.value = true
            mobileConnectionRepository.apply {
                setAllLevels(3)
                setAllRoaming(false)
                networkName.value = NetworkNameModel.Default("test network")
            }

            runCurrent()
        }

    /**
     * See [mobileDefault_usesNetworkNameAndIcon_throwsRunTimeException] for description of the
     * problem this test solves. The solution here is to assign a looper to the context via
     * RunWithLooper. In the production code, the solution is to use a Main CoroutineContext for
     * creating the SignalDrawable.
     */
    @TestableLooper.RunWithLooper
    @Test
    fun mobileDefault_usesNetworkNameAndIcon() =
    fun mobileDefault_run_withLooper_usesNetworkNameAndIcon() =
        testScope.runTest {
            val latest by
                collectLastValue(
+43 −32
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.systemui.common.shared.model.ContentDescription.Companion.loa
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel
@@ -38,7 +39,9 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.Connectivi
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -48,6 +51,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

@OptIn(ExperimentalCoroutinesApi::class)
/** Observes internet state changes providing the [InternetTileModel]. */
@@ -55,6 +59,7 @@ class InternetTileDataInteractor
@Inject
constructor(
    private val context: Context,
    @Main private val mainCoroutineContext: CoroutineContext,
    @Application private val scope: CoroutineScope,
    airplaneModeRepository: AirplaneModeRepository,
    private val connectivityRepository: ConnectivityRepository,
@@ -115,6 +120,9 @@ constructor(
                        it.signalLevelIcon,
                        mobileDataContentName,
                    ) { networkNameModel, signalIcon, dataContentDescription ->
                        Triple(networkNameModel, signalIcon, dataContentDescription)
                    }
                    .mapLatestConflated { (networkNameModel, signalIcon, dataContentDescription) ->
                        when (signalIcon) {
                            is SignalIconModel.Cellular -> {
                                val secondary =
@@ -123,21 +131,24 @@ constructor(
                                        dataContentDescription
                                    )

                            val stateLevel = signalIcon.level
                            val drawable = SignalDrawable(context)
                            drawable.setLevel(stateLevel)
                                val drawable =
                                    withContext(mainCoroutineContext) { SignalDrawable(context) }
                                drawable.setLevel(signalIcon.level)
                                val loadedIcon = Icon.Loaded(drawable, null)

                                InternetTileModel.Active(
                                    secondaryTitle = secondary,
                                    icon = loadedIcon,
                                stateDescription = ContentDescription.Loaded(secondary.toString()),
                                    stateDescription =
                                        ContentDescription.Loaded(secondary.toString()),
                                    contentDescription = ContentDescription.Loaded(internetLabel),
                                )
                            }
                            is SignalIconModel.Satellite -> {
                                val secondary =
                                signalIcon.icon.contentDescription.loadContentDescription(context)
                                    signalIcon.icon.contentDescription.loadContentDescription(
                                        context
                                    )
                                InternetTileModel.Active(
                                    secondaryTitle = secondary,
                                    iconId = signalIcon.icon.res,