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

Commit fdc3050f authored by Behnam Heydarshahi's avatar Behnam Heydarshahi
Browse files

Handle user context switch in CustomTileMapper

There was a null pointer exception when user context could not be
retrieved. This CL handles that case gracefully.

Bug: 356293227
Flag: com.android.systemui.qs_new_tiles
Test: atest CustomTileMapperTest
Test: atest PlatformScenarioTests
Change-Id: Ieb0905dda4fd0791b4d8663c1f26c1a3ef9524f9
parent 254b854c
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles.impl.custom.domain.interactor

import android.app.IUriGrantsManager
import android.content.ComponentName
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.graphics.drawable.TestStubDrawable
@@ -51,11 +52,13 @@ import org.junit.runner.RunWith
class CustomTileMapperTest : SysuiTestCase() {

    private val uriGrantsManager: IUriGrantsManager = mock {}
    private val mockContext =
        mock<Context> { whenever(createContextAsUser(any(), any())).thenReturn(context) }
    private val kosmos =
        testKosmos().apply { customTileSpec = TileSpec.Companion.create(TEST_COMPONENT) }
    private val underTest by lazy {
        CustomTileMapper(
            context = mock { whenever(createContextAsUser(any(), any())).thenReturn(context) },
            context = mockContext,
            uriGrantsManager = uriGrantsManager,
        )
    }
@@ -164,7 +167,7 @@ class CustomTileMapperTest : SysuiTestCase() {
                    )
                val expected =
                    createTileState(
                        activationState = QSTileState.ActivationState.INACTIVE,
                        activationState = QSTileState.ActivationState.UNAVAILABLE,
                        icon = DEFAULT_DRAWABLE,
                    )

@@ -173,7 +176,7 @@ class CustomTileMapperTest : SysuiTestCase() {
        }

    @Test
    fun failedToLoadIconTileIsInactive() =
    fun failedToLoadIconTileIsUnavailable() =
        with(kosmos) {
            testScope.runTest {
                val actual =
@@ -187,13 +190,32 @@ class CustomTileMapperTest : SysuiTestCase() {
                val expected =
                    createTileState(
                        icon = null,
                        activationState = QSTileState.ActivationState.INACTIVE,
                        activationState = QSTileState.ActivationState.UNAVAILABLE,
                    )

                assertThat(actual).isEqualTo(expected)
            }
        }

    @Test
    fun nullUserContextDoesNotCauseExceptionReturnsNullIconAndUnavailableState() =
        with(kosmos) {
            testScope.runTest {
                // map() will catch this exception
                whenever(mockContext.createContextAsUser(any(), any()))
                    .thenThrow(IllegalStateException("Unable to create userContext"))

                val actual = underTest.map(customTileQsTileConfig, createModel())

                val expected =
                    createTileState(
                        icon = null,
                        activationState = QSTileState.ActivationState.UNAVAILABLE,
                    )
                assertThat(actual).isEqualTo(expected)
            }
        }

    private fun Kosmos.createModel(
        tileState: Int = Tile.STATE_ACTIVE,
        tileIcon: Icon = createIcon(DRAWABLE, false),
+18 −9
Original line number Diff line number Diff line
@@ -41,9 +41,15 @@ constructor(
) : QSTileDataToStateMapper<CustomTileDataModel> {

    override fun map(config: QSTileConfig, data: CustomTileDataModel): QSTileState {
        val userContext = context.createContextAsUser(UserHandle(data.user.identifier), 0)
        val userContext =
            try {
                context.createContextAsUser(UserHandle(data.user.identifier), 0)
            } catch (exception: IllegalStateException) {
                null
            }

        val iconResult =
            if (userContext != null) {
                getIconProvider(
                    userContext = userContext,
                    icon = data.tile.icon,
@@ -51,6 +57,9 @@ constructor(
                    packageName = data.componentName.packageName,
                    defaultIcon = data.defaultTileIcon,
                )
            } else {
                IconResult({ null }, true)
            }

        return QSTileState.build(iconResult.iconProvider, data.tile.label) {
            var tileState: Int = data.tile.state
@@ -61,7 +70,7 @@ constructor(
            icon = iconResult.iconProvider
            activationState =
                if (iconResult.failedToLoad) {
                    QSTileState.ActivationState.INACTIVE
                    QSTileState.ActivationState.UNAVAILABLE
                } else {
                    QSTileState.ActivationState.valueOf(tileState)
                }