1 /*
<lambda>null2  * Copyright (C) 2021 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.egg.widget
18 
19 import android.app.PendingIntent
20 import android.appwidget.AppWidgetManager
21 import android.appwidget.AppWidgetProvider
22 import android.content.ComponentName
23 import android.content.Context
24 import android.content.Intent
25 import android.os.Bundle
26 import android.util.Log
27 import android.util.SizeF
28 import android.widget.RemoteViews
29 
30 import com.android.egg.R
31 
32 /**
33  * A homescreen widget to explore the current dynamic system theme.
34  */
35 class PaintChipsWidget : AppWidgetProvider() {
36     override fun onUpdate(
37         context: Context,
38         appWidgetManager: AppWidgetManager,
39         appWidgetIds: IntArray
40     ) {
41         for (appWidgetId in appWidgetIds) {
42             updateAppWidget(context, appWidgetManager, appWidgetId)
43         }
44     }
45 
46     override fun onAppWidgetOptionsChanged(
47         context: Context,
48         appWidgetManager: AppWidgetManager,
49         appWidgetId: Int,
50         newOptions: Bundle?
51     ) {
52         // Log.v(TAG, "onAppWidgetOptionsChanged: id=${appWidgetId}")
53         updateAppWidget(context, appWidgetManager, appWidgetId)
54         super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
55     }
56 }
57 
58 const val TAG = "PaintChips"
59 
60 val SHADE_NUMBERS = intArrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
61 
62 val COLORS_NEUTRAL1 = intArrayOf(
63     android.R.color.system_neutral1_0,
64     android.R.color.system_neutral1_10,
65     android.R.color.system_neutral1_50,
66     android.R.color.system_neutral1_100,
67     android.R.color.system_neutral1_200,
68     android.R.color.system_neutral1_300,
69     android.R.color.system_neutral1_400,
70     android.R.color.system_neutral1_500,
71     android.R.color.system_neutral1_600,
72     android.R.color.system_neutral1_700,
73     android.R.color.system_neutral1_800,
74     android.R.color.system_neutral1_900,
75     android.R.color.system_neutral1_1000
76 )
77 
78 val COLORS_NEUTRAL2 = intArrayOf(
79     android.R.color.system_neutral2_0,
80     android.R.color.system_neutral2_10,
81     android.R.color.system_neutral2_50,
82     android.R.color.system_neutral2_100,
83     android.R.color.system_neutral2_200,
84     android.R.color.system_neutral2_300,
85     android.R.color.system_neutral2_400,
86     android.R.color.system_neutral2_500,
87     android.R.color.system_neutral2_600,
88     android.R.color.system_neutral2_700,
89     android.R.color.system_neutral2_800,
90     android.R.color.system_neutral2_900,
91     android.R.color.system_neutral2_1000
92 )
93 
94 var COLORS_ACCENT1 = intArrayOf(
95     android.R.color.system_accent1_0,
96     android.R.color.system_accent1_10,
97     android.R.color.system_accent1_50,
98     android.R.color.system_accent1_100,
99     android.R.color.system_accent1_200,
100     android.R.color.system_accent1_300,
101     android.R.color.system_accent1_400,
102     android.R.color.system_accent1_500,
103     android.R.color.system_accent1_600,
104     android.R.color.system_accent1_700,
105     android.R.color.system_accent1_800,
106     android.R.color.system_accent1_900,
107     android.R.color.system_accent1_1000
108 )
109 
110 var COLORS_ACCENT2 = intArrayOf(
111     android.R.color.system_accent2_0,
112     android.R.color.system_accent2_10,
113     android.R.color.system_accent2_50,
114     android.R.color.system_accent2_100,
115     android.R.color.system_accent2_200,
116     android.R.color.system_accent2_300,
117     android.R.color.system_accent2_400,
118     android.R.color.system_accent2_500,
119     android.R.color.system_accent2_600,
120     android.R.color.system_accent2_700,
121     android.R.color.system_accent2_800,
122     android.R.color.system_accent2_900,
123     android.R.color.system_accent2_1000
124 )
125 
126 var COLORS_ACCENT3 = intArrayOf(
127     android.R.color.system_accent3_0,
128     android.R.color.system_accent3_10,
129     android.R.color.system_accent3_50,
130     android.R.color.system_accent3_100,
131     android.R.color.system_accent3_200,
132     android.R.color.system_accent3_300,
133     android.R.color.system_accent3_400,
134     android.R.color.system_accent3_500,
135     android.R.color.system_accent3_600,
136     android.R.color.system_accent3_700,
137     android.R.color.system_accent3_800,
138     android.R.color.system_accent3_900,
139     android.R.color.system_accent3_1000
140 )
141 
142 var COLOR_NAMES = arrayOf(
143     "N1", "N2", "A1", "A2", "A3"
144 )
145 
146 var COLORS = arrayOf(
147     COLORS_NEUTRAL1,
148     COLORS_NEUTRAL2,
149     COLORS_ACCENT1,
150     COLORS_ACCENT2,
151     COLORS_ACCENT3
152 )
153 
updateAppWidgetnull154 internal fun updateAppWidget(
155     context: Context,
156     appWidgetManager: AppWidgetManager,
157     appWidgetId: Int
158 ) {
159     // val opts = appWidgetManager.getAppWidgetOptions(appWidgetId)
160     // Log.v(TAG, "requested sizes=${opts[OPTION_APPWIDGET_SIZES]}")
161 
162     val allSizes = mapOf(
163         SizeF(50f, 50f)
164                 to buildWidget(context, 1, 1, ClickBehavior.LAUNCH),
165         SizeF(100f, 50f)
166                 to buildWidget(context, 1, 2, ClickBehavior.LAUNCH),
167         SizeF(150f, 50f)
168                 to buildWidget(context, 1, 3, ClickBehavior.LAUNCH),
169         SizeF(200f, 50f)
170                 to buildWidget(context, 1, 4, ClickBehavior.LAUNCH),
171         SizeF(250f, 50f)
172                 to buildWidget(context, 1, 5, ClickBehavior.LAUNCH),
173 
174         SizeF(50f, 120f)
175                 to buildWidget(context, 3, 1, ClickBehavior.LAUNCH),
176         SizeF(100f, 120f)
177                 to buildWidget(context, 3, 2, ClickBehavior.LAUNCH),
178         SizeF(150f, 120f)
179                 to buildWidget(context, 3, 3, ClickBehavior.LAUNCH),
180         SizeF(200f, 120f)
181                 to buildWidget(context, 3, 4, ClickBehavior.LAUNCH),
182         SizeF(250f, 120f)
183                 to buildWidget(context, 3, 5, ClickBehavior.LAUNCH),
184 
185         SizeF(50f, 250f)
186                 to buildWidget(context, 5, 1, ClickBehavior.LAUNCH),
187         SizeF(100f, 250f)
188                 to buildWidget(context, 5, 2, ClickBehavior.LAUNCH),
189         SizeF(150f, 250f)
190                 to buildWidget(context, 5, 3, ClickBehavior.LAUNCH),
191         SizeF(200f, 250f)
192                 to buildWidget(context, 5, 4, ClickBehavior.LAUNCH),
193         SizeF(250f, 250f)
194                 to buildWidget(context, 5, 5, ClickBehavior.LAUNCH),
195 
196         SizeF(300f, 300f)
197                 to buildWidget(context, SHADE_NUMBERS.size, COLORS.size, ClickBehavior.LAUNCH)
198     )
199 
200     // Instruct the widget manager to update the widget
201     appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(allSizes))
202 }
203 
buildFullWidgetnull204 fun buildFullWidget(context: Context, clickable: ClickBehavior): RemoteViews {
205     return buildWidget(context, SHADE_NUMBERS.size, COLORS.size, clickable)
206 }
207 
buildWidgetnull208 fun buildWidget(context: Context, numShades: Int, numColors: Int, clickable: ClickBehavior):
209         RemoteViews {
210     val grid = RemoteViews(context.packageName, R.layout.paint_chips_grid)
211 
212     // shouldn't be necessary but sometimes the RV instructions get played twice in launcher.
213     grid.removeAllViews(R.id.paint_grid)
214 
215     grid.setInt(R.id.paint_grid, "setRowCount", numShades)
216     grid.setInt(R.id.paint_grid, "setColumnCount", numColors)
217 
218     Log.v(TAG, "building widget: shade rows=$numShades, color columns=$numColors")
219 
220     COLORS.forEachIndexed colorLoop@{ i, colorlist ->
221         when (colorlist) {
222             COLORS_NEUTRAL1 -> if (numColors < 2) return@colorLoop
223             COLORS_NEUTRAL2 -> if (numColors < 4) return@colorLoop
224             COLORS_ACCENT2 -> if (numColors < 3) return@colorLoop
225             COLORS_ACCENT3 -> if (numColors < 5) return@colorLoop
226             else -> {} // always do ACCENT1
227         }
228         colorlist.forEachIndexed shadeLoop@{ j, resId ->
229             when (SHADE_NUMBERS[j]) {
230                 500 -> {}
231                 300, 700 -> if (numShades < 3) return@shadeLoop
232                 100, 900 -> if (numShades < 5) return@shadeLoop
233                 else -> if (numShades < SHADE_NUMBERS.size) return@shadeLoop
234             }
235             val cell = RemoteViews(context.packageName, R.layout.paint_chip)
236             cell.setTextViewText(R.id.chip, "${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]}")
237             val textColor = if (SHADE_NUMBERS[j] > 500)
238                     colorlist[0]
239                     else colorlist[colorlist.size - 1]
240             cell.setTextColor(R.id.chip, context.getColor(textColor))
241             cell.setColorStateList(R.id.chip, "setBackgroundTintList", resId)
242             val text = """
243                     ${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]} (@${
244                     context.resources.getResourceName(resId) })
245                     currently: #${ String.format("%06x", context.getColor(resId) and 0xFFFFFF) }
246                     """.trimIndent()
247             when (clickable) {
248                 ClickBehavior.SHARE -> cell.setOnClickPendingIntent(
249                     R.id.chip,
250                     makeTextSharePendingIntent(context, text)
251                 )
252                 ClickBehavior.LAUNCH -> cell.setOnClickPendingIntent(
253                     R.id.chip,
254                     makeActivityLaunchPendingIntent(context)
255                 )
256                 ClickBehavior.NONE -> { }
257             }
258             grid.addView(R.id.paint_grid, cell)
259         }
260     }
261 
262     return grid
263 }
264 
265 enum class ClickBehavior {
266     NONE,
267     SHARE,
268     LAUNCH
269 }
270 
makeTextSharePendingIntentnull271 fun makeTextSharePendingIntent(context: Context, text: String): PendingIntent {
272     val shareIntent: Intent = Intent().apply {
273         action = Intent.ACTION_SEND
274         putExtra(Intent.EXTRA_TEXT, text)
275         type = "text/plain"
276     }
277 
278     val chooserIntent = Intent.createChooser(shareIntent, null).apply {
279         identifier = text // incredible quality-of-life improvement, thanks framework team
280     }
281 
282     return PendingIntent.getActivity(context, 0, chooserIntent,
283             PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
284 }
285 
makeActivityLaunchPendingIntentnull286 fun makeActivityLaunchPendingIntent(context: Context): PendingIntent {
287     return PendingIntent.getActivity(context, 0,
288         Intent().apply {
289             component = ComponentName(context, PaintChipsActivity::class.java)
290             action = Intent.ACTION_MAIN
291         },
292         PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
293 }
294