Loading packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -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> Loading packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetMetadata.kt 0 → 100644 +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> ) packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt +27 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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() Loading Loading @@ -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 Loading packages/SystemUI/src/com/android/systemui/communal/shared/CommunalContentSize.kt 0 → 100644 +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, } packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt +44 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) } Loading Loading @@ -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, Loading Loading @@ -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
packages/SystemUI/res/values/config.xml +3 −0 Original line number Diff line number Diff line Loading @@ -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> Loading
packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetMetadata.kt 0 → 100644 +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> )
packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt +27 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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() Loading Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/communal/shared/CommunalContentSize.kt 0 → 100644 +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, }
packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt +44 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading @@ -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) } Loading Loading @@ -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, Loading Loading @@ -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" } }