Improve visualizer color selection.
Make sure to select the color that contrasts the most to the artwork.
Change-Id: I0043463e05132a01f8ff3351565b672825779079
diff --git a/src/com/cyanogenmod/eleven/ui/activities/HomeActivity.java b/src/com/cyanogenmod/eleven/ui/activities/HomeActivity.java
index 1462f9a..9dd7576 100644
--- a/src/com/cyanogenmod/eleven/ui/activities/HomeActivity.java
+++ b/src/com/cyanogenmod/eleven/ui/activities/HomeActivity.java
@@ -202,7 +202,7 @@
@Override
protected void onPostExecute(BitmapWithColors bmc) {
updateVisualizerColor(bmc != null
- ? bmc.getVibrantColor() : Color.TRANSPARENT);
+ ? bmc.getContrastingColor() : Color.TRANSPARENT);
updateStatusBarColor(bmc != null
? bmc.getVibrantDarkColor() : Color.TRANSPARENT);
}
diff --git a/src/com/cyanogenmod/eleven/utils/BitmapWithColors.java b/src/com/cyanogenmod/eleven/utils/BitmapWithColors.java
index 77b3573..a587c84 100644
--- a/src/com/cyanogenmod/eleven/utils/BitmapWithColors.java
+++ b/src/com/cyanogenmod/eleven/utils/BitmapWithColors.java
@@ -18,16 +18,42 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.v7.graphics.Palette;
+import android.support.v7.graphics.Target;
import android.util.LruCache;
public class BitmapWithColors {
private static final class BitmapColors {
- public int mVibrantColor;
- public int mVibrantDarkColor;
+ public final int mVibrantColor;
+ public final int mVibrantDarkColor;
+ public final int mVibrantLightColor;
+ public final int mDominantColor;
+
+ public BitmapColors(Palette palette) {
+ mVibrantColor = determineColor(palette.getVibrantSwatch());
+ mVibrantDarkColor = determineColor(palette.getDarkVibrantSwatch());
+ mVibrantLightColor = determineColor(palette.getLightVibrantSwatch());
+ mDominantColor = determineColor(getDominantSwatch(palette));
+ }
public BitmapColors(int vibrantColor, int vibrantDarkColor) {
mVibrantColor = vibrantColor;
mVibrantDarkColor = vibrantDarkColor;
+ mVibrantLightColor = Color.TRANSPARENT;
+ mDominantColor = vibrantColor;
+ }
+
+ private int determineColor(Palette.Swatch swatch) {
+ return swatch != null ? swatch.getRgb() : Color.TRANSPARENT;
+ }
+
+ private static Palette.Swatch getDominantSwatch(Palette palette) {
+ Palette.Swatch dominant = null;
+ for (Palette.Swatch swatch : palette.getSwatches()) {
+ if (dominant == null || swatch.getPopulation() > dominant.getPopulation()) {
+ dominant = swatch;
+ }
+ }
+ return dominant;
}
}
@@ -70,6 +96,59 @@
return mColors.mVibrantDarkColor;
}
+ public int getContrastingColor() {
+ loadColorsIfNeeded();
+
+ float contrastToDark = computeContrastBetweenColors(mColors.mDominantColor,
+ mColors.mVibrantDarkColor);
+ float contrastToLight = computeContrastBetweenColors(mColors.mDominantColor,
+ mColors.mVibrantLightColor);
+ float contrastToVibrant = computeContrastBetweenColors(mColors.mDominantColor,
+ mColors.mVibrantColor);
+
+ int bestColor = mColors.mDominantColor;
+ float bestContrast = -1;
+ if (contrastToVibrant > bestContrast) {
+ bestColor = mColors.mVibrantColor;
+ bestContrast = contrastToVibrant;
+ }
+ if (contrastToDark > bestContrast) {
+ bestColor = mColors.mVibrantDarkColor;
+ bestContrast = contrastToDark;
+ }
+ if (contrastToLight > bestContrast) {
+ bestColor = mColors.mVibrantLightColor;
+ bestContrast = contrastToLight;
+ }
+
+ return bestColor;
+ }
+
+ /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
+ private static float computeContrastBetweenColors(int bg, int fg) {
+ if (bg == Color.TRANSPARENT || fg == Color.TRANSPARENT || bg == fg) {
+ return -1;
+ }
+
+ float bgR = Color.red(bg) / 255f;
+ float bgG = Color.green(bg) / 255f;
+ float bgB = Color.blue(bg) / 255f;
+ bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
+ bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
+ bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
+ float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
+
+ float fgR = Color.red(fg) / 255f;
+ float fgG = Color.green(fg) / 255f;
+ float fgB = Color.blue(fg) / 255f;
+ fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
+ fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
+ fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
+ float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
+
+ return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
+ }
+
private synchronized void loadColorsIfNeeded() {
if (mColors != null) {
return;
@@ -82,24 +161,17 @@
return;
}
- final Palette p = Palette.generate(mBitmap);
+ final Palette p = Palette.from(mBitmap)
+ .clearTargets()
+ .addTarget(Target.VIBRANT)
+ .addTarget(Target.LIGHT_VIBRANT)
+ .addTarget(Target.DARK_VIBRANT)
+ .generate();
if (p == null) {
return;
}
- int vibrantColor = Color.TRANSPARENT;
- int vibrantDarkColor = Color.TRANSPARENT;
-
- Palette.Swatch swatch = p.getDarkVibrantSwatch();
- if (swatch != null) {
- vibrantDarkColor = swatch.getRgb();
- }
- swatch = p.getVibrantSwatch();
- if (swatch != null) {
- vibrantColor = swatch.getRgb();
- }
-
- mColors = new BitmapColors(vibrantColor, vibrantDarkColor);
+ mColors = new BitmapColors(p);
synchronized (sCachedColors) {
sCachedColors.put(mBitmapKey, mColors);
}