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

Commit 0fdb6425 authored by Coco Duan's avatar Coco Duan Committed by Android (Google) Code Review
Browse files

Merge "Get communal widget allowlist from config.xml" into main

parents 104205f9 42d848a1
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -730,6 +730,9 @@
    <!-- Whether the communal service should be enabled -->
    <!-- Whether the communal service should be enabled -->
    <bool name="config_communalServiceEnabled">false</bool>
    <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 -->
    <!-- Component name of communal source service -->
    <string name="config_communalSourceComponent" translatable="false">@null</string>
    <string name="config_communalSourceComponent" translatable="false">@null</string>


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

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


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


    private val logger = Logger(logBuffer, TAG)
    private val logger = Logger(logBuffer, TAG)


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


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

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


@@ -129,6 +144,18 @@ constructor(
            return@map addWidget(providerInfo)
            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() {
    private fun startListening() {
        if (isHostListening) {
        if (isHostListening) {
            return
            return
+8 −0
Original line number Original line 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 Original line Diff line number Diff line
@@ -11,11 +11,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
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.coroutines.collectLastValue
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.log.core.FakeLogBuffer
import com.android.systemui.res.R
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.any
import com.android.systemui.util.mockito.kotlinArgumentCaptor
import com.android.systemui.util.mockito.kotlinArgumentCaptor
@@ -59,9 +62,12 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {


    @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo
    @Mock private lateinit var stopwatchProviderInfo: AppWidgetProviderInfo


    private lateinit var communalRepository: FakeCommunalRepository

    private lateinit var logBuffer: LogBuffer
    private lateinit var logBuffer: LogBuffer


    private val testDispatcher = StandardTestDispatcher()
    private val testDispatcher = StandardTestDispatcher()

    private val testScope = TestScope(testDispatcher)
    private val testScope = TestScope(testDispatcher)


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


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

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

        whenever(stopwatchProviderInfo.loadLabel(any())).thenReturn("Stopwatch")
        whenever(stopwatchProviderInfo.loadLabel(any())).thenReturn("Stopwatch")
        whenever(userTracker.userHandle).thenReturn(userHandle)
        whenever(userTracker.userHandle).thenReturn(userHandle)
    }
    }
@@ -219,11 +233,36 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
            Mockito.verify(appWidgetHost).stopListening()
            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 {
    private fun initCommunalWidgetRepository(): CommunalWidgetRepositoryImpl {
        return CommunalWidgetRepositoryImpl(
        return CommunalWidgetRepositoryImpl(
            context,
            appWidgetManager,
            appWidgetManager,
            appWidgetHost,
            appWidgetHost,
            broadcastDispatcher,
            broadcastDispatcher,
            communalRepository,
            packageManager,
            packageManager,
            userManager,
            userManager,
            userTracker,
            userTracker,
@@ -282,4 +321,9 @@ class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
    private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
    private fun installedProviders(providers: List<AppWidgetProviderInfo>) {
        whenever(appWidgetManager.installedProviders).thenReturn(providers)
        whenever(appWidgetManager.installedProviders).thenReturn(providers)
    }
    }

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