• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.launcher2;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.Bitmap.Config;
22 import android.graphics.Canvas;
23 import android.graphics.Paint;
24 import android.graphics.PorterDuff.Mode;
25 import android.graphics.drawable.Drawable;
26 import android.text.Layout;
27 import android.util.AttributeSet;
28 import android.widget.TextView;
29 
30 /*
31  * This class is a bit of a hack, designed to speed up long text labels in Launcher. It caches the
32  * text in a TextView to a bitmap and then just draws that Bitmap instead afterward, speeding up
33  * rendering. Marquee scrolling is not currently supported.
34  *
35  */
36 public class CachedTextView extends TextView {
37     private Bitmap mCache;
38     private final Paint mCachePaint = new Paint();
39     private final Canvas mCacheCanvas = new Canvas();
40 
41     private int mPrevAlpha = -1;
42     private boolean mIsBuildingCache;
43     boolean mIsTextCacheDirty;
44     float mTextCacheLeft;
45     float mTextCacheTop;
46     float mTextCacheScrollX;
47     float mRectLeft, mRectTop;
48     private float mPaddingH = 0;
49     private float mPaddingV = 0;
50     private CharSequence mText;
51     private boolean mEnabled = true;
52 
CachedTextView(Context context)53     public CachedTextView(Context context) {
54         super(context);
55     }
56 
CachedTextView(Context context, AttributeSet attrs)57     public CachedTextView(Context context, AttributeSet attrs) {
58         super(context, attrs);
59     }
60 
CachedTextView(Context context, AttributeSet attrs, int defStyle)61     public CachedTextView(Context context, AttributeSet attrs, int defStyle) {
62         super(context, attrs, defStyle);
63     }
64 
getCacheTopPadding()65     protected int getCacheTopPadding() {
66         return 0;
67     }
getCacheLeftPadding()68     protected int getCacheLeftPadding() {
69         return 0;
70     }
getCacheRightPadding()71     protected int getCacheRightPadding() {
72         return 0;
73     }
getCacheBottomPadding()74     protected int getCacheBottomPadding() {
75         return 0;
76     }
77 
disableCache()78     public void disableCache() {
79         mEnabled = false;
80     }
81 
setText(CharSequence text, BufferType type)82     public void setText(CharSequence text, BufferType type) {
83         super.setText(text, type);
84         mIsTextCacheDirty = true;
85     }
86 
buildAndUpdateCache()87     private void buildAndUpdateCache() {
88         final Layout layout = getLayout();
89         final int left = getCompoundPaddingLeft();
90         final int top = getExtendedPaddingTop();
91         final float prevAlpha = getAlpha();
92 
93         mTextCacheLeft = layout.getLineLeft(0) - getCacheLeftPadding();
94         mTextCacheTop = top + layout.getLineTop(0) - mPaddingV - getCacheTopPadding();
95 
96         mRectLeft = mScrollX + getLeft();
97         mRectTop = 0;
98         mTextCacheScrollX = mScrollX;
99 
100         final float textCacheRight =
101             Math.min(left + layout.getLineRight(0) + mPaddingH, mScrollX + mRight - mLeft) +
102             getCacheRightPadding();
103         final float textCacheBottom = top + layout.getLineBottom(0) + mPaddingV +
104             getCacheBottomPadding();
105         final float xCharWidth = getPaint().measureText("x");
106 
107         int width = (int) (textCacheRight - mTextCacheLeft + (2 * xCharWidth));
108         int height = (int) (textCacheBottom - mTextCacheTop);
109 
110         if (width > 0 && height > 0) {
111             if (mCache != null) {
112                 if (mCache.getWidth() != width || mCache.getHeight() != height) {
113                     mCache.recycle();
114                     mCache = null;
115                 }
116             }
117             if (mCache == null) {
118                 mCache = Bitmap.createBitmap(width, height, Config.ARGB_8888);
119                 mCacheCanvas.setBitmap(mCache);
120             } else {
121                 mCacheCanvas.drawColor(0, Mode.CLEAR);
122             }
123 
124             mCacheCanvas.save();
125             mCacheCanvas.translate(-mTextCacheLeft, -mTextCacheTop);
126 
127             mIsBuildingCache = true;
128             setAlpha(1.0f);
129             draw(mCacheCanvas);
130             setAlpha(prevAlpha);
131             mIsBuildingCache = false;
132             mCacheCanvas.restore();
133             mCacheCanvas.setBitmap(null);
134 
135             // A hack-- we set the text to be one space (we don't make it empty just to avoid any
136             // potential issues with text measurement, like line height, etc.) so that the text view
137             // doesn't draw it anymore, since it's been cached.
138             mText = getText();
139             setText(" ");
140         }
141     }
142 
getText()143     public CharSequence getText() {
144         return (mText == null) ? super.getText() : mText;
145     }
146 
draw(Canvas canvas)147     public void draw(Canvas canvas) {
148         if (mEnabled && mIsTextCacheDirty && !mIsBuildingCache) {
149             buildAndUpdateCache();
150             mIsTextCacheDirty = false;
151         }
152         if (mCache != null && !mIsBuildingCache) {
153             canvas.drawBitmap(mCache, mTextCacheLeft - mTextCacheScrollX + mScrollX,
154                     mTextCacheTop, mCachePaint);
155         }
156         super.draw(canvas);
157     }
158 
isBuildingCache()159     protected boolean isBuildingCache() {
160         return mIsBuildingCache;
161     }
162 
163     @Override
onSetAlpha(int alpha)164     protected boolean onSetAlpha(int alpha) {
165         if (mPrevAlpha != alpha) {
166             mPrevAlpha = alpha;
167             mCachePaint.setAlpha(alpha);
168 
169             // We manually update the drawables alpha since the default TextView implementation may
170             // not do this if there is a background set (which we may due to the focus bg)
171             final Drawable[] dr = getCompoundDrawables();
172             for (int i = 0; i < dr.length; ++i) {
173                 if (dr[i] != null) {
174                     dr[i].mutate().setAlpha(alpha);
175                 }
176             }
177 
178             super.onSetAlpha(alpha);
179         }
180         return true;
181     }
182 }
183