blob: 8ab22ebc8bb7559c96048037cfe6cd46991c312e [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
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
Joe Onoratoa5902522009-07-30 13:37:37 -070017package com.android.launcher2;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Winson Chungaafa03c2010-06-11 17:34:16 -070019import android.content.Context;
20import android.content.res.Resources;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080021import android.graphics.Bitmap;
Joe Onorato1291a8c2009-09-15 15:07:25 -040022import android.graphics.BlurMaskFilter;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080023import android.graphics.Canvas;
Joe Onorato56d82912010-03-07 14:32:10 -050024import android.graphics.ColorMatrix;
25import android.graphics.ColorMatrixColorFilter;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080026import android.graphics.Paint;
Joe Onoratobf15cb42009-08-07 14:33:40 -070027import android.graphics.PaintFlagsDrawFilter;
Joe Onorato1291a8c2009-09-15 15:07:25 -040028import android.graphics.PorterDuff;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080029import android.graphics.Rect;
Joe Onoratobf15cb42009-08-07 14:33:40 -070030import android.graphics.RectF;
Mike Reedcdd11792009-10-29 17:27:55 -040031import android.graphics.TableMaskFilter;
Joe Onoratobf15cb42009-08-07 14:33:40 -070032import android.graphics.Typeface;
Winson Chungaafa03c2010-06-11 17:34:16 -070033import android.graphics.drawable.BitmapDrawable;
34import android.graphics.drawable.Drawable;
35import android.graphics.drawable.PaintDrawable;
Joe Onoratobf15cb42009-08-07 14:33:40 -070036import android.text.StaticLayout;
37import android.text.TextPaint;
Winson Chungaafa03c2010-06-11 17:34:16 -070038import android.text.Layout.Alignment;
Dianne Hackborn32ce7f12009-07-22 21:56:50 -070039import android.util.DisplayMetrics;
Joe Onoratobf15cb42009-08-07 14:33:40 -070040import android.util.Log;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080041
Romain Guyedcce092010-03-04 13:03:17 -080042import com.android.launcher.R;
43
The Android Open Source Project31dd5032009-03-03 19:32:27 -080044/**
45 * Various utilities shared amongst the Launcher's classes.
46 */
47final class Utilities {
Joe Onorato1291a8c2009-09-15 15:07:25 -040048 private static final String TAG = "Launcher.Utilities";
49
Joe Onorato9392a752009-09-15 17:13:09 -040050 private static final boolean TEXT_BURN = false;
51
The Android Open Source Project31dd5032009-03-03 19:32:27 -080052 private static int sIconWidth = -1;
53 private static int sIconHeight = -1;
Michael Jurka7ef959b2011-02-23 11:48:32 -080054 private static int sIconContentSize = -1;
Joe Onorato6665c0f2009-09-02 15:27:24 -070055 private static int sIconTextureWidth = -1;
56 private static int sIconTextureHeight = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080057
Joe Onorato1291a8c2009-09-15 15:07:25 -040058 private static final Paint sBlurPaint = new Paint();
Joe Onoratoeb8325a2009-11-08 13:20:30 -050059 private static final Paint sGlowColorPressedPaint = new Paint();
Joe Onoratoc61cff92009-11-08 11:54:39 -050060 private static final Paint sGlowColorFocusedPaint = new Paint();
Joe Onorato56d82912010-03-07 14:32:10 -050061 private static final Paint sDisabledPaint = new Paint();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080062 private static final Rect sOldBounds = new Rect();
Romain Guy89911d22009-09-28 18:48:49 -070063 private static final Canvas sCanvas = new Canvas();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080064
65 static {
66 sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
67 Paint.FILTER_BITMAP_FLAG));
68 }
69
70 static Bitmap centerToFit(Bitmap bitmap, int width, int height, Context context) {
71 final int bitmapWidth = bitmap.getWidth();
72 final int bitmapHeight = bitmap.getHeight();
73
74 if (bitmapWidth < width || bitmapHeight < height) {
75 int color = context.getResources().getColor(R.color.window_background);
76
77 Bitmap centered = Bitmap.createBitmap(bitmapWidth < width ? width : bitmapWidth,
78 bitmapHeight < height ? height : bitmapHeight, Bitmap.Config.RGB_565);
Dianne Hackborn32ce7f12009-07-22 21:56:50 -070079 centered.setDensity(bitmap.getDensity());
The Android Open Source Project31dd5032009-03-03 19:32:27 -080080 Canvas canvas = new Canvas(centered);
81 canvas.drawColor(color);
82 canvas.drawBitmap(bitmap, (width - bitmapWidth) / 2.0f, (height - bitmapHeight) / 2.0f,
83 null);
84
85 bitmap = centered;
86 }
87
88 return bitmap;
89 }
90
Joe Onorato6665c0f2009-09-02 15:27:24 -070091 static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
92 static int sColorIndex = 0;
93
Michael Jurka7ef959b2011-02-23 11:48:32 -080094 static int getIconContentSize() {
95 return sIconContentSize;
96 }
97
Joe Onorato6665c0f2009-09-02 15:27:24 -070098 /**
99 * Returns a bitmap suitable for the all apps view. The bitmap will be a power
100 * of two sized ARGB_8888 bitmap that can be used as a gl texture.
101 */
Joe Onorato0589f0f2010-02-08 13:44:00 -0800102 static Bitmap createIconBitmap(Drawable icon, Context context) {
Joe Onorato6665c0f2009-09-02 15:27:24 -0700103 synchronized (sCanvas) { // we share the statics :-(
104 if (sIconWidth == -1) {
105 initStatics(context);
106 }
107
108 int width = sIconWidth;
109 int height = sIconHeight;
110
Joe Onorato6665c0f2009-09-02 15:27:24 -0700111 if (icon instanceof PaintDrawable) {
112 PaintDrawable painter = (PaintDrawable) icon;
113 painter.setIntrinsicWidth(width);
114 painter.setIntrinsicHeight(height);
115 } else if (icon instanceof BitmapDrawable) {
116 // Ensure the bitmap has a density.
117 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
118 Bitmap bitmap = bitmapDrawable.getBitmap();
119 if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
120 bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
121 }
122 }
123 int sourceWidth = icon.getIntrinsicWidth();
124 int sourceHeight = icon.getIntrinsicHeight();
125
126 if (sourceWidth > 0 && sourceWidth > 0) {
127 // There are intrinsic sizes.
Romain Guy89911d22009-09-28 18:48:49 -0700128 if (width < sourceWidth || height < sourceHeight) {
Joe Onorato6665c0f2009-09-02 15:27:24 -0700129 // It's too big, scale it down.
130 final float ratio = (float) sourceWidth / sourceHeight;
131 if (sourceWidth > sourceHeight) {
132 height = (int) (width / ratio);
133 } else if (sourceHeight > sourceWidth) {
134 width = (int) (height * ratio);
135 }
136 } else if (sourceWidth < width && sourceHeight < height) {
137 // It's small, use the size they gave us.
138 width = sourceWidth;
Romain Guy89911d22009-09-28 18:48:49 -0700139 height = sourceHeight;
Joe Onorato6665c0f2009-09-02 15:27:24 -0700140 }
141 }
142
143 // no intrinsic size --> use default size
144 int textureWidth = sIconTextureWidth;
145 int textureHeight = sIconTextureHeight;
146
147 final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
148 Bitmap.Config.ARGB_8888);
149 final Canvas canvas = sCanvas;
150 canvas.setBitmap(bitmap);
151
152 final int left = (textureWidth-width) / 2;
153 final int top = (textureHeight-height) / 2;
154
155 if (false) {
156 // draw a big box for the icon for debugging
157 canvas.drawColor(sColors[sColorIndex]);
158 if (++sColorIndex >= sColors.length) sColorIndex = 0;
159 Paint debugPaint = new Paint();
160 debugPaint.setColor(0xffcccc00);
161 canvas.drawRect(left, top, left+width, top+height, debugPaint);
162 }
163
164 sOldBounds.set(icon.getBounds());
165 icon.setBounds(left, top, left+width, top+height);
166 icon.draw(canvas);
167 icon.setBounds(sOldBounds);
168
169 return bitmap;
170 }
171 }
172
Joe Onoratoc61cff92009-11-08 11:54:39 -0500173 static void drawSelectedAllAppsBitmap(Canvas dest, int destWidth, int destHeight,
Joe Onoratoeb8325a2009-11-08 13:20:30 -0500174 boolean pressed, Bitmap src) {
Joe Onorato1291a8c2009-09-15 15:07:25 -0400175 synchronized (sCanvas) { // we share the statics :-(
176 if (sIconWidth == -1) {
177 // We can't have gotten to here without src being initialized, which
178 // comes from this file already. So just assert.
179 //initStatics(context);
180 throw new RuntimeException("Assertion failed: Utilities not initialized");
181 }
182
183 dest.drawColor(0, PorterDuff.Mode.CLEAR);
Jason Samsb4ecab22010-01-19 16:43:26 -0800184
Joe Onorato1291a8c2009-09-15 15:07:25 -0400185 int[] xy = new int[2];
Mike Reedcdd11792009-10-29 17:27:55 -0400186 Bitmap mask = src.extractAlpha(sBlurPaint, xy);
Joe Onorato1291a8c2009-09-15 15:07:25 -0400187
Mike Reedcdd11792009-10-29 17:27:55 -0400188 float px = (destWidth - src.getWidth()) / 2;
189 float py = (destHeight - src.getHeight()) / 2;
Joe Onoratoc61cff92009-11-08 11:54:39 -0500190 dest.drawBitmap(mask, px + xy[0], py + xy[1],
Joe Onoratoeb8325a2009-11-08 13:20:30 -0500191 pressed ? sGlowColorPressedPaint : sGlowColorFocusedPaint);
Joe Onorato1291a8c2009-09-15 15:07:25 -0400192
193 mask.recycle();
194 }
195 }
Joe Onorato6665c0f2009-09-02 15:27:24 -0700196
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800197 /**
198 * Returns a Bitmap representing the thumbnail of the specified Bitmap.
199 * The size of the thumbnail is defined by the dimension
200 * android.R.dimen.launcher_application_icon_size.
201 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800202 * @param bitmap The bitmap to get a thumbnail of.
203 * @param context The application's context.
204 *
205 * @return A thumbnail for the specified bitmap or the bitmap itself if the
206 * thumbnail could not be created.
207 */
Joe Onorato0589f0f2010-02-08 13:44:00 -0800208 static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
Joe Onorato9c1289c2009-08-17 11:03:03 -0400209 synchronized (sCanvas) { // we share the statics :-(
210 if (sIconWidth == -1) {
Joe Onorato6665c0f2009-09-02 15:27:24 -0700211 initStatics(context);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800212 }
213
Joe Onorato0589f0f2010-02-08 13:44:00 -0800214 if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
215 return bitmap;
216 } else {
217 return createIconBitmap(new BitmapDrawable(bitmap), context);
Joe Onorato9c1289c2009-08-17 11:03:03 -0400218 }
Joe Onorato9c1289c2009-08-17 11:03:03 -0400219 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800220 }
Joe Onoratobf15cb42009-08-07 14:33:40 -0700221
Joe Onorato56d82912010-03-07 14:32:10 -0500222 static Bitmap drawDisabledBitmap(Bitmap bitmap, Context context) {
223 synchronized (sCanvas) { // we share the statics :-(
224 if (sIconWidth == -1) {
225 initStatics(context);
226 }
227 final Bitmap disabled = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
228 Bitmap.Config.ARGB_8888);
229 final Canvas canvas = sCanvas;
230 canvas.setBitmap(disabled);
231
232 canvas.drawBitmap(bitmap, 0.0f, 0.0f, sDisabledPaint);
233
234 return disabled;
235 }
236 }
237
Joe Onorato6665c0f2009-09-02 15:27:24 -0700238 private static void initStatics(Context context) {
239 final Resources resources = context.getResources();
Joe Onorato1291a8c2009-09-15 15:07:25 -0400240 final DisplayMetrics metrics = resources.getDisplayMetrics();
241 final float density = metrics.density;
242
Michael Jurkac9a96192010-11-01 11:52:08 -0700243 sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
Michael Jurka7ef959b2011-02-23 11:48:32 -0800244 if (LauncherApplication.isScreenXLarge()) {
245 sIconContentSize = (int) resources.getDimension(R.dimen.app_icon_content_size);
246 }
Jason Samsb4ecab22010-01-19 16:43:26 -0800247 sIconTextureWidth = sIconTextureHeight = sIconWidth + 2;
Joe Onorato1291a8c2009-09-15 15:07:25 -0400248
Joe Onoratoa4c0cb92009-11-02 10:42:02 -0500249 sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
Joe Onoratoeb8325a2009-11-08 13:20:30 -0500250 sGlowColorPressedPaint.setColor(0xffffc300);
251 sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
Joe Onoratoc61cff92009-11-08 11:54:39 -0500252 sGlowColorFocusedPaint.setColor(0xffff8e00);
253 sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
Joe Onorato56d82912010-03-07 14:32:10 -0500254
255 ColorMatrix cm = new ColorMatrix();
256 cm.setSaturation(0.2f);
257 sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
258 sDisabledPaint.setAlpha(0x88);
Joe Onorato6665c0f2009-09-02 15:27:24 -0700259 }
260
Joe Onoratobf15cb42009-08-07 14:33:40 -0700261 static class BubbleText {
262 private static final int MAX_LINES = 2;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700263
Romain Guy88f38d12010-01-26 14:50:34 -0800264 private final TextPaint mTextPaint;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700265
Romain Guy88f38d12010-01-26 14:50:34 -0800266 private final RectF mBubbleRect = new RectF();
Joe Onoratobf15cb42009-08-07 14:33:40 -0700267
Romain Guy88f38d12010-01-26 14:50:34 -0800268 private final float mTextWidth;
269 private final int mLeading;
270 private final int mFirstLineY;
271 private final int mLineHeight;
272
273 private final int mBitmapWidth;
274 private final int mBitmapHeight;
275 private final int mDensity;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700276
277 BubbleText(Context context) {
278 final Resources resources = context.getResources();
279
Romain Guy88f38d12010-01-26 14:50:34 -0800280 final DisplayMetrics metrics = resources.getDisplayMetrics();
281 final float scale = metrics.density;
282 mDensity = metrics.densityDpi;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700283
Kenny Root97051642010-03-05 13:24:08 -0800284 final float paddingLeft = 2.0f * scale;
285 final float paddingRight = 2.0f * scale;
Romain Guy442eda22010-02-04 15:59:37 -0800286 final float cellWidth = resources.getDimension(R.dimen.title_texture_width);
Joe Onoratobf15cb42009-08-07 14:33:40 -0700287
288 RectF bubbleRect = mBubbleRect;
289 bubbleRect.left = 0;
290 bubbleRect.top = 0;
Romain Guyc0c4fe32010-02-12 23:20:25 +0100291 bubbleRect.right = (int) cellWidth;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700292
Kenny Root97051642010-03-05 13:24:08 -0800293 mTextWidth = cellWidth - paddingLeft - paddingRight;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700294
Joe Onoratobf15cb42009-08-07 14:33:40 -0700295 TextPaint textPaint = mTextPaint = new TextPaint();
Joe Onoratoefabe002009-08-28 09:38:18 -0700296 textPaint.setTypeface(Typeface.DEFAULT);
297 textPaint.setTextSize(13*scale);
Joe Onoratobf15cb42009-08-07 14:33:40 -0700298 textPaint.setColor(0xffffffff);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700299 textPaint.setAntiAlias(true);
Joe Onorato9392a752009-09-15 17:13:09 -0400300 if (TEXT_BURN) {
301 textPaint.setShadowLayer(8, 0, 0, 0xff000000);
302 }
Joe Onoratobf15cb42009-08-07 14:33:40 -0700303
304 float ascent = -textPaint.ascent();
305 float descent = textPaint.descent();
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700306 float leading = 0.0f;//(ascent+descent) * 0.1f;
Joe Onoratobf15cb42009-08-07 14:33:40 -0700307 mLeading = (int)(leading + 0.5f);
308 mFirstLineY = (int)(leading + ascent + 0.5f);
309 mLineHeight = (int)(leading + ascent + descent + 0.5f);
310
Romain Guy442eda22010-02-04 15:59:37 -0800311 mBitmapWidth = (int)(mBubbleRect.width() + 0.5f);
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700312 mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f));
Joe Onoratobf15cb42009-08-07 14:33:40 -0700313
Joe Onoratofccc8df2009-10-01 14:30:16 -0700314 mBubbleRect.offsetTo((mBitmapWidth-mBubbleRect.width())/2, 0);
315
Joe Onorato080d9b62009-11-02 12:01:11 -0500316 if (false) {
317 Log.d(TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight="
318 + mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f))
319 + " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f)));
320 }
Joe Onoratobf15cb42009-08-07 14:33:40 -0700321 }
322
323 /** You own the bitmap after this and you must call recycle on it. */
324 Bitmap createTextBitmap(String text) {
Jason Sams6ec11bc2010-01-19 17:56:52 -0800325 Bitmap b = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ALPHA_8);
Romain Guy88f38d12010-01-26 14:50:34 -0800326 b.setDensity(mDensity);
Joe Onoratobf15cb42009-08-07 14:33:40 -0700327 Canvas c = new Canvas(b);
328
329 StaticLayout layout = new StaticLayout(text, mTextPaint, (int)mTextWidth,
330 Alignment.ALIGN_CENTER, 1, 0, true);
331 int lineCount = layout.getLineCount();
332 if (lineCount > MAX_LINES) {
333 lineCount = MAX_LINES;
334 }
Jason Samsfd22dac2009-09-20 17:24:16 -0700335 //if (!TEXT_BURN && lineCount > 0) {
336 //RectF bubbleRect = mBubbleRect;
337 //bubbleRect.bottom = height(lineCount);
338 //c.drawRoundRect(bubbleRect, mCornerRadius, mCornerRadius, mRectPaint);
339 //}
Joe Onoratobf15cb42009-08-07 14:33:40 -0700340 for (int i=0; i<lineCount; i++) {
Joe Onoratofccc8df2009-10-01 14:30:16 -0700341 //int x = (int)((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f);
342 //int y = mFirstLineY + (i * mLineHeight);
Romain Guy88f38d12010-01-26 14:50:34 -0800343 final String lineText = text.substring(layout.getLineStart(i), layout.getLineEnd(i));
Joe Onoratofccc8df2009-10-01 14:30:16 -0700344 int x = (int)(mBubbleRect.left
Romain Guy88f38d12010-01-26 14:50:34 -0800345 + ((mBubbleRect.width() - mTextPaint.measureText(lineText)) * 0.5f));
Joe Onoratobf15cb42009-08-07 14:33:40 -0700346 int y = mFirstLineY + (i * mLineHeight);
Romain Guy88f38d12010-01-26 14:50:34 -0800347 c.drawText(lineText, x, y, mTextPaint);
Joe Onoratobf15cb42009-08-07 14:33:40 -0700348 }
349
350 return b;
351 }
Joe Onorato43e7bcf2009-08-08 18:53:53 -0700352
353 private int height(int lineCount) {
354 return (int)((lineCount * mLineHeight) + mLeading + mLeading + 0.0f);
355 }
356
357 int getBubbleWidth() {
358 return (int)(mBubbleRect.width() + 0.5f);
359 }
360
361 int getMaxBubbleHeight() {
362 return height(MAX_LINES);
363 }
364
365 int getBitmapWidth() {
366 return mBitmapWidth;
367 }
368
369 int getBitmapHeight() {
370 return mBitmapHeight;
371 }
Joe Onoratobf15cb42009-08-07 14:33:40 -0700372 }
373
374 /** Only works for positive numbers. */
375 static int roundToPow2(int n) {
376 int orig = n;
377 n >>= 1;
378 int mask = 0x8000000;
379 while (mask != 0 && (n & mask) == 0) {
380 mask >>= 1;
381 }
382 while (mask != 0) {
383 n |= mask;
384 mask >>= 1;
385 }
386 n += 1;
387 if (n != orig) {
388 n <<= 1;
389 }
390 return n;
391 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800392}