• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.launcher3;
18 
19 import android.animation.ObjectAnimator;
20 import android.animation.TimeInterpolator;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Color;
24 import android.graphics.ColorFilter;
25 import android.graphics.ColorMatrix;
26 import android.graphics.ColorMatrixColorFilter;
27 import android.graphics.Paint;
28 import android.graphics.PixelFormat;
29 import android.graphics.PorterDuff;
30 import android.graphics.PorterDuffColorFilter;
31 import android.graphics.Rect;
32 import android.graphics.drawable.Drawable;
33 import android.util.SparseArray;
34 
35 public class FastBitmapDrawable extends Drawable {
36 
37     static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
38 
39         @Override
40         public float getInterpolation(float input) {
41             if (input < 0.05f) {
42                 return input / 0.05f;
43             } else if (input < 0.3f){
44                 return 1;
45             } else {
46                 return (1 - input) / 0.7f;
47             }
48         }
49     };
50     static final long CLICK_FEEDBACK_DURATION = 2000;
51 
52     private static final int PRESSED_BRIGHTNESS = 100;
53     private static ColorMatrix sGhostModeMatrix;
54     private static final ColorMatrix sTempMatrix = new ColorMatrix();
55 
56     /**
57      * Store the brightness colors filters to optimize animations during icon press. This
58      * only works for non-ghost-mode icons.
59      */
60     private static final SparseArray<ColorFilter> sCachedBrightnessFilter =
61             new SparseArray<ColorFilter>();
62 
63     private static final int GHOST_MODE_MIN_COLOR_RANGE = 130;
64 
65     private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
66     private final Bitmap mBitmap;
67     private int mAlpha;
68 
69     private int mBrightness = 0;
70     private boolean mGhostModeEnabled = false;
71 
72     private boolean mPressed = false;
73     private ObjectAnimator mPressedAnimator;
74 
FastBitmapDrawable(Bitmap b)75     public FastBitmapDrawable(Bitmap b) {
76         mAlpha = 255;
77         mBitmap = b;
78         setBounds(0, 0, b.getWidth(), b.getHeight());
79     }
80 
81     @Override
draw(Canvas canvas)82     public void draw(Canvas canvas) {
83         final Rect r = getBounds();
84         // Draw the bitmap into the bounding rect
85         canvas.drawBitmap(mBitmap, null, r, mPaint);
86     }
87 
88     @Override
setColorFilter(ColorFilter cf)89     public void setColorFilter(ColorFilter cf) {
90         // No op
91     }
92 
93     @Override
getOpacity()94     public int getOpacity() {
95         return PixelFormat.TRANSLUCENT;
96     }
97 
98     @Override
setAlpha(int alpha)99     public void setAlpha(int alpha) {
100         mAlpha = alpha;
101         mPaint.setAlpha(alpha);
102     }
103 
104     @Override
setFilterBitmap(boolean filterBitmap)105     public void setFilterBitmap(boolean filterBitmap) {
106         mPaint.setFilterBitmap(filterBitmap);
107         mPaint.setAntiAlias(filterBitmap);
108     }
109 
getAlpha()110     public int getAlpha() {
111         return mAlpha;
112     }
113 
114     @Override
getIntrinsicWidth()115     public int getIntrinsicWidth() {
116         return mBitmap.getWidth();
117     }
118 
119     @Override
getIntrinsicHeight()120     public int getIntrinsicHeight() {
121         return mBitmap.getHeight();
122     }
123 
124     @Override
getMinimumWidth()125     public int getMinimumWidth() {
126         return getBounds().width();
127     }
128 
129     @Override
getMinimumHeight()130     public int getMinimumHeight() {
131         return getBounds().height();
132     }
133 
getBitmap()134     public Bitmap getBitmap() {
135         return mBitmap;
136     }
137 
138     /**
139      * When enabled, the icon is grayed out and the contrast is increased to give it a 'ghost'
140      * appearance.
141      */
setGhostModeEnabled(boolean enabled)142     public void setGhostModeEnabled(boolean enabled) {
143         if (mGhostModeEnabled != enabled) {
144             mGhostModeEnabled = enabled;
145             updateFilter();
146         }
147     }
148 
setPressed(boolean pressed)149     public void setPressed(boolean pressed) {
150         if (mPressed != pressed) {
151             mPressed = pressed;
152             if (mPressed) {
153                 mPressedAnimator = ObjectAnimator
154                         .ofInt(this, "brightness", PRESSED_BRIGHTNESS)
155                         .setDuration(CLICK_FEEDBACK_DURATION);
156                 mPressedAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
157                 mPressedAnimator.start();
158             } else if (mPressedAnimator != null) {
159                 mPressedAnimator.cancel();
160                 setBrightness(0);
161             }
162         }
163         invalidateSelf();
164     }
165 
isGhostModeEnabled()166     public boolean isGhostModeEnabled() {
167         return mGhostModeEnabled;
168     }
169 
getBrightness()170     public int getBrightness() {
171         return mBrightness;
172     }
173 
setBrightness(int brightness)174     public void setBrightness(int brightness) {
175         if (mBrightness != brightness) {
176             mBrightness = brightness;
177             updateFilter();
178             invalidateSelf();
179         }
180     }
181 
updateFilter()182     private void updateFilter() {
183         if (mGhostModeEnabled) {
184             if (sGhostModeMatrix == null) {
185                 sGhostModeMatrix = new ColorMatrix();
186                 sGhostModeMatrix.setSaturation(0);
187 
188                 // For ghost mode, set the color range to [GHOST_MODE_MIN_COLOR_RANGE, 255]
189                 float range = (255 - GHOST_MODE_MIN_COLOR_RANGE) / 255.0f;
190                 sTempMatrix.set(new float[] {
191                         range, 0, 0, 0, GHOST_MODE_MIN_COLOR_RANGE,
192                         0, range, 0, 0, GHOST_MODE_MIN_COLOR_RANGE,
193                         0, 0, range, 0, GHOST_MODE_MIN_COLOR_RANGE,
194                         0, 0, 0, 1, 0 });
195                 sGhostModeMatrix.preConcat(sTempMatrix);
196             }
197 
198             if (mBrightness == 0) {
199                 mPaint.setColorFilter(new ColorMatrixColorFilter(sGhostModeMatrix));
200             } else {
201                 setBrightnessMatrix(sTempMatrix, mBrightness);
202                 sTempMatrix.postConcat(sGhostModeMatrix);
203                 mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix));
204             }
205         } else if (mBrightness != 0) {
206             ColorFilter filter = sCachedBrightnessFilter.get(mBrightness);
207             if (filter == null) {
208                 filter = new PorterDuffColorFilter(Color.argb(mBrightness, 255, 255, 255),
209                         PorterDuff.Mode.SRC_ATOP);
210                 sCachedBrightnessFilter.put(mBrightness, filter);
211             }
212             mPaint.setColorFilter(filter);
213         } else {
214             mPaint.setColorFilter(null);
215         }
216     }
217 
setBrightnessMatrix(ColorMatrix matrix, int brightness)218     private static void setBrightnessMatrix(ColorMatrix matrix, int brightness) {
219         // Brightness: C-new = C-old*(1-amount) + amount
220         float scale = 1 - brightness / 255.0f;
221         matrix.setScale(scale, scale, scale, 1);
222         float[] array = matrix.getArray();
223 
224         // Add the amount to RGB components of the matrix, as per the above formula.
225         // Fifth elements in the array correspond to the constant being added to
226         // red, blue, green, and alpha channel respectively.
227         array[4] = brightness;
228         array[9] = brightness;
229         array[14] = brightness;
230     }
231 }
232