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

Commit 54a41031 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fetch tile categories from service metadata" into main

parents c0737306 67aaa3d8
Loading
Loading
Loading
Loading
+178 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.qs.panels.data.repository

import android.content.ComponentName
import android.content.packageManager
import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
import android.graphics.drawable.TestStubDrawable
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.quicksettings.Flags
import android.service.quicksettings.TileService
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.kosmos.mainCoroutineContext
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.shared.model.EditTileData
import com.android.systemui.qs.pipeline.data.repository.FakeInstalledTilesComponentRepository
import com.android.systemui.qs.pipeline.data.repository.fakeInstalledTilesRepository
import com.android.systemui.qs.pipeline.data.repository.installedTilesRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@RunWith(ParameterizedAndroidJunit4::class)
@SmallTest
@android.platform.test.annotations.EnabledOnRavenwood
internal class IconAndNameCustomRepositoryParameterizedTest(private val testCase: TestCase) :
    SysuiTestCase() {
    private val kosmos = testKosmos()

    private val packageManager: PackageManager = kosmos.packageManager
    private val userTracker: FakeUserTracker =
        kosmos.fakeUserTracker.apply {
            whenever(userContext.packageManager).thenReturn(packageManager)
        }

    private val underTest =
        with(kosmos) {
            IconAndNameCustomRepository(
                installedTilesRepository,
                userTracker,
                mainCoroutineContext,
                appIconRepositoryFactory,
            )
        }

    @Before
    fun setUp() {
        kosmos.fakeInstalledTilesRepository.setInstalledServicesForUser(
            userTracker.userId,
            listOf(testCase.toServiceInfo()),
        )
    }

    @Test
    @EnableFlags(Flags.FLAG_QUICKSETTINGS_TILE_CATEGORIES)
    fun tileService_categoriesEnabled_returnsValidCategory() =
        with(kosmos) {
            testScope.runTest {
                val editTileDataList = underTest.getCustomTileData()
                val expectedData1 =
                    EditTileData(
                        TileSpec.create(component1),
                        Icon.Loaded(drawable1, ContentDescription.Loaded(tileService1)),
                        Text.Loaded(tileService1),
                        Text.Loaded(appName1),
                        null,
                        testCase.expected,
                    )

                assertThat(editTileDataList).containsExactly(expectedData1)
            }
        }

    @Test
    @DisableFlags(Flags.FLAG_QUICKSETTINGS_TILE_CATEGORIES)
    fun tileService_categoriesDisabled_returnsValidCategory() =
        with(kosmos) {
            testScope.runTest {
                val editTileDataList = underTest.getCustomTileData()
                val expectedData1 =
                    EditTileData(
                        TileSpec.create(component1),
                        Icon.Loaded(drawable1, ContentDescription.Loaded(tileService1)),
                        Text.Loaded(tileService1),
                        Text.Loaded(appName1),
                        null,
                        testCase.expectedDefault,
                    )

                assertThat(editTileDataList).containsExactly(expectedData1)
            }
        }

    internal data class TestCase(
        val category: String,
        val isSystemApp: Boolean,
        val expected: TileCategory,
        val expectedDefault: TileCategory =
            if (isSystemApp) TileCategory.PROVIDED_BY_SYSTEM_APP else TileCategory.PROVIDED_BY_APP,
    ) {
        fun toServiceInfo(): ServiceInfo {
            return FakeInstalledTilesComponentRepository.ServiceInfo(
                component1,
                tileService1,
                drawable1,
                appName1,
                null,
                isSystemApp,
                category,
            )
        }

        override fun toString(): String =
            "category=$category," +
                "isSystemApp=$isSystemApp," +
                "expected=${expected.name}," +
                "expectedDefault=${expectedDefault.name}"
    }

    companion object {
        val drawable1 = TestStubDrawable("drawable1")
        val appName1 = "App1"
        val tileService1 = "Tile Service 1"
        val component1 = ComponentName("pkg1", "srv1")

        @Parameters(name = "{0}")
        @JvmStatic
        fun data() =
            listOf(
                TestCase(TileService.CATEGORY_CONNECTIVITY, true, TileCategory.CONNECTIVITY),
                TestCase(TileService.CATEGORY_DISPLAY, false, TileCategory.DISPLAY),
                TestCase(TileService.CATEGORY_UTILITIES, true, TileCategory.UTILITIES),
                TestCase(TileService.CATEGORY_PRIVACY, false, TileCategory.PRIVACY),
                TestCase(TileService.CATEGORY_ACCESSIBILITY, true, TileCategory.ACCESSIBILITY),
                TestCase(
                    "android.service.quicksettings.CATEGORY_NON_VALID",
                    true,
                    TileCategory.PROVIDED_BY_SYSTEM_APP,
                ),
                TestCase(
                    "android.service.quicksettings.CATEGORY_NON_VALID",
                    false,
                    TileCategory.PROVIDED_BY_APP,
                ),
            )
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.kosmos.mainCoroutineContext
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.shared.model.EditTileData
import com.android.systemui.qs.pipeline.data.repository.FakeInstalledTilesComponentRepository
+12 −10
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
            InstalledTilesComponentRepositoryImpl(
                context,
                testScope.backgroundScope,
                kosmos.packageChangeRepository
                kosmos.packageChangeRepository,
            )
    }

@@ -98,7 +98,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -127,7 +127,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -149,7 +149,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -172,7 +172,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -213,7 +213,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    secondaryUserPackageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -221,7 +221,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -259,7 +259,7 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
                    packageManager.queryIntentServicesAsUser(
                        matchIntent(),
                        matchFlags(),
                        eq(userId)
                        eq(userId),
                    )
                )
                .thenReturn(listOf(resolveInfo))
