From 49fa723e9ca14de06a1789577c9e4f113365133d Mon Sep 17 00:00:00 2001 From: James O'Leary Date: Thu, 26 May 2022 19:52:30 +0000 Subject: [PATCH] Match latest variant spec; update hue rotation logic - Update a couple rotations to match spec (ex. rotation occurs at 151 degrees instead of 141) - If hue rotation specs have an entry at 0 degrees, they also need an entry at 360 degrees. There's no way to determine that, for example, 321 is between 315 and 0, 360 must be listed. - Find hue rotation in a way that ensures ex. an angle isn't tested for being between 0 and 360 degrees, as that will always return true. Instead, use first element, (always 0 degrees), check if angle is between and the next element, and stop once the next element is 360 degrees (always the last element in the array) - Remove code that became unused after the above change. Test: atest ColorSchemeTest (unit test); atest SystemPaletteTest (CTS). Spent ~4 hours trying a variety of wallpapers, and seed colors, and used dumpsys to verify results match UX spec. Create spreadsheet for UX to fill out their spec, then another spreadsheet that contains the dumpsys results for blue/red/yellow/green seed colors across all theme variants, and the preset colors for Ice Cream and Fruit Salad variants. Confirmed the runtime results, as reported by dumpsys, match the spec in all cases. Bug: 213314628 Change-Id: Id35faa294bf82c0e81c2690c65c42218a87c236a --- .../com/android/systemui/monet/ColorScheme.kt | 65 +++++-------------- .../systemui/monet/ColorSchemeTest.java | 2 +- 2 files changed, 19 insertions(+), 48 deletions(-) diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt index 0c82022609074..9df65e3417f52 100644 --- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt @@ -22,7 +22,6 @@ import android.graphics.Color import com.android.internal.graphics.ColorUtils import com.android.internal.graphics.cam.Cam import kotlin.math.absoluteValue -import kotlin.math.max import kotlin.math.roundToInt const val TAG = "ColorScheme" @@ -43,13 +42,13 @@ internal interface Hue { * second item in the pair is a hue rotation that should be applied */ fun getHueRotation(sourceHue: Float, hueAndRotations: List>): Double { - for (i in 0..hueAndRotations.size) { - val previousIndex = if (i == 0) hueAndRotations.size - 1 else i - 1 - val thisHue = hueAndRotations[i].first - val previousHue = hueAndRotations[previousIndex].first - if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) { - return ColorScheme.wrapDegreesDouble(sourceHue.toDouble() + - hueAndRotations[previousIndex].second) + val sanitizedSourceHue = (if (sourceHue < 0 || sourceHue >= 360) 0 else sourceHue).toFloat() + for (i in 0..hueAndRotations.size - 2) { + val thisHue = hueAndRotations[i].first.toFloat() + val nextHue = hueAndRotations[i + 1].first.toFloat() + if (thisHue <= sanitizedSourceHue && sanitizedSourceHue < nextHue) { + return ColorScheme.wrapDegreesDouble(sanitizedSourceHue.toDouble() + + hueAndRotations[i].second) } } @@ -79,7 +78,7 @@ internal class HueSubtract(val amountDegrees: Double) : Hue { internal class HueVibrantSecondary() : Hue { val hueToRotations = listOf(Pair(0, 18), Pair(41, 15), Pair(61, 10), Pair(101, 12), - Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12)) + Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12), Pair(360, 12)) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) } @@ -87,7 +86,7 @@ internal class HueVibrantSecondary() : Hue { internal class HueVibrantTertiary() : Hue { val hueToRotations = listOf(Pair(0, 35), Pair(41, 30), Pair(61, 20), Pair(101, 25), - Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25)) + Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25), Pair(360, 25)) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) } @@ -95,7 +94,7 @@ internal class HueVibrantTertiary() : Hue { internal class HueExpressiveSecondary() : Hue { val hueToRotations = listOf(Pair(0, 45), Pair(21, 95), Pair(51, 45), Pair(121, 20), - Pair(141, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45)) + Pair(151, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45), Pair(360, 45)) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) } @@ -103,7 +102,7 @@ internal class HueExpressiveSecondary() : Hue { internal class HueExpressiveTertiary() : Hue { val hueToRotations = listOf(Pair(0, 120), Pair(21, 120), Pair(51, 20), Pair(121, 45), - Pair(141, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120)) + Pair(151, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120), Pair(360, 120)) override fun get(sourceColor: Cam): Double { return getHueRotation(sourceColor.hue, hueToRotations) } @@ -111,34 +110,13 @@ internal class HueExpressiveTertiary() : Hue { internal interface Chroma { fun get(sourceColor: Cam): Double - - /** - * Given a hue, and a mapping of hues to hue rotations, find which hues in the mapping the - * hue fall betweens, and use the hue rotation of the lower hue. - * - * @param sourceHue hue of source color - * @param hueAndChromas list of pairs, where the first item in a pair is a hue, and the - * second item in the pair is a chroma that should be applied - */ - fun getSpecifiedChroma(sourceHue: Float, hueAndChromas: List>): Double { - for (i in 0..hueAndChromas.size) { - val previousIndex = if (i == 0) hueAndChromas.size - 1 else i - 1 - val thisHue = hueAndChromas[i].first - val previousHue = hueAndChromas[previousIndex].first - if (ColorScheme.angleIsBetween(sourceHue, thisHue, previousHue)) { - return hueAndChromas[i].second.toDouble() - } - } - - // If this statement executes, something is wrong, there should have been a rotation - // found using the arrays. - return sourceHue.toDouble() - } } -internal class ChromaMinimum(val chroma: Double) : Chroma { +internal class ChromaMaxOut : Chroma { override fun get(sourceColor: Cam): Double { - return max(sourceColor.chroma.toDouble(), chroma) + // Intentionally high. Gamut mapping from impossible HCT to sRGB will ensure that + // the maximum chroma is reached, even if lower than this constant. + return 130.0 } } @@ -192,11 +170,11 @@ enum class Style(internal val coreSpec: CoreSpec) { n2 = TonalSpec(HueSource(), ChromaConstant(8.0)) )), VIBRANT(CoreSpec( - a1 = TonalSpec(HueSource(), ChromaMinimum(48.0)), + a1 = TonalSpec(HueSource(), ChromaMaxOut()), a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)), a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)), - n1 = TonalSpec(HueSource(), ChromaConstant(12.0)), - n2 = TonalSpec(HueSource(), ChromaConstant(14.0)) + n1 = TonalSpec(HueSource(), ChromaConstant(8.0)), + n2 = TonalSpec(HueSource(), ChromaConstant(12.0)) )), EXPRESSIVE(CoreSpec( a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)), @@ -416,13 +394,6 @@ class ColorScheme( return seeds } - internal fun angleIsBetween(angle: Float, a: Int, b: Int): Boolean { - if (a < b) { - return a <= angle && angle <= b - } - return a <= angle || angle <= b - } - private fun wrapDegrees(degrees: Int): Int { return when { degrees < 0 -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java index 890e4de118e3f..63dca3bafc5b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java @@ -69,7 +69,7 @@ public class ColorSchemeTest extends SysuiTestCase { // Expressive applies hue rotations to the theme color. The input theme color has hue // 117, ensuring the hue changed significantly is a strong signal styles are being applied. ColorScheme colorScheme = new ColorScheme(wallpaperColors, false, Style.EXPRESSIVE); - Assert.assertEquals(Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 357.46, 0.1); + Assert.assertEquals(357.77, Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 0.1); }