From 3bc073de03439c0c89add9f6d260620f4b599f1e Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Mon, 26 Jul 2021 02:55:49 -0400 Subject: [PATCH 1/2] icon++ Test: visual Bug: 177962166 Change-Id: I730e6494e2bf0d26a84fbe24b579663306fffb6c --- .../res/drawable-nodpi/android_12.xml | 37 +++++++++++++++++++ packages/SystemUI/res/drawable-nodpi/icon.xml | 2 +- .../SystemUI/res/drawable-nodpi/icon_bg.xml | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 packages/SystemUI/res/drawable-nodpi/android_12.xml diff --git a/packages/SystemUI/res/drawable-nodpi/android_12.xml b/packages/SystemUI/res/drawable-nodpi/android_12.xml new file mode 100644 index 0000000000000..bdeeced2d290f --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/android_12.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml index 7f8d4fa8833ff..997249632709e 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon.xml @@ -15,5 +15,5 @@ Copyright (C) 2018 The Android Open Source Project --> - + diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml index 31b2a7f9a333d..ff7cbae16ab28 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml @@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> + android:color="@android:color/system_accent1_500" /> From 3f261e6eca8e066cd3893af30b9e9549f07b7ca4 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Sat, 24 Jul 2021 15:23:19 -0400 Subject: [PATCH 2/2] Do you need paint chips? Android 12 has so many new colors. But which to use? Sounds like you might need some PAINT CHIPS! Stop by your local hardware store, where you'll find them in the paint aisle. Grab as many as you can hold---they're free! When you get home, hold them up to your app or appwidget and see how they look in different lighting and against different wallpaper. You'll be soothed by the neutrals and piqued by the accents! Test: To enable the widget and activity, use the platlogo, or: $ adb shell settings put system egg_mode_s 12345 && \ adb shell am start -a android.intent.action.MAIN \ -c com.android.internal.category.PLATLOGO Then you should be able to add the widget to the launcher, as well as: $ adb shell am start -n com.android.egg/.widget.PaintChipsActivity Bug: 177962166 Change-Id: I0f3907c86f881d92a14d7659388f6a56154d8c10 --- packages/EasterEgg/AndroidManifest.xml | 101 +++--- packages/EasterEgg/build.gradle | 8 +- packages/EasterEgg/gradle.properties | 2 +- packages/EasterEgg/res/drawable/android_s.xml | 23 ++ packages/EasterEgg/res/drawable/icon.xml | 2 +- packages/EasterEgg/res/drawable/icon_bg.xml | 2 +- packages/EasterEgg/res/drawable/roundrect.xml | 7 + packages/EasterEgg/res/layout/paint_chip.xml | 29 ++ .../EasterEgg/res/layout/paint_chips_grid.xml | 25 ++ .../res/layout/paint_chips_widget_preview.xml | 79 +++++ .../EasterEgg/res/values-night/themes.xml | 7 + packages/EasterEgg/res/values/attrs.xml | 6 + packages/EasterEgg/res/values/colors.xml | 7 +- packages/EasterEgg/res/values/dimens.xml | 9 +- packages/EasterEgg/res/values/strings.xml | 6 +- packages/EasterEgg/res/values/themes.xml | 7 + .../res/xml/paint_chips_widget_info.xml | 24 ++ .../egg/ComponentActivationActivity.java | 83 +++++ .../egg/neko/NekoActivationActivity.java | 66 ---- .../android/egg/widget/PaintChipsActivity.kt | 67 ++++ .../android/egg/widget/PaintChipsWidget.kt | 293 ++++++++++++++++++ 21 files changed, 742 insertions(+), 111 deletions(-) create mode 100644 packages/EasterEgg/res/drawable/android_s.xml create mode 100644 packages/EasterEgg/res/drawable/roundrect.xml create mode 100644 packages/EasterEgg/res/layout/paint_chip.xml create mode 100644 packages/EasterEgg/res/layout/paint_chips_grid.xml create mode 100644 packages/EasterEgg/res/layout/paint_chips_widget_preview.xml create mode 100644 packages/EasterEgg/res/values-night/themes.xml create mode 100644 packages/EasterEgg/res/values/attrs.xml create mode 100644 packages/EasterEgg/res/values/themes.xml create mode 100644 packages/EasterEgg/res/xml/paint_chips_widget_info.xml create mode 100644 packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java delete mode 100644 packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java create mode 100644 packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt create mode 100644 packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml index 3d62af020627f..7f258eb2f910a 100644 --- a/packages/EasterEgg/AndroidManifest.xml +++ b/packages/EasterEgg/AndroidManifest.xml @@ -1,26 +1,28 @@ + + - - @@ -29,9 +31,9 @@ @@ -39,13 +41,15 @@ - + android:label="@string/app_name" + android:theme="@android:style/Theme.Material.NoActionBar"> + @@ -54,25 +58,24 @@ - - + android:exported="true" + android:permission="android.permission.BIND_JOB_SERVICE" /> - - + android:showOnLockScreen="true" + android:theme="@android:style/Theme.Material.Light.Dialog.NoActionBar" /> - + android:theme="@android:style/Theme.NoDisplay"> - + + @@ -81,37 +84,65 @@ + android:icon="@drawable/stat_icon" + android:label="@string/default_tile_name" + android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> - - + android:exported="true" + android:icon="@drawable/ic_fullcat_icon" + android:label="@string/r_egg_name" + android:permission="android.permission.BIND_CONTROLS"> - - - + + android:exported="false" + android:grantUriPermissions="true"> + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/packages/EasterEgg/build.gradle b/packages/EasterEgg/build.gradle index 20b469898498b..0565369fe81fe 100644 --- a/packages/EasterEgg/build.gradle +++ b/packages/EasterEgg/build.gradle @@ -7,8 +7,8 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.android.tools.build:gradle:7.0.0-alpha08' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30" } } @@ -62,6 +62,9 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + buildFeatures { + viewBinding true + } } @@ -74,6 +77,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6' implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}" implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}" + implementation 'com.google.android.material:material:1.3.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/packages/EasterEgg/gradle.properties b/packages/EasterEgg/gradle.properties index e8e6450e2943f..0b5a73677b3b0 100644 --- a/packages/EasterEgg/gradle.properties +++ b/packages/EasterEgg/gradle.properties @@ -19,5 +19,5 @@ android.enableJetifier=true kotlin.code.style=official ANDROID_X_VERSION=1+ -COMPILE_SDK=android-30 +COMPILE_SDK=android-S BUILD_TOOLS_VERSION=28.0.3 diff --git a/packages/EasterEgg/res/drawable/android_s.xml b/packages/EasterEgg/res/drawable/android_s.xml new file mode 100644 index 0000000000000..9cecab103ac82 --- /dev/null +++ b/packages/EasterEgg/res/drawable/android_s.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/icon.xml index 7f8d4fa8833ff..7054962b3503f 100644 --- a/packages/EasterEgg/res/drawable/icon.xml +++ b/packages/EasterEgg/res/drawable/icon.xml @@ -15,5 +15,5 @@ Copyright (C) 2018 The Android Open Source Project --> - + diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml index 31b2a7f9a333d..d08e160ea312b 100644 --- a/packages/EasterEgg/res/drawable/icon_bg.xml +++ b/packages/EasterEgg/res/drawable/icon_bg.xml @@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> + android:color="@android:color/system_accent2_500" /> diff --git a/packages/EasterEgg/res/drawable/roundrect.xml b/packages/EasterEgg/res/drawable/roundrect.xml new file mode 100644 index 0000000000000..070adadf3814a --- /dev/null +++ b/packages/EasterEgg/res/drawable/roundrect.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/packages/EasterEgg/res/layout/paint_chip.xml b/packages/EasterEgg/res/layout/paint_chip.xml new file mode 100644 index 0000000000000..d5745b94d163a --- /dev/null +++ b/packages/EasterEgg/res/layout/paint_chip.xml @@ -0,0 +1,29 @@ + + + \ No newline at end of file diff --git a/packages/EasterEgg/res/layout/paint_chips_grid.xml b/packages/EasterEgg/res/layout/paint_chips_grid.xml new file mode 100644 index 0000000000000..79f7013221496 --- /dev/null +++ b/packages/EasterEgg/res/layout/paint_chips_grid.xml @@ -0,0 +1,25 @@ + + + diff --git a/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml new file mode 100644 index 0000000000000..9893ec0549922 --- /dev/null +++ b/packages/EasterEgg/res/layout/paint_chips_widget_preview.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + diff --git a/packages/EasterEgg/res/values-night/themes.xml b/packages/EasterEgg/res/values-night/themes.xml new file mode 100644 index 0000000000000..83ec7a5557c3c --- /dev/null +++ b/packages/EasterEgg/res/values-night/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/EasterEgg/res/values/attrs.xml b/packages/EasterEgg/res/values/attrs.xml new file mode 100644 index 0000000000000..97531a25692c3 --- /dev/null +++ b/packages/EasterEgg/res/values/attrs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/EasterEgg/res/values/colors.xml b/packages/EasterEgg/res/values/colors.xml index 1a5388b738dd9..d79e83b8af0c7 100644 --- a/packages/EasterEgg/res/values/colors.xml +++ b/packages/EasterEgg/res/values/colors.xml @@ -1,5 +1,4 @@ - - 64dp + + + 0dp diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml index 25f94215d433d..743947ad281e1 100644 --- a/packages/EasterEgg/res/values/strings.xml +++ b/packages/EasterEgg/res/values/strings.xml @@ -14,7 +14,7 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> - Android R Easter Egg + Android S Easter Egg Icon Quiz @@ -23,4 +23,8 @@ Copyright (C) 2018 The Android Open Source Project PAINT.APK Cat Controls + + + Paint Chips diff --git a/packages/EasterEgg/res/values/themes.xml b/packages/EasterEgg/res/values/themes.xml new file mode 100644 index 0000000000000..5b163043a3561 --- /dev/null +++ b/packages/EasterEgg/res/values/themes.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/EasterEgg/res/xml/paint_chips_widget_info.xml b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml new file mode 100644 index 0000000000000..7780a757f01c3 --- /dev/null +++ b/packages/EasterEgg/res/xml/paint_chips_widget_info.xml @@ -0,0 +1,24 @@ + + + \ No newline at end of file diff --git a/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java new file mode 100644 index 0000000000000..5820b5a758942 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/ComponentActivationActivity.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 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.egg; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.provider.Settings; +import android.util.Log; +import android.widget.Toast; + +import com.android.egg.neko.NekoControlsService; +import com.android.egg.widget.PaintChipsActivity; +import com.android.egg.widget.PaintChipsWidget; + +/** + * Launched from the PlatLogoActivity. Enables everything else in this easter egg. + */ +public class ComponentActivationActivity extends Activity { + private static final String TAG = "EasterEgg"; + + private static final String S_EGG_UNLOCK_SETTING = "egg_mode_s"; + + private void toastUp(String s) { + Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT); + toast.show(); + } + + @Override + public void onStart() { + super.onStart(); + + final PackageManager pm = getPackageManager(); + final ComponentName[] cns = new ComponentName[] { + new ComponentName(this, NekoControlsService.class), + new ComponentName(this, PaintChipsActivity.class), + new ComponentName(this, PaintChipsWidget.class) + }; + final long unlockValue = Settings.System.getLong(getContentResolver(), + S_EGG_UNLOCK_SETTING, 0); + for (ComponentName cn : cns) { + final boolean componentEnabled = pm.getComponentEnabledSetting(cn) + == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + if (unlockValue == 0) { + if (componentEnabled) { + Log.v(TAG, "Disabling component: " + cn); + pm.setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + //toastUp("\uD83D\uDEAB"); + } else { + Log.v(TAG, "Already disabled: " + cn); + } + } else { + if (!componentEnabled) { + Log.v(TAG, "Enabling component: " + cn); + pm.setComponentEnabledSetting(cn, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + //toastUp("\uD83D\uDC31"); + } else { + Log.v(TAG, "Already enabled: " + cn); + } + } + } + + finish(); + } +} diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java b/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java deleted file mode 100644 index df461c6878f0c..0000000000000 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoActivationActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2016 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.egg.neko; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.pm.PackageManager; -import android.provider.Settings; -import android.util.Log; -import android.widget.Toast; - -import com.android.internal.logging.MetricsLogger; - -public class NekoActivationActivity extends Activity { - private static final String R_EGG_UNLOCK_SETTING = "egg_mode_r"; - - private void toastUp(String s) { - Toast toast = Toast.makeText(this, s, Toast.LENGTH_SHORT); - toast.show(); - } - - @Override - public void onStart() { - super.onStart(); - - final PackageManager pm = getPackageManager(); - final ComponentName cn = new ComponentName(this, NekoControlsService.class); - final boolean componentEnabled = pm.getComponentEnabledSetting(cn) - == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - if (Settings.System.getLong(getContentResolver(), - R_EGG_UNLOCK_SETTING, 0) == 0) { - if (componentEnabled) { - Log.v("Neko", "Disabling controls."); - pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP); - MetricsLogger.histogram(this, "egg_neko_enable", 0); - toastUp("\uD83D\uDEAB"); - } else { - Log.v("Neko", "Controls already disabled."); - } - } else { - if (!componentEnabled) { - Log.v("Neko", "Enabling controls."); - pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP); - MetricsLogger.histogram(this, "egg_neko_enable", 1); - toastUp("\uD83D\uDC31"); - } else { - Log.v("Neko", "Controls already enabled."); - } - } - finish(); - } -} diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt new file mode 100644 index 0000000000000..8799aecf55166 --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsActivity.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 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.egg.widget + +import android.app.Activity +import android.content.res.Configuration +import android.os.Bundle +import android.widget.FrameLayout + +/** + * Activity to show off the current dynamic system theme in all its glory. + */ +class PaintChipsActivity : Activity() { + private lateinit var layout: FrameLayout + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + window.navigationBarColor = 0 + window.statusBarColor = 0 + actionBar?.hide() + + layout = FrameLayout(this) + layout.setPadding(dp2px(8f), dp2px(8f), dp2px(8f), dp2px(8f)) + rebuildGrid() + + setContentView(layout) + } + + fun dp2px(dp: Float): Int { + return (dp * resources.displayMetrics.density).toInt() + } + + override fun onResume() { + super.onResume() + + rebuildGrid() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + + rebuildGrid() + } + + private fun rebuildGrid() { + layout.removeAllViews() + val grid = buildFullWidget(this, ClickBehavior.SHARE) + val asView = grid.apply(this, layout) + layout.addView(asView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT)) + } +} diff --git a/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt new file mode 100644 index 0000000000000..c15cabbb0eb6a --- /dev/null +++ b/packages/EasterEgg/src/com/android/egg/widget/PaintChipsWidget.kt @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2021 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.egg.widget + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.util.Log +import android.util.SizeF +import android.widget.RemoteViews + +import com.android.egg.R + +/** + * A homescreen widget to explore the current dynamic system theme. + */ +class PaintChipsWidget : AppWidgetProvider() { + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray + ) { + for (appWidgetId in appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId) + } + } + + override fun onAppWidgetOptionsChanged( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetId: Int, + newOptions: Bundle? + ) { + // Log.v(TAG, "onAppWidgetOptionsChanged: id=${appWidgetId}") + updateAppWidget(context, appWidgetManager, appWidgetId) + super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions) + } +} + +const val TAG = "PaintChips" + +val SHADE_NUMBERS = intArrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000) + +val COLORS_NEUTRAL1 = intArrayOf( + android.R.color.system_neutral1_0, + android.R.color.system_neutral1_10, + android.R.color.system_neutral1_50, + android.R.color.system_neutral1_100, + android.R.color.system_neutral1_200, + android.R.color.system_neutral1_300, + android.R.color.system_neutral1_400, + android.R.color.system_neutral1_500, + android.R.color.system_neutral1_600, + android.R.color.system_neutral1_700, + android.R.color.system_neutral1_800, + android.R.color.system_neutral1_900, + android.R.color.system_neutral1_1000 +) + +val COLORS_NEUTRAL2 = intArrayOf( + android.R.color.system_neutral2_0, + android.R.color.system_neutral2_10, + android.R.color.system_neutral2_50, + android.R.color.system_neutral2_100, + android.R.color.system_neutral2_200, + android.R.color.system_neutral2_300, + android.R.color.system_neutral2_400, + android.R.color.system_neutral2_500, + android.R.color.system_neutral2_600, + android.R.color.system_neutral2_700, + android.R.color.system_neutral2_800, + android.R.color.system_neutral2_900, + android.R.color.system_neutral2_1000 +) + +var COLORS_ACCENT1 = intArrayOf( + android.R.color.system_accent1_0, + android.R.color.system_accent1_10, + android.R.color.system_accent1_50, + android.R.color.system_accent1_100, + android.R.color.system_accent1_200, + android.R.color.system_accent1_300, + android.R.color.system_accent1_400, + android.R.color.system_accent1_500, + android.R.color.system_accent1_600, + android.R.color.system_accent1_700, + android.R.color.system_accent1_800, + android.R.color.system_accent1_900, + android.R.color.system_accent1_1000 +) + +var COLORS_ACCENT2 = intArrayOf( + android.R.color.system_accent2_0, + android.R.color.system_accent2_10, + android.R.color.system_accent2_50, + android.R.color.system_accent2_100, + android.R.color.system_accent2_200, + android.R.color.system_accent2_300, + android.R.color.system_accent2_400, + android.R.color.system_accent2_500, + android.R.color.system_accent2_600, + android.R.color.system_accent2_700, + android.R.color.system_accent2_800, + android.R.color.system_accent2_900, + android.R.color.system_accent2_1000 +) + +var COLORS_ACCENT3 = intArrayOf( + android.R.color.system_accent3_0, + android.R.color.system_accent3_10, + android.R.color.system_accent3_50, + android.R.color.system_accent3_100, + android.R.color.system_accent3_200, + android.R.color.system_accent3_300, + android.R.color.system_accent3_400, + android.R.color.system_accent3_500, + android.R.color.system_accent3_600, + android.R.color.system_accent3_700, + android.R.color.system_accent3_800, + android.R.color.system_accent3_900, + android.R.color.system_accent3_1000 +) + +var COLOR_NAMES = arrayOf( + "N1", "N2", "A1", "A2", "A3" +) + +var COLORS = arrayOf( + COLORS_NEUTRAL1, + COLORS_NEUTRAL2, + COLORS_ACCENT1, + COLORS_ACCENT2, + COLORS_ACCENT3 +) + +internal fun updateAppWidget( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetId: Int +) { + // val opts = appWidgetManager.getAppWidgetOptions(appWidgetId) + // Log.v(TAG, "requested sizes=${opts[OPTION_APPWIDGET_SIZES]}") + + val allSizes = mapOf( + SizeF(50f, 50f) + to buildWidget(context, 1, 1, ClickBehavior.LAUNCH), + SizeF(100f, 50f) + to buildWidget(context, 1, 2, ClickBehavior.LAUNCH), + SizeF(150f, 50f) + to buildWidget(context, 1, 3, ClickBehavior.LAUNCH), + SizeF(200f, 50f) + to buildWidget(context, 1, 4, ClickBehavior.LAUNCH), + SizeF(250f, 50f) + to buildWidget(context, 1, 5, ClickBehavior.LAUNCH), + + SizeF(50f, 120f) + to buildWidget(context, 3, 1, ClickBehavior.LAUNCH), + SizeF(100f, 120f) + to buildWidget(context, 3, 2, ClickBehavior.LAUNCH), + SizeF(150f, 120f) + to buildWidget(context, 3, 3, ClickBehavior.LAUNCH), + SizeF(200f, 120f) + to buildWidget(context, 3, 4, ClickBehavior.LAUNCH), + SizeF(250f, 120f) + to buildWidget(context, 3, 5, ClickBehavior.LAUNCH), + + SizeF(50f, 250f) + to buildWidget(context, 5, 1, ClickBehavior.LAUNCH), + SizeF(100f, 250f) + to buildWidget(context, 5, 2, ClickBehavior.LAUNCH), + SizeF(150f, 250f) + to buildWidget(context, 5, 3, ClickBehavior.LAUNCH), + SizeF(200f, 250f) + to buildWidget(context, 5, 4, ClickBehavior.LAUNCH), + SizeF(250f, 250f) + to buildWidget(context, 5, 5, ClickBehavior.LAUNCH), + + SizeF(300f, 300f) + to buildWidget(context, SHADE_NUMBERS.size, COLORS.size, ClickBehavior.LAUNCH) + ) + + // Instruct the widget manager to update the widget + appWidgetManager.updateAppWidget(appWidgetId, RemoteViews(allSizes)) +} + +fun buildFullWidget(context: Context, clickable: ClickBehavior): RemoteViews { + return buildWidget(context, SHADE_NUMBERS.size, COLORS.size, clickable) +} + +fun buildWidget(context: Context, numShades: Int, numColors: Int, clickable: ClickBehavior): + RemoteViews { + val grid = RemoteViews(context.packageName, R.layout.paint_chips_grid) + + // shouldn't be necessary but sometimes the RV instructions get played twice in launcher. + grid.removeAllViews(R.id.paint_grid) + + grid.setInt(R.id.paint_grid, "setRowCount", numShades) + grid.setInt(R.id.paint_grid, "setColumnCount", numColors) + + Log.v(TAG, "building widget: shade rows=$numShades, color columns=$numColors") + + COLORS.forEachIndexed colorLoop@{ i, colorlist -> + when (colorlist) { + COLORS_NEUTRAL1 -> if (numColors < 2) return@colorLoop + COLORS_NEUTRAL2 -> if (numColors < 4) return@colorLoop + COLORS_ACCENT2 -> if (numColors < 3) return@colorLoop + COLORS_ACCENT3 -> if (numColors < 5) return@colorLoop + else -> {} // always do ACCENT1 + } + colorlist.forEachIndexed shadeLoop@{ j, resId -> + when (SHADE_NUMBERS[j]) { + 500 -> {} + 300, 700 -> if (numShades < 3) return@shadeLoop + 100, 900 -> if (numShades < 5) return@shadeLoop + else -> if (numShades < SHADE_NUMBERS.size) return@shadeLoop + } + val cell = RemoteViews(context.packageName, R.layout.paint_chip) + cell.setTextViewText(R.id.chip, "${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]}") + val textColor = if (SHADE_NUMBERS[j] > 500) + colorlist[0] + else colorlist[colorlist.size - 1] + cell.setTextColor(R.id.chip, context.getColor(textColor)) + cell.setColorStateList(R.id.chip, "setBackgroundTintList", resId) + val text = """ + ${COLOR_NAMES[i]}-${SHADE_NUMBERS[j]} (@${ + context.resources.getResourceName(resId) }) + currently: #${ String.format("%06x", context.getColor(resId) and 0xFFFFFF) } + """.trimIndent() + when (clickable) { + ClickBehavior.SHARE -> cell.setOnClickPendingIntent( + R.id.chip, + makeTextSharePendingIntent(context, text) + ) + ClickBehavior.LAUNCH -> cell.setOnClickPendingIntent( + R.id.chip, + makeActivityLaunchPendingIntent(context) + ) + ClickBehavior.NONE -> { } + } + grid.addView(R.id.paint_grid, cell) + } + } + + return grid +} + +enum class ClickBehavior { + NONE, + SHARE, + LAUNCH +} + +fun makeTextSharePendingIntent(context: Context, text: String): PendingIntent { + val shareIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, text) + type = "text/plain" + } + + val chooserIntent = Intent.createChooser(shareIntent, null).apply { + identifier = text // incredible quality-of-life improvement, thanks framework team + } + + return PendingIntent.getActivity(context, 0, chooserIntent, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) +} + +fun makeActivityLaunchPendingIntent(context: Context): PendingIntent { + return PendingIntent.getActivity(context, 0, + Intent().apply { + component = ComponentName(context, PaintChipsActivity::class.java) + action = Intent.ACTION_MAIN + }, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) +}