1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package android.support.v17.leanback.graphics;
15
16import android.content.Context;
17import android.content.res.TypedArray;
18import android.graphics.ColorFilter;
19import android.graphics.Paint;
20import android.view.View;
21import android.support.v17.leanback.R;
22
23/**
24 * Helper class for applying a dim level to a View.  The ColorFilterDimmer
25 * uses a ColorFilter in a Paint object to dim the view according to the
26 * currently active level.
27 */
28public final class ColorFilterDimmer {
29
30    private final ColorFilterCache mColorDimmer;
31
32    private final float mActiveLevel;
33    private final float mDimmedLevel;
34
35    private final Paint mPaint;
36    private ColorFilter mFilter;
37
38    /**
39     * Creates a default ColorFilterDimmer. Uses the default color and level for
40     * the dimmer.
41     *
42     * @param context A Context used to retrieve Resources.
43     * @return A ColorFilterDimmer with the default dim color and levels.
44     */
45    public static ColorFilterDimmer createDefault(Context context) {
46        TypedArray a = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
47
48        int dimColor = a.getColor(R.styleable.LeanbackTheme_overlayDimMaskColor,
49                context.getResources().getColor(R.color.lb_view_dim_mask_color));
50        float activeLevel = a.getFraction(R.styleable.LeanbackTheme_overlayDimActiveLevel, 1, 1,
51                context.getResources().getFraction(R.fraction.lb_view_active_level, 1, 0));
52        float dimmedLevel = a.getFraction(R.styleable.LeanbackTheme_overlayDimDimmedLevel, 1, 1,
53                context.getResources().getFraction(R.fraction.lb_view_dimmed_level, 1, 1));
54        a.recycle();
55        return new ColorFilterDimmer(ColorFilterCache.getColorFilterCache(
56                    dimColor), activeLevel, dimmedLevel);
57    }
58
59    /**
60     * Creates a ColorFilterDimmer for the given color and levels..
61     *
62     * @param dimmer      The ColorFilterCache for dim color.
63     * @param activeLevel The level of dimming when the View is in its active
64     *                    state. Must be a float value between 0.0 and 1.0.
65     * @param dimmedLevel The level of dimming when the View is in its dimmed
66     *                    state. Must be a float value between 0.0 and 1.0.
67     */
68    public static ColorFilterDimmer create(ColorFilterCache dimmer,
69            float activeLevel, float dimmedLevel) {
70        return new ColorFilterDimmer(dimmer, activeLevel, dimmedLevel);
71    }
72
73    private ColorFilterDimmer(ColorFilterCache dimmer, float activeLevel, float dimmedLevel) {
74        mColorDimmer = dimmer;
75        if (activeLevel > 1.0f) activeLevel = 1.0f;
76        if (activeLevel < 0.0f) activeLevel = 0.0f;
77        if (dimmedLevel > 1.0f) dimmedLevel = 1.0f;
78        if (dimmedLevel < 0.0f) dimmedLevel = 0.0f;
79        mActiveLevel = activeLevel;
80        mDimmedLevel = dimmedLevel;
81        mPaint = new Paint();
82    }
83
84    /**
85     * Apply current the ColorFilter to a View. This method will set the
86     * hardware layer of the view when applying a filter, and remove it when not
87     * applying a filter.
88     *
89     * @param view The View to apply the ColorFilter to.
90     */
91    public void applyFilterToView(View view) {
92        if (mFilter != null) {
93            view.setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
94        } else {
95            view.setLayerType(View.LAYER_TYPE_NONE, null);
96        }
97        // FIXME: Current framework has bug that not triggering invalidate when change layer
98        // paint.  Will add conditional sdk version check once bug is fixed in released
99        // framework.
100        view.invalidate();
101    }
102
103    /**
104     * Sets the active level of the dimmer. Updates the ColorFilter based on the
105     * level.
106     *
107     * @param level A float between 0 (fully dim) and 1 (fully active).
108     */
109    public void setActiveLevel(float level) {
110        if (level < 0.0f) level = 0.0f;
111        if (level > 1.0f) level = 1.0f;
112        mFilter = mColorDimmer.getFilterForLevel(
113                mDimmedLevel + level * (mActiveLevel - mDimmedLevel));
114        mPaint.setColorFilter(mFilter);
115    }
116
117    /**
118     * Gets the ColorFilter set to the current dim level.
119     *
120     * @return The current ColorFilter.
121     */
122    public ColorFilter getColorFilter() {
123        return mFilter;
124    }
125
126    /**
127     * Gets the Paint object set to the current dim level.
128     *
129     * @return The current Paint object.
130     */
131    public Paint getPaint() {
132        return mPaint;
133    }
134}
135