Home | History | Annotate | Download | only in util
      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.Parcel;
     24 import android.os.Parcelable;
     25 import android.os.Trace;
     26 
     27 public class MaterialColorMapUtils {
     28     private final TypedArray sPrimaryColors;
     29     private final TypedArray sSecondaryColors;
     30 
     31     public MaterialColorMapUtils(Resources resources) {
     32         sPrimaryColors = resources.obtainTypedArray(
     33                 com.android.contacts.common.R.array.letter_tile_colors);
     34         sSecondaryColors = resources.obtainTypedArray(
     35                 com.android.contacts.common.R.array.letter_tile_colors_dark);
     36     }
     37 
     38     public static class MaterialPalette implements Parcelable {
     39         public MaterialPalette(int primaryColor, int secondaryColor) {
     40             mPrimaryColor = primaryColor;
     41             mSecondaryColor = secondaryColor;
     42         }
     43         public final int mPrimaryColor;
     44         public final int mSecondaryColor;
     45 
     46         @Override
     47         public boolean equals(Object obj) {
     48             if (this == obj) {
     49                 return true;
     50             }
     51             if (obj == null) {
     52                 return false;
     53             }
     54             if (getClass() != obj.getClass()) {
     55                 return false;
     56             }
     57             MaterialPalette other = (MaterialPalette) obj;
     58             if (mPrimaryColor != other.mPrimaryColor) {
     59                 return false;
     60             }
     61             if (mSecondaryColor != other.mSecondaryColor) {
     62                 return false;
     63             }
     64             return true;
     65         }
     66 
     67         @Override
     68         public int hashCode() {
     69             final int prime = 31;
     70             int result = 1;
     71             result = prime * result + mPrimaryColor;
     72             result = prime * result + mSecondaryColor;
     73             return result;
     74         }
     75 
     76         @Override
     77         public int describeContents() {
     78             return 0;
     79         }
     80 
     81         @Override
     82         public void writeToParcel(Parcel dest, int flags) {
     83             dest.writeInt(mPrimaryColor);
     84             dest.writeInt(mSecondaryColor);
     85         }
     86 
     87         private MaterialPalette(Parcel in) {
     88             mPrimaryColor = in.readInt();
     89             mSecondaryColor = in.readInt();
     90         }
     91 
     92         public static final Creator<MaterialPalette> CREATOR = new Creator<MaterialPalette>() {
     93                 @Override
     94                 public MaterialPalette createFromParcel(Parcel in) {
     95                     return new MaterialPalette(in);
     96                 }
     97 
     98                 @Override
     99                 public MaterialPalette[] newArray(int size) {
    100                     return new MaterialPalette[size];
    101                 }
    102         };
    103     }
    104 
    105     /**
    106      * Return primary and secondary colors from the Material color palette that are similar to
    107      * {@param color}.
    108      */
    109     public MaterialPalette calculatePrimaryAndSecondaryColor(int color) {
    110         Trace.beginSection("calculatePrimaryAndSecondaryColor");
    111 
    112         final float colorHue = hue(color);
    113         float minimumDistance = Float.MAX_VALUE;
    114         int indexBestMatch = 0;
    115         for (int i = 0; i < sPrimaryColors.length(); i++) {
    116             final int primaryColor = sPrimaryColors.getColor(i, 0);
    117             final float comparedHue = hue(primaryColor);
    118             // No need to be perceptually accurate when calculating color distances since
    119             // we are only mapping to 15 colors. Being slightly inaccurate isn't going to change
    120             // the mapping very often.
    121             final float distance = Math.abs(comparedHue - colorHue);
    122             if (distance < minimumDistance) {
    123                 minimumDistance = distance;
    124                 indexBestMatch = i;
    125             }
    126         }
    127 
    128         Trace.endSection();
    129         return new MaterialPalette(sPrimaryColors.getColor(indexBestMatch, 0),
    130                 sSecondaryColors.getColor(indexBestMatch, 0));
    131     }
    132 
    133     public static MaterialPalette getDefaultPrimaryAndSecondaryColors(Resources resources) {
    134         final int primaryColor = resources.getColor(
    135                 R.color.quickcontact_default_photo_tint_color);
    136         final int secondaryColor = resources.getColor(
    137                 R.color.quickcontact_default_photo_tint_color_dark);
    138         return new MaterialPalette(primaryColor, secondaryColor);
    139     }
    140 
    141     /**
    142      * Returns the hue component of a color int.
    143      *
    144      * @return A value between 0.0f and 1.0f
    145      */
    146     public static float hue(int color) {
    147         int r = (color >> 16) & 0xFF;
    148         int g = (color >> 8) & 0xFF;
    149         int b = color & 0xFF;
    150 
    151         int V = Math.max(b, Math.max(r, g));
    152         int temp = Math.min(b, Math.min(r, g));
    153 
    154         float H;
    155 
    156         if (V == temp) {
    157             H = 0;
    158         } else {
    159             final float vtemp = V - temp;
    160             final float cr = (V - r) / vtemp;
    161             final float cg = (V - g) / vtemp;
    162             final float cb = (V - b) / vtemp;
    163 
    164             if (r == V) {
    165                 H = cb - cg;
    166             } else if (g == V) {
    167                 H = 2 + cr - cb;
    168             } else {
    169                 H = 4 + cg - cr;
    170             }
    171 
    172             H /= 6.f;
    173             if (H < 0) {
    174                 H++;
    175             }
    176         }
    177 
    178         return H;
    179     }
    180 }
    181