Loading packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +76 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.communal.ui.compose import android.appwidget.AppWidgetHostView import android.graphics.drawable.Icon import android.os.Bundle import android.util.SizeF import android.widget.FrameLayout Loading @@ -26,6 +27,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box Loading Loading @@ -77,6 +79,8 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.LayoutCoordinates Loading @@ -85,8 +89,10 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId Loading @@ -101,6 +107,8 @@ import androidx.compose.ui.window.Popup import androidx.core.view.setPadding import com.android.compose.modifiers.thenIf import com.android.compose.theme.LocalAndroidColorScheme import com.android.compose.ui.graphics.painter.rememberDrawablePainter import com.android.internal.R.dimen.system_app_widget_background_radius import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.compose.Dimensions.CardOutlineWidth Loading Loading @@ -178,7 +186,7 @@ fun CommunalHub( // not display this button. if ( index == null || communalContent[index].isWidget() || communalContent[index].isWidgetContent() || communalContent[index] is CommunalContentModel.CtaTileInViewMode ) { isButtonToEditWidgetsShowing = true Loading Loading @@ -330,7 +338,7 @@ private fun BoxScope.CommunalHubLazyGrid( DraggableItem( dragDropState = dragDropState, selected = selected, enabled = list[index] is CommunalContentModel.Widget, enabled = list[index].isWidgetContent(), index = index, ) { isDragging -> CommunalContent( Loading Loading @@ -539,9 +547,11 @@ private fun CommunalContent( widgetConfigurator: WidgetConfigurator? = null, ) { when (model) { is CommunalContentModel.Widget -> is CommunalContentModel.WidgetContent.Widget -> WidgetContent(viewModel, model, size, selected, widgetConfigurator, modifier) is CommunalContentModel.WidgetPlaceholder -> HighlightedItem(modifier) is CommunalContentModel.WidgetContent.DisabledWidget -> DisabledWidgetPlaceholder(model, modifier) is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier) is CommunalContentModel.CtaTileInEditMode -> CtaTileInEditModeContent(modifier, onOpenWidgetPicker) Loading Loading @@ -672,7 +682,7 @@ private fun CtaTileInEditModeContent( @Composable private fun WidgetContent( viewModel: BaseCommunalViewModel, model: CommunalContentModel.Widget, model: CommunalContentModel.WidgetContent.Widget, size: SizeF, selected: Boolean, widgetConfigurator: WidgetConfigurator?, Loading @@ -692,8 +702,9 @@ private fun WidgetContent( }, update = { view -> // Remove the extra padding applied to AppWidgetHostView to allow widgets to // occupy the entire box. The added padding is now adjusted to leave only sufficient // space for displaying the outline around the box when the widget is selected. // occupy the entire box. The added padding is now adjusted to leave only // sufficient space for displaying the outline around the box when the widget // is selected. view.setPadding(paddingInPx) }, // For reusing composition in lazy lists. Loading @@ -717,7 +728,7 @@ private fun WidgetContent( @Composable fun WidgetConfigureButton( visible: Boolean, model: CommunalContentModel.Widget, model: CommunalContentModel.WidgetContent.Widget, modifier: Modifier = Modifier, widgetConfigurator: WidgetConfigurator, ) { Loading Loading @@ -751,6 +762,38 @@ fun WidgetConfigureButton( } } @Composable fun DisabledWidgetPlaceholder( model: CommunalContentModel.WidgetContent.DisabledWidget, modifier: Modifier = Modifier, ) { val context = LocalContext.current val appInfo = model.appInfo val icon: Icon = if (appInfo == null || appInfo.icon == 0) { Icon.createWithResource(context, android.R.drawable.sym_def_app_icon) } else { Icon.createWithResource(appInfo.packageName, appInfo.icon) } Column( modifier = modifier.background( MaterialTheme.colorScheme.surfaceVariant, RoundedCornerShape(dimensionResource(system_app_widget_background_radius)) ), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Image( painter = rememberDrawablePainter(icon.loadDrawable(context)), contentDescription = stringResource(R.string.icon_description_for_disabled_widget), modifier = Modifier.size(48.dp), colorFilter = ColorFilter.colorMatrix(Colors.DisabledColorFilter), ) } } @Composable private fun SmartspaceContent( model: CommunalContentModel.Smartspace, Loading Loading @@ -852,7 +895,7 @@ private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = /** Returns the key of item if it's editable at the given index. Only widget is editable. */ private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = if (index in list.indices && list[index].isWidget()) list[index].key else null if (index in list.indices && list[index].isWidgetContent()) list[index].key else null data class ContentPaddingInPx(val start: Float, val top: Float) { fun toOffset(): Offset = Offset(start, top) Loading Loading @@ -882,5 +925,30 @@ object Dimensions { val IconSize = 48.dp } private object Colors { val DisabledColorFilter by lazy { disabledColorMatrix() } /** Returns the disabled image filter. Ported over from [DisableImageView]. */ private fun disabledColorMatrix(): ColorMatrix { val brightnessMatrix = ColorMatrix() val brightnessAmount = 0.5f val brightnessRgb = (255 * brightnessAmount).toInt().toFloat() // Brightness: C-new = C-old*(1-amount) + amount val scale = 1f - brightnessAmount val mat = brightnessMatrix.values mat[0] = scale mat[6] = scale mat[12] = scale mat[4] = brightnessRgb mat[9] = brightnessRgb mat[14] = brightnessRgb return ColorMatrix().apply { setToSaturation(0F) timesAssign(brightnessMatrix) } } } /** The resource id of communal hub accessible from UiAutomator. */ private const val COMMUNAL_HUB_TEST_TAG = "communal_hub" packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt +4 −4 Original line number Diff line number Diff line Loading @@ -71,8 +71,8 @@ internal constructor( /** Remove widget from the list and the database. */ fun onRemove(indexToRemove: Int) { if (list[indexToRemove] is CommunalContentModel.Widget) { val widget = list[indexToRemove] as CommunalContentModel.Widget if (list[indexToRemove].isWidgetContent()) { val widget = list[indexToRemove] as CommunalContentModel.WidgetContent list.apply { removeAt(indexToRemove) } onDeleteWidget(widget.appWidgetId) } Loading Loading @@ -100,7 +100,7 @@ internal constructor( val widgetIdToPriorityMap: Map<Int, Int> = list .mapIndexedNotNull { index, item -> if (item is CommunalContentModel.Widget) { if (item is CommunalContentModel.WidgetContent) { item.appWidgetId to list.size - index } else { null Loading @@ -115,5 +115,5 @@ internal constructor( } /** Returns true if the item at given index is editable. */ fun isItemEditable(index: Int) = list[index] is CommunalContentModel.Widget fun isItemEditable(index: Int) = list[index].isWidgetContent() } packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +102 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.FakeCommunalRepository Loading Loading @@ -62,6 +63,7 @@ import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -831,6 +833,95 @@ class CommunalInteractorTest : SysuiTestCase() { } } @Test fun widgetContent_containsDisabledWidgets_whenCategoryNotAllowed() = testScope.runTest { // Communal available, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) runCurrent() // Widgets available. val widget1 = createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) val widget2 = createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widget3 = createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) val widgetContent by collectLastValue(underTest.widgetContent) kosmos.fakeSettings.putIntForUser( CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, mainUser.id ) runCurrent() // Only the keyguard widget is enabled. assertThat(widgetContent).hasSize(3) assertThat(widgetContent!!.get(0)) .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) assertThat(widgetContent!!.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) assertThat(widgetContent!!.get(2)) .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) } @Test fun widgetContent_allEnabled_whenCategoryAllowed() = testScope.runTest { // Communal available, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) runCurrent() // Widgets available. val widget1 = createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) val widget2 = createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widget3 = createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) val widgetContent by collectLastValue(underTest.widgetContent) kosmos.fakeSettings.putIntForUser( CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, mainUser.id ) runCurrent() // All widgets are enabled. assertThat(widgetContent).hasSize(3) widgetContent!!.forEach { model -> assertThat(model) .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) } } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading @@ -848,6 +939,17 @@ class CommunalInteractorTest : SysuiTestCase() { whenever(this.providerInfo).thenReturn(providerInfo) } private fun createWidgetWithCategory( appWidgetId: Int, category: Int ): CommunalWidgetContentModel = mock<CommunalWidgetContentModel> { whenever(this.appWidgetId).thenReturn(appWidgetId) val providerInfo = mock<AppWidgetProviderInfo>().apply { widgetCategory = category } whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) whenever(this.providerInfo).thenReturn(providerInfo) } private companion object { val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +6 −5 Original line number Diff line number Diff line Loading @@ -135,9 +135,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) } Loading Loading @@ -181,9 +181,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) Loading @@ -192,7 +192,8 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only one widget and CTA tile remain. assertThat(communalContent?.size).isEqualTo(2) val item = communalContent?.get(0) val appWidgetId = if (item is CommunalContentModel.Widget) item.appWidgetId else null val appWidgetId = if (item is CommunalContentModel.WidgetContent) item.appWidgetId else null assertThat(appWidgetId).isEqualTo(widgets.get(1).appWidgetId) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -184,9 +184,9 @@ class CommunalViewModelTest : SysuiTestCase() { .isInstanceOf(CommunalContentModel.Smartspace::class.java) assertThat(communalContent?.get(1)).isInstanceOf(CommunalContentModel.Umo::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(3)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(4)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +76 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.communal.ui.compose import android.appwidget.AppWidgetHostView import android.graphics.drawable.Icon import android.os.Bundle import android.util.SizeF import android.widget.FrameLayout Loading @@ -26,6 +27,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box Loading Loading @@ -77,6 +79,8 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.LayoutCoordinates Loading @@ -85,8 +89,10 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId Loading @@ -101,6 +107,8 @@ import androidx.compose.ui.window.Popup import androidx.core.view.setPadding import com.android.compose.modifiers.thenIf import com.android.compose.theme.LocalAndroidColorScheme import com.android.compose.ui.graphics.painter.rememberDrawablePainter import com.android.internal.R.dimen.system_app_widget_background_radius import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.compose.Dimensions.CardOutlineWidth Loading Loading @@ -178,7 +186,7 @@ fun CommunalHub( // not display this button. if ( index == null || communalContent[index].isWidget() || communalContent[index].isWidgetContent() || communalContent[index] is CommunalContentModel.CtaTileInViewMode ) { isButtonToEditWidgetsShowing = true Loading Loading @@ -330,7 +338,7 @@ private fun BoxScope.CommunalHubLazyGrid( DraggableItem( dragDropState = dragDropState, selected = selected, enabled = list[index] is CommunalContentModel.Widget, enabled = list[index].isWidgetContent(), index = index, ) { isDragging -> CommunalContent( Loading Loading @@ -539,9 +547,11 @@ private fun CommunalContent( widgetConfigurator: WidgetConfigurator? = null, ) { when (model) { is CommunalContentModel.Widget -> is CommunalContentModel.WidgetContent.Widget -> WidgetContent(viewModel, model, size, selected, widgetConfigurator, modifier) is CommunalContentModel.WidgetPlaceholder -> HighlightedItem(modifier) is CommunalContentModel.WidgetContent.DisabledWidget -> DisabledWidgetPlaceholder(model, modifier) is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier) is CommunalContentModel.CtaTileInEditMode -> CtaTileInEditModeContent(modifier, onOpenWidgetPicker) Loading Loading @@ -672,7 +682,7 @@ private fun CtaTileInEditModeContent( @Composable private fun WidgetContent( viewModel: BaseCommunalViewModel, model: CommunalContentModel.Widget, model: CommunalContentModel.WidgetContent.Widget, size: SizeF, selected: Boolean, widgetConfigurator: WidgetConfigurator?, Loading @@ -692,8 +702,9 @@ private fun WidgetContent( }, update = { view -> // Remove the extra padding applied to AppWidgetHostView to allow widgets to // occupy the entire box. The added padding is now adjusted to leave only sufficient // space for displaying the outline around the box when the widget is selected. // occupy the entire box. The added padding is now adjusted to leave only // sufficient space for displaying the outline around the box when the widget // is selected. view.setPadding(paddingInPx) }, // For reusing composition in lazy lists. Loading @@ -717,7 +728,7 @@ private fun WidgetContent( @Composable fun WidgetConfigureButton( visible: Boolean, model: CommunalContentModel.Widget, model: CommunalContentModel.WidgetContent.Widget, modifier: Modifier = Modifier, widgetConfigurator: WidgetConfigurator, ) { Loading Loading @@ -751,6 +762,38 @@ fun WidgetConfigureButton( } } @Composable fun DisabledWidgetPlaceholder( model: CommunalContentModel.WidgetContent.DisabledWidget, modifier: Modifier = Modifier, ) { val context = LocalContext.current val appInfo = model.appInfo val icon: Icon = if (appInfo == null || appInfo.icon == 0) { Icon.createWithResource(context, android.R.drawable.sym_def_app_icon) } else { Icon.createWithResource(appInfo.packageName, appInfo.icon) } Column( modifier = modifier.background( MaterialTheme.colorScheme.surfaceVariant, RoundedCornerShape(dimensionResource(system_app_widget_background_radius)) ), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Image( painter = rememberDrawablePainter(icon.loadDrawable(context)), contentDescription = stringResource(R.string.icon_description_for_disabled_widget), modifier = Modifier.size(48.dp), colorFilter = ColorFilter.colorMatrix(Colors.DisabledColorFilter), ) } } @Composable private fun SmartspaceContent( model: CommunalContentModel.Smartspace, Loading Loading @@ -852,7 +895,7 @@ private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = /** Returns the key of item if it's editable at the given index. Only widget is editable. */ private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = if (index in list.indices && list[index].isWidget()) list[index].key else null if (index in list.indices && list[index].isWidgetContent()) list[index].key else null data class ContentPaddingInPx(val start: Float, val top: Float) { fun toOffset(): Offset = Offset(start, top) Loading Loading @@ -882,5 +925,30 @@ object Dimensions { val IconSize = 48.dp } private object Colors { val DisabledColorFilter by lazy { disabledColorMatrix() } /** Returns the disabled image filter. Ported over from [DisableImageView]. */ private fun disabledColorMatrix(): ColorMatrix { val brightnessMatrix = ColorMatrix() val brightnessAmount = 0.5f val brightnessRgb = (255 * brightnessAmount).toInt().toFloat() // Brightness: C-new = C-old*(1-amount) + amount val scale = 1f - brightnessAmount val mat = brightnessMatrix.values mat[0] = scale mat[6] = scale mat[12] = scale mat[4] = brightnessRgb mat[9] = brightnessRgb mat[14] = brightnessRgb return ColorMatrix().apply { setToSaturation(0F) timesAssign(brightnessMatrix) } } } /** The resource id of communal hub accessible from UiAutomator. */ private const val COMMUNAL_HUB_TEST_TAG = "communal_hub"
packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt +4 −4 Original line number Diff line number Diff line Loading @@ -71,8 +71,8 @@ internal constructor( /** Remove widget from the list and the database. */ fun onRemove(indexToRemove: Int) { if (list[indexToRemove] is CommunalContentModel.Widget) { val widget = list[indexToRemove] as CommunalContentModel.Widget if (list[indexToRemove].isWidgetContent()) { val widget = list[indexToRemove] as CommunalContentModel.WidgetContent list.apply { removeAt(indexToRemove) } onDeleteWidget(widget.appWidgetId) } Loading Loading @@ -100,7 +100,7 @@ internal constructor( val widgetIdToPriorityMap: Map<Int, Int> = list .mapIndexedNotNull { index, item -> if (item is CommunalContentModel.Widget) { if (item is CommunalContentModel.WidgetContent) { item.appWidgetId to list.size - index } else { null Loading @@ -115,5 +115,5 @@ internal constructor( } /** Returns true if the item at given index is editable. */ fun isItemEditable(index: Int) = list[index] is CommunalContentModel.Widget fun isItemEditable(index: Int) = list[index].isWidgetContent() }
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +102 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.FakeCommunalRepository Loading Loading @@ -62,6 +63,7 @@ import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow Loading Loading @@ -831,6 +833,95 @@ class CommunalInteractorTest : SysuiTestCase() { } } @Test fun widgetContent_containsDisabledWidgets_whenCategoryNotAllowed() = testScope.runTest { // Communal available, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) runCurrent() // Widgets available. val widget1 = createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) val widget2 = createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widget3 = createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) val widgetContent by collectLastValue(underTest.widgetContent) kosmos.fakeSettings.putIntForUser( CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, mainUser.id ) runCurrent() // Only the keyguard widget is enabled. assertThat(widgetContent).hasSize(3) assertThat(widgetContent!!.get(0)) .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) assertThat(widgetContent!!.get(1)) .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) assertThat(widgetContent!!.get(2)) .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) } @Test fun widgetContent_allEnabled_whenCategoryAllowed() = testScope.runTest { // Communal available, and tutorial completed. keyguardRepository.setKeyguardShowing(true) keyguardRepository.setKeyguardOccluded(false) tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) userRepository.setSelectedUserInfo(mainUser) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) userRepository.setUserInfos(userInfos) userTracker.set( userInfos = userInfos, selectedUserIndex = 0, ) runCurrent() // Widgets available. val widget1 = createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) val widget2 = createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widget3 = createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) val widgets = listOf(widget1, widget2, widget3) widgetRepository.setCommunalWidgets(widgets) val widgetContent by collectLastValue(underTest.widgetContent) kosmos.fakeSettings.putIntForUser( CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, mainUser.id ) runCurrent() // All widgets are enabled. assertThat(widgetContent).hasSize(3) widgetContent!!.forEach { model -> assertThat(model) .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) } } private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) Loading @@ -848,6 +939,17 @@ class CommunalInteractorTest : SysuiTestCase() { whenever(this.providerInfo).thenReturn(providerInfo) } private fun createWidgetWithCategory( appWidgetId: Int, category: Int ): CommunalWidgetContentModel = mock<CommunalWidgetContentModel> { whenever(this.appWidgetId).thenReturn(appWidgetId) val providerInfo = mock<AppWidgetProviderInfo>().apply { widgetCategory = category } whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) whenever(this.providerInfo).thenReturn(providerInfo) } private companion object { val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +6 −5 Original line number Diff line number Diff line Loading @@ -135,9 +135,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) } Loading Loading @@ -181,9 +181,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) Loading @@ -192,7 +192,8 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only one widget and CTA tile remain. assertThat(communalContent?.size).isEqualTo(2) val item = communalContent?.get(0) val appWidgetId = if (item is CommunalContentModel.Widget) item.appWidgetId else null val appWidgetId = if (item is CommunalContentModel.WidgetContent) item.appWidgetId else null assertThat(appWidgetId).isEqualTo(widgets.get(1).appWidgetId) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -184,9 +184,9 @@ class CommunalViewModelTest : SysuiTestCase() { .isInstanceOf(CommunalContentModel.Smartspace::class.java) assertThat(communalContent?.get(1)).isInstanceOf(CommunalContentModel.Umo::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(3)) .isInstanceOf(CommunalContentModel.Widget::class.java) .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(4)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } Loading