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

Commit 42d848a1 authored by Coco Duan's avatar Coco Duan
Browse files

Get communal widget allowlist from config.xml

Defines the component names for the widget allowlist in config
xml and stores the metadata in CommunalWidgetRepository, which
will later be needed when creating the db.
The metadata will be used to create the widget inventory flow.

Bug: b/303844599
Test: atest CommunalWidgetRepositoryImplTest
Change-Id: I40e931be85dd0459b3ad092668eb64f8392ca840
parent b4309eff
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -730,6 +730,9 @@
    <!-- Whether the communal service should be enabled -->
    <bool name="config_communalServiceEnabled">false</bool>

    <!-- Component names of allowed communal widgets -->
    <string-array name="config_communalWidgetAllowlist" translatable="false" />

    <!-- Component name of communal source service -->
    <string name="config_communalSourceComponent" translatable="false">@null</string>

+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.communal.data.model

import com.android.systemui.communal.shared.CommunalContentSize

/** Metadata for the default widgets */
data class CommunalWidgetMetadata(
    /* Widget provider component name */
    val componentName: String,

    /* Defines the order in which the widget will be rendered in the grid. */
    val priority: Int,

    /* Supported sizes */
    val sizes: List<CommunalContentSize>
)
+27 −0
Original line number Diff line number Diff line
@@ -27,13 +27,17 @@ import android.content.pm.PackageManager
import android.os.UserManager
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.communal.data.model.CommunalWidgetMetadata
import com.android.systemui.communal.shared.CommunalAppWidgetInfo
import com.android.systemui.communal.shared.CommunalContentSize
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.Logger
import com.android.systemui.log.dagger.CommunalLog
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
@@ -45,15 +49,20 @@ import kotlinx.coroutines.flow.map
interface CommunalWidgetRepository {
    /** A flow of provider info for the stopwatch widget, or null if widget is unavailable. */
    val stopwatchAppWidgetInfo: Flow<CommunalAppWidgetInfo?>

    /** Widgets that are allowed to render in the glanceable hub */
    val communalWidgetAllowlist: List<CommunalWidgetMetadata>
}

@SysUISingleton
class CommunalWidgetRepositoryImpl
@Inject
constructor(
    @Application private val applicationContext: Context,
    private val appWidgetManager: AppWidgetManager,
    private val appWidgetHost: AppWidgetHost,
    broadcastDispatcher: BroadcastDispatcher,
    communalRepository: CommunalRepository,
    private val packageManager: PackageManager,
    private val userManager: UserManager,
    private val userTracker: UserTracker,
@@ -64,12 +73,18 @@ constructor(
        const val TAG = "CommunalWidgetRepository"
        const val WIDGET_LABEL = "Stopwatch"
    }
    override val communalWidgetAllowlist: List<CommunalWidgetMetadata>

    private val logger = Logger(logBuffer, TAG)

    // Whether the [AppWidgetHost] is listening for updates.
    private var isHostListening = false

    init {
        communalWidgetAllowlist =
            if (communalRepository.isCommunalEnabled) getWidgetAllowlist() else emptyList()
    }

    // Widgets that should be rendered in communal mode.
    private val widgets: HashMap<Int, CommunalAppWidgetInfo> = hashMapOf()

@@ -129,6 +144,18 @@ constructor(
            return@map addWidget(providerInfo)
        }

    private fun getWidgetAllowlist(): List<CommunalWidgetMetadata> {
        val componentNames =
            applicationContext.resources.getStringArray(R.array.config_communalWidgetAllowlist)
        return componentNames.mapIndexed { index, name ->
            CommunalWidgetMetadata(
                componentName = name,
                priority = componentNames.size - index,
                sizes = listOf(CommunalContentSize.HALF)
            )
        }
    }

    private fun startListening() {
        if (isHostListening) {
            return
+8 −0
Original line number Diff line number Diff line
package com.android.systemui.communal.shared

/** Supported sizes for communal content in the layout grid. */
enum class CommunalContentSize {
    FULL,
    HALF,
    THIRD,
}
+44 −0
Original line number Diff line number Diff line
@@ -11,11 +11,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.communal.data.model.CommunalWidgetMetadata
import com.android.systemui.communal.shared.CommunalContentSize
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
@@ -59,9 +62,12 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {

    @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo

    private lateinit var communalRepository: FakeCommunalRepository

    private lateinit var logBuffer: LogBuffer

    private val testDispatcher = StandardTestDispatcher()

    private val testScope = TestScope(testDispatcher)

    @Before
@@ -71,6 +77,14 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
        logBuffer = FakeLogBuffer.Factory.create()

        featureFlagEnabled(true)
        communalRepository = FakeCommunalRepository()
        communalRepository.setIsCommunalEnabled(true)

        overrideResource(
            R.array.config_communalWidgetAllowlist,
            arrayOf(componentName1, componentName2)
        )

        whenever(stopwatchProviderInfo.loadLabel(any())).thenReturn("Stopwatch")
        whenever(userTracker.userHandle).thenReturn(userHandle)
    }
@@ -219,11 +233,36 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            Mockito.verify(appWidgetHost).stopListening()
        }

    @Test
    fun getCommunalWidgetAllowList_onInit() {
        testScope.runTest {
            val repository = initCommunalWidgetRepository()
            val communalWidgetAllowlist = repository.communalWidgetAllowlist
            assertThat(
                    listOf(
                        CommunalWidgetMetadata(
                            componentName = componentName1,
                            priority = 2,
                            sizes = listOf(CommunalContentSize.HALF)
                        ),
                        CommunalWidgetMetadata(
                            componentName = componentName2,
                            priority = 1,
                            sizes = listOf(CommunalContentSize.HALF)
                        )
                    )
                )
                .containsExactly(*communalWidgetAllowlist.toTypedArray())
        }
    }

    private fun initCommunalWidgetRepository(): CommunalWidgetRepositoryImpl {
        return CommunalWidgetRepositoryImpl(
            context,
            appWidgetManager,
            appWidgetHost,
            broadcastDispatcher,
            communalRepository,
            packageManager,
            userManager,
            userTracker,
@@ -282,4 +321,9 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
        whenever(appWidgetManager.installedProviders).thenReturn(providers)
    }

    companion object {
        const val componentName1 = "component name 1"
        const val componentName2 = "component name 2"
    }
}
Loading