1528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell/*
2528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * Copyright (C) 2014 The Android Open Source Project
3528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell *
4528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * Licensed under the Apache License, Version 2.0 (the "License");
5528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * you may not use this file except in compliance with the License.
6528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * You may obtain a copy of the License at
7528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell *
8528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell *      http://www.apache.org/licenses/LICENSE-2.0
9528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell *
10528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * Unless required by applicable law or agreed to in writing, software
11528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * distributed under the License is distributed on an "AS IS" BASIS,
12528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * See the License for the specific language governing permissions and
14528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell * limitations under the License.
15528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell */
16528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
17528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwellpackage com.android.contacts.common.util;
18528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
19d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwellimport com.android.contacts.common.R;
20d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell
21d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwellimport android.content.res.Resources;
22d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwellimport android.content.res.TypedArray;
23528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwellimport android.os.Trace;
24528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
25528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwellpublic class MaterialColorMapUtils {
26528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
27d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    private final TypedArray sPrimaryColors;
28d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    private final TypedArray sSecondaryColors;
29528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
30d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    public MaterialColorMapUtils(Resources resources) {
31d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        sPrimaryColors = resources.obtainTypedArray(
32d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell                com.android.contacts.common.R.array.letter_tile_colors);
33d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        sSecondaryColors = resources.obtainTypedArray(
34d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell                com.android.contacts.common.R.array.letter_tile_colors_dark);
35d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    }
36528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
37528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell    public static class MaterialPalette {
38528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        public MaterialPalette(int primaryColor, int secondaryColor) {
39528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            mPrimaryColor = primaryColor;
40528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            mSecondaryColor = secondaryColor;
41528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        }
42528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        public final int mPrimaryColor;
43528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        public final int mSecondaryColor;
44528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell    }
45528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
46528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell    /**
47d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell     * Return primary and secondary colors from the Material color palette that are similar to
48d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell     * {@param color}.
49528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell     */
50d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    public MaterialPalette calculatePrimaryAndSecondaryColor(int color) {
51528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        Trace.beginSection("calculatePrimaryAndSecondaryColor");
52528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
53d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        final float colorHue = hue(color);
54528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        float minimumDistance = Float.MAX_VALUE;
55528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        int indexBestMatch = 0;
56d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        for (int i = 0; i < sPrimaryColors.length(); i++) {
57d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell            final int primaryColor = sPrimaryColors.getColor(i, 0);
58d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell            final float comparedHue = hue(primaryColor);
59528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            // No need to be perceptually accurate when calculating color distances since
60528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            // we are only mapping to 15 colors. Being slightly inaccurate isn't going to change
61528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            // the mapping very often.
62528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            final float distance = Math.abs(comparedHue - colorHue);
63528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            if (distance < minimumDistance) {
64528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell                minimumDistance = distance;
65528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell                indexBestMatch = i;
66528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell            }
67528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        }
68528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
69528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell        Trace.endSection();
70d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        return new MaterialPalette(sPrimaryColors.getColor(indexBestMatch, 0),
71d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell                sSecondaryColors.getColor(indexBestMatch, 0));
72528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell    }
73528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
74d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell    public static MaterialPalette getDefaultPrimaryAndSecondaryColors(Resources resources) {
75d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        final int primaryColor = resources.getColor(
76d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell                R.color.quickcontact_default_photo_tint_color);
77d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        final int secondaryColor = resources.getColor(
78d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell                R.color.quickcontact_default_photo_tint_color_dark);
79d4d290d39d14e17683ec86b07a150c9df35505aeBrian Attwell        return new MaterialPalette(primaryColor, secondaryColor);
80528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell    }
81528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell
82d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee    /**
83d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee     * Returns the hue component of a color int.
84d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee     *
85d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee     * @return A value between 0.0f and 1.0f
86d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee     */
87d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee    public static float hue(int color) {
88d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        int r = (color >> 16) & 0xFF;
89d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        int g = (color >> 8) & 0xFF;
90d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        int b = color & 0xFF;
91d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
92d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        int V = Math.max(b, Math.max(r, g));
93d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        int temp = Math.min(b, Math.min(r, g));
94d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
95d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        float H;
96d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
97d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        if (V == temp) {
98d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            H = 0;
99d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        } else {
100d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            final float vtemp = V - temp;
101d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            final float cr = (V - r) / vtemp;
102d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            final float cg = (V - g) / vtemp;
103d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            final float cb = (V - b) / vtemp;
104d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
105d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            if (r == V) {
106d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee                H = cb - cg;
107d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            } else if (g == V) {
108d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee                H = 2 + cr - cb;
109d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            } else {
110d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee                H = 4 + cg - cr;
111d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            }
112d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
113d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            H /= 6.f;
114d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            if (H < 0) {
115d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee                H++;
116d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee            }
117d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        }
118d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee
119d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee        return H;
120d585ac1c9ea385751b69897a9efb907655296f66Yorke Lee    }
121528cb5eae10cc221cdc989035b0dc5e21f09684bBrian Attwell}
122