@@ -277,7 +277,8 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {
            ResolveInfoFlags.of(
                (PackageManager.MATCH_DIRECT_BOOT_AWARE or
                        PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
                        PackageManager.GET_SERVICES)
                        PackageManager.GET_SERVICES or
                        PackageManager.GET_META_DATA)
                    .toLong()
            )
        private val PERMISSION = BIND_QUICK_SETTINGS_TILE
@@ -286,12 +287,13 @@ class InstalledTilesComponentRepositoryImplTest : SysuiTestCase() {

        private fun matchFlags() =
            argThat<ResolveInfoFlags> { flags -> flags?.value == FLAGS.value }

        private fun matchIntent() = argThat<Intent> { intent -> intent.action == INTENT.action }

        private fun ResolveInfo(
            componentName: ComponentName,
            hasPermission: Boolean,
            defaultEnabled: Boolean
            defaultEnabled: Boolean,
        ): ResolveInfo {
            val applicationInfo = ApplicationInfo().apply { enabled = true }
            val serviceInfo =
+22 −5
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.systemui.qs.panels.data.repository

import android.os.Bundle
import android.service.quicksettings.Flags
import android.service.quicksettings.TileService
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
@@ -25,6 +28,7 @@ import com.android.systemui.qs.panels.shared.model.EditTileData
import com.android.systemui.qs.pipeline.data.repository.InstalledTilesComponentRepository
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.shared.model.TileCategory
import com.android.systemui.qs.shared.model.tileCategoryFor
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -57,11 +61,8 @@ constructor(
                    val icon = it.loadIcon(packageManager)
                    val appName = it.applicationInfo.loadLabel(packageManager)
                    val category =
                        if (it.applicationInfo.isSystemApp) {
                            TileCategory.PROVIDED_BY_SYSTEM_APP
                        } else {
                            TileCategory.PROVIDED_BY_APP
                        }
                        it.metaData?.getTileCategory()
                            ?: defaultCategory(it.applicationInfo.isSystemApp)
                    val appIcon =
                        if (it.applicationInfo.isSystemApp) {
                            null
@@ -84,4 +85,20 @@ constructor(
                .filterNotNull()
        }
    }

    private fun Bundle.getTileCategory(): TileCategory? {
        return if (Flags.quicksettingsTileCategories()) {
            getString(TileService.META_DATA_TILE_CATEGORY)?.let { tileCategoryFor(it) }
        } else {
            null
        }
    }

    private fun defaultCategory(isSystemApp: Boolean): TileCategory {
        return if (isSystemApp) {
            TileCategory.PROVIDED_BY_SYSTEM_APP
        } else {
            TileCategory.PROVIDED_BY_APP
        }
    }
}
+4 −8
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ class InstalledTilesComponentRepositoryImpl
constructor(
    @ShadeDisplayAware private val context: Context,
    @Background private val backgroundScope: CoroutineScope,
    private val packageChangeRepository: PackageChangeRepository
    private val packageChangeRepository: PackageChangeRepository,
) : InstalledTilesComponentRepository {

    @GuardedBy("userMap") private val userMap = mutableMapOf<Int, StateFlow<List<ServiceInfo>>>()
@@ -80,12 +80,7 @@ constructor(
                if (context.userId == userId) {
                    context.packageManager
                } else {
                    context
                        .createContextAsUser(
                            UserHandle.of(userId),
                            /* flags */ 0,
                        )
                        .packageManager
                    context.createContextAsUser(UserHandle.of(userId), /* flags */ 0).packageManager
                }
            packageChangeRepository
                .packageChanged(UserHandle.of(userId))
@@ -119,7 +114,8 @@ constructor(
            ResolveInfoFlags.of(
                (PackageManager.GET_SERVICES or
                        PackageManager.MATCH_DIRECT_BOOT_AWARE or
                        PackageManager.MATCH_DIRECT_BOOT_UNAWARE)
                        PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
                        PackageManager.GET_META_DATA)
                    .toLong()
            )
    }
Loading