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