PagedViewIcon.java revision 4dbea7920a5f52df1d35009352f7e5cba16c05fb
1/*
2 * Copyright (C) 2010 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
17package com.android.launcher2;
18
19import com.android.launcher.R;
20
21import android.animation.ObjectAnimator;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.pm.PackageManager;
25import android.content.pm.ResolveInfo;
26import android.content.res.Resources;
27import android.content.res.TypedArray;
28import android.graphics.Bitmap;
29import android.graphics.Canvas;
30import android.graphics.Paint;
31import android.os.Handler;
32import android.os.HandlerThread;
33import android.os.Message;
34import android.util.AttributeSet;
35import android.view.KeyEvent;
36import android.widget.Checkable;
37import android.widget.TextView;
38
39
40
41/**
42 * An icon on a PagedView, specifically for items in the launcher's paged view (with compound
43 * drawables on the top).
44 */
45public class PagedViewIcon extends CachedTextView implements Checkable {
46    private static final String TAG = "PagedViewIcon";
47
48    // holographic outline
49    private final Paint mPaint = new Paint();
50    private static HolographicOutlineHelper sHolographicOutlineHelper;
51    private Bitmap mCheckedOutline;
52    private Bitmap mHolographicOutline;
53    private Bitmap mIcon;
54
55    private PagedViewIconCache.Key mIconCacheKey;
56    private PagedViewIconCache mIconCache;
57
58    private int mAlpha = 255;
59    private int mHolographicAlpha;
60
61    private boolean mHolographicEffectsEnabled;
62    private boolean mIsChecked;
63    private ObjectAnimator mCheckedAlphaAnimator;
64    private float mCheckedAlpha = 1.0f;
65    private int mCheckedFadeInDuration;
66    private int mCheckedFadeOutDuration;
67
68    // Highlight colors
69    private int mHoloBlurColor;
70    private int mHoloOutlineColor;
71
72    HolographicPagedViewIcon mHolographicOutlineView;
73
74    private static final HandlerThread sWorkerThread = new HandlerThread("pagedviewicon-helper");
75    static {
76        sWorkerThread.start();
77    }
78
79    private static final int MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE = 1;
80
81    private static final Handler sWorker = new Handler(sWorkerThread.getLooper()) {
82        private DeferredHandler mHandler = new DeferredHandler();
83        private Paint mPaint = new Paint();
84        public void handleMessage(Message msg) {
85            final PagedViewIcon icon = (PagedViewIcon) msg.obj;
86
87            final Bitmap holographicOutline = Bitmap.createBitmap(
88                    icon.mIcon.getWidth(), icon.mIcon.getHeight(), Bitmap.Config.ARGB_8888);
89            Canvas holographicOutlineCanvas = new Canvas(holographicOutline);
90            holographicOutlineCanvas.drawBitmap(icon.mIcon, 0, 0, mPaint);
91
92            sHolographicOutlineHelper.applyThickExpensiveOutlineWithBlur(holographicOutline,
93                    holographicOutlineCanvas, icon.mHoloBlurColor, icon.mHoloOutlineColor);
94
95            mHandler.post(new Runnable() {
96                public void run() {
97                    icon.mHolographicOutline = holographicOutline;
98                    icon.mIconCache.addOutline(icon.mIconCacheKey, holographicOutline);
99                    icon.getHolographicOutlineView().invalidate();
100                }
101            });
102        }
103    };
104
105    public PagedViewIcon(Context context) {
106        this(context, null);
107    }
108
109    public PagedViewIcon(Context context, AttributeSet attrs) {
110        this(context, attrs, 0);
111    }
112
113    public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) {
114        super(context, attrs, defStyle);
115
116        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedViewIcon, defStyle, 0);
117        mHoloBlurColor = a.getColor(R.styleable.PagedViewIcon_blurColor, 0);
118        mHoloOutlineColor = a.getColor(R.styleable.PagedViewIcon_outlineColor, 0);
119        a.recycle();
120
121        if (sHolographicOutlineHelper == null) {
122            sHolographicOutlineHelper = new HolographicOutlineHelper();
123        }
124
125        // Set up fade in/out constants
126        final Resources r = context.getResources();
127        final int alpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha);
128        if (alpha > 0) {
129            mCheckedAlpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha) / 256.0f;
130            mCheckedFadeInDuration =
131                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeInDuration);
132            mCheckedFadeOutDuration =
133                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeOutDuration);
134        }
135
136        mHolographicOutlineView = new HolographicPagedViewIcon(context, this);
137        mHolographicEffectsEnabled = isHardwareAccelerated();
138    }
139
140    protected HolographicPagedViewIcon getHolographicOutlineView() {
141        return mHolographicOutlineView;
142    }
143
144    protected Bitmap getHolographicOutline() {
145        return mHolographicOutline;
146    }
147
148    private boolean queueHolographicOutlineCreation() {
149        // Generate the outline in the background
150        if (mHolographicOutline == null) {
151            Message m = sWorker.obtainMessage(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE);
152            m.obj = this;
153            sWorker.sendMessage(m);
154            return true;
155        }
156        return false;
157    }
158
159    public void applyFromApplicationInfo(ApplicationInfo info, PagedViewIconCache cache,
160            boolean scaleUp, boolean createHolographicOutlines) {
161        mIcon = info.iconBitmap;
162        setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
163        setText(info.title);
164        setTag(info);
165
166        if (createHolographicOutlines) {
167            mIconCache = cache;
168            mIconCacheKey = new PagedViewIconCache.Key(info);
169            mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
170            if (mHolographicEffectsEnabled && !queueHolographicOutlineCreation()) {
171                getHolographicOutlineView().invalidate();
172            }
173        }
174    }
175
176    public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
177            PagedViewIconCache cache, IconCache modelIconCache, boolean createHolographicOutlines) {
178        ComponentName cn = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
179        mIcon = modelIconCache.getIcon(cn, info);
180        setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
181        setText(info.loadLabel(packageManager));
182        setTag(info);
183
184        if (createHolographicOutlines) {
185            mIconCache = cache;
186            mIconCacheKey = new PagedViewIconCache.Key(info);
187            mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
188            if (mHolographicEffectsEnabled && !queueHolographicOutlineCreation()) {
189                getHolographicOutlineView().invalidate();
190            }
191        }
192    }
193
194    @Override
195    public void setAlpha(float alpha) {
196        final float viewAlpha = sHolographicOutlineHelper.viewAlphaInterpolator(alpha);
197        final float holographicAlpha = sHolographicOutlineHelper.highlightAlphaInterpolator(alpha);
198        int newViewAlpha = (int) (viewAlpha * 255);
199        int newHolographicAlpha = (int) (holographicAlpha * 255);
200        if ((mAlpha != newViewAlpha) || (mHolographicAlpha != newHolographicAlpha)) {
201            mAlpha = newViewAlpha;
202            mHolographicAlpha = newHolographicAlpha;
203            super.setAlpha(viewAlpha);
204        }
205    }
206
207    public void invalidateCheckedImage() {
208        if (mCheckedOutline != null) {
209            mCheckedOutline.recycle();
210            mCheckedOutline = null;
211        }
212    }
213
214    @Override
215    protected void onDraw(Canvas canvas) {
216        if (mAlpha > 0) {
217            super.onDraw(canvas);
218        }
219
220        Bitmap overlay = null;
221
222        // draw any blended overlays
223        if (mCheckedOutline == null) {
224            if (mHolographicEffectsEnabled && mHolographicOutline != null
225                    && mHolographicAlpha > 0) {
226                mPaint.setAlpha(mHolographicAlpha);
227                overlay = mHolographicOutline;
228            }
229        } else {
230            mPaint.setAlpha(255);
231            overlay = mCheckedOutline;
232        }
233
234        if (overlay != null) {
235            final int offset = getScrollX();
236            final int compoundPaddingLeft = getCompoundPaddingLeft();
237            final int compoundPaddingRight = getCompoundPaddingRight();
238            int hspace = getWidth() - compoundPaddingRight - compoundPaddingLeft;
239            canvas.drawBitmap(overlay,
240                    offset + compoundPaddingLeft + (hspace - overlay.getWidth()) / 2,
241                    mPaddingTop,
242                    mPaint);
243        }
244    }
245
246    @Override
247    public void onDetachedFromWindow() {
248        super.onDetachedFromWindow();
249        sWorker.removeMessages(MESSAGE_CREATE_HOLOGRAPHIC_OUTLINE, this);
250    }
251
252    @Override
253    public boolean onKeyDown(int keyCode, KeyEvent event) {
254        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
255                || super.onKeyDown(keyCode, event);
256    }
257
258    @Override
259    public boolean onKeyUp(int keyCode, KeyEvent event) {
260        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
261                || super.onKeyUp(keyCode, event);
262    }
263
264    @Override
265    public boolean isChecked() {
266        return mIsChecked;
267    }
268
269    void setChecked(boolean checked, boolean animate) {
270        if (mIsChecked != checked) {
271            mIsChecked = checked;
272
273            float alpha;
274            int duration;
275            if (mIsChecked) {
276                alpha = mCheckedAlpha;
277                duration = mCheckedFadeInDuration;
278            } else {
279                alpha = 1.0f;
280                duration = mCheckedFadeOutDuration;
281            }
282
283            // Initialize the animator
284            if (mCheckedAlphaAnimator != null) {
285                mCheckedAlphaAnimator.cancel();
286            }
287            if (animate) {
288                mCheckedAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", getAlpha(), alpha);
289                mCheckedAlphaAnimator.setDuration(duration);
290                mCheckedAlphaAnimator.start();
291            } else {
292                setAlpha(alpha);
293            }
294
295            invalidate();
296        }
297    }
298
299    @Override
300    public void setChecked(boolean checked) {
301        setChecked(checked, true);
302    }
303
304    @Override
305    public void toggle() {
306        setChecked(!mIsChecked);
307    }
308}
309