diff options
8 files changed, 248 insertions, 41 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 609f314bb540..078da1c863ce 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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( @@ -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) @@ -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?, @@ -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. @@ -717,7 +728,7 @@ private fun WidgetContent( @Composable fun WidgetConfigureButton( visible: Boolean, - model: CommunalContentModel.Widget, + model: CommunalContentModel.WidgetContent.Widget, modifier: Modifier = Modifier, widgetConfigurator: WidgetConfigurator, ) { @@ -752,6 +763,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, modifier: Modifier = Modifier, @@ -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) @@ -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" diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt index 9b8c9d0ab616..c5dab3347e5f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt @@ -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) } @@ -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 @@ -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() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index cd296524c17c..6e3573b64f9a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -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 @@ -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 @@ -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) @@ -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) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index 5ee88cb92fa0..8e2e94716660 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -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) } @@ -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) @@ -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) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 1e523dd2a9cc..563aad1920f7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -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) } diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d0d89c81f96a..346bdfc8b2d8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1118,6 +1118,8 @@ <string name="popup_on_dismiss_cta_tile_text">Long press to customize widgets</string> <!-- Text for the button to configure widgets after long press. [CHAR LIMIT=50] --> <string name="button_to_configure_widgets_text">Customize widgets</string> + <!-- Description for the App icon of disabled widget. [CHAR LIMIT=NONE] --> + <string name="icon_description_for_disabled_widget">App icon for disabled widget</string> <!-- Label for the button which configures widgets [CHAR LIMIT=NONE] --> <string name="edit_widget">Edit widget</string> <!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] --> diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 5d525413a919..151e1eeaefc5 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.communal.data.repository.CommunalPrefsRepository import com.android.systemui.communal.data.repository.CommunalRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalContentSize.FULL import com.android.systemui.communal.shared.model.CommunalContentSize.HALF @@ -278,14 +279,25 @@ constructor( } /** A list of widget content to be displayed in the communal hub. */ - val widgetContent: Flow<List<CommunalContentModel.Widget>> = - widgetRepository.communalWidgets.map { widgets -> - filterWidgetsByExistingUsers(widgets).map Widget@{ widget -> - return@Widget CommunalContentModel.Widget( - appWidgetId = widget.appWidgetId, - providerInfo = widget.providerInfo, - appWidgetHost = appWidgetHost, - ) + val widgetContent: Flow<List<WidgetContent>> = + combine( + widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) }, + communalSettingsInteractor.communalWidgetCategories + ) { widgets, allowedCategories -> + widgets.map { widget -> + if (widget.providerInfo.widgetCategory and allowedCategories != 0) { + // At least one category this widget specified is allowed, so show it + WidgetContent.Widget( + appWidgetId = widget.appWidgetId, + providerInfo = widget.providerInfo, + appWidgetHost = appWidgetHost, + ) + } else { + WidgetContent.DisabledWidget( + appWidgetId = widget.appWidgetId, + providerInfo = widget.providerInfo, + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt index ae019a187bae..c64f666ebf10 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.communal.domain.model import android.appwidget.AppWidgetProviderInfo import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE +import android.content.pm.ApplicationInfo import android.widget.RemoteViews import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.widgets.CommunalAppWidgetHost @@ -42,20 +43,37 @@ sealed interface CommunalContentModel { val createdTimestampMillis: Long } - data class Widget( - val appWidgetId: Int, - val providerInfo: AppWidgetProviderInfo, - val appWidgetHost: CommunalAppWidgetHost, - ) : CommunalContentModel { - override val key = KEY.widget(appWidgetId) - // Widget size is always half. - override val size = CommunalContentSize.HALF + sealed interface WidgetContent : CommunalContentModel { + val appWidgetId: Int + val providerInfo: AppWidgetProviderInfo + + data class Widget( + override val appWidgetId: Int, + override val providerInfo: AppWidgetProviderInfo, + val appWidgetHost: CommunalAppWidgetHost, + ) : WidgetContent { + override val key = KEY.widget(appWidgetId) + // Widget size is always half. + override val size = CommunalContentSize.HALF + + /** Whether this widget can be reconfigured after it has already been added. */ + val reconfigurable: Boolean + get() = + (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) && + providerInfo.configure != null + } + + data class DisabledWidget( + override val appWidgetId: Int, + override val providerInfo: AppWidgetProviderInfo + ) : WidgetContent { + override val key = KEY.disabledWidget(appWidgetId) + // Widget size is always half. + override val size = CommunalContentSize.HALF - /** Whether this widget can be reconfigured after it has already been added. */ - val reconfigurable: Boolean - get() = - (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) && - providerInfo.configure != null + val appInfo: ApplicationInfo? + get() = providerInfo.providerInfo?.applicationInfo + } } /** A placeholder item representing a new widget being added */ @@ -111,6 +129,10 @@ sealed interface CommunalContentModel { return "widget_$id" } + fun disabledWidget(id: Int): String { + return "disabled_widget_$id" + } + fun widgetPlaceholder(): String { return "widget_placeholder_${UUID.randomUUID()}" } @@ -129,5 +151,5 @@ sealed interface CommunalContentModel { } } - fun isWidget() = this is Widget + fun isWidgetContent() = this is WidgetContent } |