1 /* 2 * Copyright (C) 2014 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.contacts.common.util; 18 19 import com.android.contacts.common.R; 20 21 import android.content.res.Resources; 22 import android.content.res.TypedArray; 23 import android.os.Trace; 24 25 public class MaterialColorMapUtils { 26 27 private final TypedArray sPrimaryColors; 28 private final TypedArray sSecondaryColors; 29 30 public MaterialColorMapUtils(Resources resources) { 31 sPrimaryColors = resources.obtainTypedArray( 32 com.android.contacts.common.R.array.letter_tile_colors); 33 sSecondaryColors = resources.obtainTypedArray( 34 com.android.contacts.common.R.array.letter_tile_colors_dark); 35 } 36 37 public static class MaterialPalette { 38 public MaterialPalette(int primaryColor, int secondaryColor) { 39 mPrimaryColor = primaryColor; 40 mSecondaryColor = secondaryColor; 41 } 42 public final int mPrimaryColor; 43 public final int mSecondaryColor; 44 } 45 46 /** 47 * Return primary and secondary colors from the Material color palette that are similar to 48 * {@param color}. 49 */ 50 public MaterialPalette calculatePrimaryAndSecondaryColor(int color) { 51 Trace.beginSection("calculatePrimaryAndSecondaryColor"); 52 53 final float colorHue = hue(color); 54 float minimumDistance = Float.MAX_VALUE; 55 int indexBestMatch = 0; 56 for (int i = 0; i < sPrimaryColors.length(); i++) { 57 final int primaryColor = sPrimaryColors.getColor(i, 0); 58 final float comparedHue = hue(primaryColor); 59 // No need to be perceptually accurate when calculating color distances since 60 // we are only mapping to 15 colors. Being slightly inaccurate isn't going to change 61 // the mapping very often. 62 final float distance = Math.abs(comparedHue - colorHue); 63 if (distance < minimumDistance) { 64 minimumDistance = distance; 65 indexBestMatch = i; 66 } 67 } 68 69 Trace.endSection(); 70 return new MaterialPalette(sPrimaryColors.getColor(indexBestMatch, 0), 71 sSecondaryColors.getColor(indexBestMatch, 0)); 72 } 73 74 public static MaterialPalette getDefaultPrimaryAndSecondaryColors(Resources resources) { 75 final int primaryColor = resources.getColor( 76 R.color.quickcontact_default_photo_tint_color); 77 final int secondaryColor = resources.getColor( 78 R.color.quickcontact_default_photo_tint_color_dark); 79 return new MaterialPalette(primaryColor, secondaryColor); 80 } 81 82 /** 83 * Returns the hue component of a color int. 84 * 85 * @return A value between 0.0f and 1.0f 86 */ 87 public static float hue(int color) { 88 int r = (color >> 16) & 0xFF; 89 int g = (color >> 8) & 0xFF; 90 int b = color & 0xFF; 91 92 int V = Math.max(b, Math.max(r, g)); 93 int temp = Math.min(b, Math.min(r, g)); 94 95 float H; 96 97 if (V == temp) { 98 H = 0; 99 } else { 100 final float vtemp = V - temp; 101 final float cr = (V - r) / vtemp; 102 final float cg = (V - g) / vtemp; 103 final float cb = (V - b) / vtemp; 104 105 if (r == V) { 106 H = cb - cg; 107 } else if (g == V) { 108 H = 2 + cr - cb; 109 } else { 110 H = 4 + cg - cr; 111 } 112 113 H /= 6.f; 114 if (H < 0) { 115 H++; 116 } 117 } 118 119 return H; 120 } 121 } 122