• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.communal.domain.model
18 
19 import android.appwidget.AppWidgetProviderInfo
20 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
21 import android.content.ComponentName
22 import android.content.pm.ApplicationInfo
23 import android.graphics.Bitmap
24 import android.widget.RemoteViews
25 import com.android.systemui.Flags.communalResponsiveGrid
26 import com.android.systemui.communal.shared.model.CommunalContentSize
27 import java.util.UUID
28 
29 /** Encapsulates data for a communal content. */
30 sealed interface CommunalContentModel {
31     /** Unique key across all types of content models. */
32     val key: String
33 
34     /** Size to be rendered in the grid. */
35     val size: CommunalContentSize
36 
37     /** The minimum size content can be resized to. */
38     val minSize: CommunalContentSize
39         get() = fixedHalfOrResponsiveSize()
40 
41     /**
42      * A type of communal content is ongoing / live / ephemeral, and can be sized and ordered
43      * dynamically.
44      */
45     sealed interface Ongoing : CommunalContentModel {
46         override var size: CommunalContentSize
47         override val minSize
48             get() =
49                 if (communalResponsiveGrid()) {
50                     CommunalContentSize.Responsive(1)
51                 } else {
52                     CommunalContentSize.FixedSize.THIRD
53                 }
54 
55         /** Timestamp in milliseconds of when the content was created. */
56         val createdTimestampMillis: Long
57     }
58 
59     sealed interface WidgetContent : CommunalContentModel {
60         val appWidgetId: Int
61         val rank: Int
62         val componentName: ComponentName
63 
64         data class Widget(
65             override val appWidgetId: Int,
66             override val rank: Int,
67             val providerInfo: AppWidgetProviderInfo,
68             val inQuietMode: Boolean,
69             override val size: CommunalContentSize,
70         ) : WidgetContent {
71             override val key = KEY.widget(appWidgetId)
72             override val componentName: ComponentName = providerInfo.provider
73 
74             /** Whether this widget can be reconfigured after it has already been added. */
75             val reconfigurable: Boolean
76                 get() =
77                     (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) &&
78                         providerInfo.configure != null
79         }
80 
81         data class DisabledWidget(
82             override val appWidgetId: Int,
83             override val rank: Int,
84             val providerInfo: AppWidgetProviderInfo,
85             override val size: CommunalContentSize,
86         ) : WidgetContent {
87             override val key = KEY.disabledWidget(appWidgetId)
88             override val componentName: ComponentName = providerInfo.provider
89 
90             val appInfo: ApplicationInfo?
91                 get() = providerInfo.providerInfo?.applicationInfo
92         }
93 
94         data class PendingWidget(
95             override val appWidgetId: Int,
96             override val rank: Int,
97             override val componentName: ComponentName,
98             override val size: CommunalContentSize,
99             val icon: Bitmap? = null,
100         ) : WidgetContent {
101             override val key = KEY.pendingWidget(appWidgetId)
102         }
103     }
104 
105     /** A placeholder item representing a new widget being added */
106     class WidgetPlaceholder : CommunalContentModel {
107         override val key: String = KEY.widgetPlaceholder()
108         // Same as widget size.
109         override val size: CommunalContentSize
110             get() = fixedHalfOrResponsiveSize()
111     }
112 
113     /** An empty spacer to reserve space in the grid. */
114     data class Spacer(override val size: CommunalContentSize) : CommunalContentModel {
115         override val key: String = KEY.spacer()
116     }
117 
118     /** A CTA tile in the glanceable hub view mode which can be dismissed. */
119     class CtaTileInViewMode : CommunalContentModel {
120         override val key: String = KEY.CTA_TILE_IN_VIEW_MODE_KEY
121         // Same as widget size.
122         override val size: CommunalContentSize
123             get() = fixedHalfOrResponsiveSize()
124     }
125 
126     class Tutorial(id: Int, override var size: CommunalContentSize) : CommunalContentModel {
127         override val key = KEY.tutorial(id)
128     }
129 
130     class Smartspace(
131         smartspaceTargetId: String,
132         val remoteViews: RemoteViews,
133         override val createdTimestampMillis: Long,
134         override var size: CommunalContentSize = fixedHalfOrResponsiveSize(),
135     ) : Ongoing {
136         override val key = KEY.smartspace(smartspaceTargetId)
137     }
138 
139     class Umo(
140         override val createdTimestampMillis: Long,
141         override var size: CommunalContentSize = fixedHalfOrResponsiveSize(),
142         override var minSize: CommunalContentSize = fixedHalfOrResponsiveSize(),
143     ) : Ongoing {
144         override val key = KEY.umo()
145     }
146 
147     class KEY {
148         companion object {
149             const val CTA_TILE_IN_VIEW_MODE_KEY = "cta_tile_in_view_mode"
150             const val CTA_TILE_IN_EDIT_MODE_KEY = "cta_tile_in_edit_mode"
151 
widgetnull152             fun widget(id: Int): String {
153                 return "widget_$id"
154             }
155 
disabledWidgetnull156             fun disabledWidget(id: Int): String {
157                 return "disabled_widget_$id"
158             }
159 
pendingWidgetnull160             fun pendingWidget(id: Int): String {
161                 return "pending_widget_$id"
162             }
163 
widgetPlaceholdernull164             fun widgetPlaceholder(): String {
165                 return "widget_placeholder_${UUID.randomUUID()}"
166             }
167 
tutorialnull168             fun tutorial(id: Int): String {
169                 return "tutorial_$id"
170             }
171 
smartspacenull172             fun smartspace(id: String): String {
173                 return "smartspace_$id"
174             }
175 
umonull176             fun umo(): String {
177                 return "umo"
178             }
179 
spacernull180             fun spacer(): String {
181                 return "spacer_${UUID.randomUUID()}"
182             }
183         }
184     }
185 
isWidgetContentnull186     fun isWidgetContent() = this is WidgetContent
187 
188     fun isLiveContent() = this is Smartspace || this is Umo
189 }
190 
191 private fun fixedHalfOrResponsiveSize() =
192     if (communalResponsiveGrid()) {
193         CommunalContentSize.Responsive(1)
194     } else {
195         CommunalContentSize.FixedSize.HALF
196     }
197