mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 10:48:19 +00:00
469 lines
18 KiB
Java
469 lines
18 KiB
Java
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.launcher2;
|
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.graphics.drawable.PaintDrawable;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BlurMaskFilter;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Paint;
|
|
import android.graphics.PaintFlagsDrawFilter;
|
|
import android.graphics.PixelFormat;
|
|
import android.graphics.PorterDuff;
|
|
import android.graphics.Rect;
|
|
import android.graphics.RectF;
|
|
import android.graphics.Typeface;
|
|
import android.text.Layout.Alignment;
|
|
import android.text.StaticLayout;
|
|
import android.text.TextPaint;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
import android.content.res.Resources;
|
|
import android.content.Context;
|
|
|
|
/**
|
|
* Various utilities shared amongst the Launcher's classes.
|
|
*/
|
|
final class Utilities {
|
|
private static final String TAG = "Launcher.Utilities";
|
|
|
|
private static final boolean TEXT_BURN = false;
|
|
|
|
private static int sIconWidth = -1;
|
|
private static int sIconHeight = -1;
|
|
private static int sIconTextureWidth = -1;
|
|
private static int sIconTextureHeight = -1;
|
|
|
|
private static final Paint sPaint = new Paint();
|
|
private static final Paint sBlurPaint = new Paint();
|
|
private static final Paint sGlowColorPaint = new Paint();
|
|
private static final Paint sEmptyPaint = new Paint();
|
|
private static final Rect sBounds = new Rect();
|
|
private static final Rect sOldBounds = new Rect();
|
|
private static Canvas sCanvas = new Canvas();
|
|
|
|
static {
|
|
sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
|
|
Paint.FILTER_BITMAP_FLAG));
|
|
}
|
|
|
|
static Bitmap centerToFit(Bitmap bitmap, int width, int height, Context context) {
|
|
final int bitmapWidth = bitmap.getWidth();
|
|
final int bitmapHeight = bitmap.getHeight();
|
|
|
|
if (bitmapWidth < width || bitmapHeight < height) {
|
|
int color = context.getResources().getColor(R.color.window_background);
|
|
|
|
Bitmap centered = Bitmap.createBitmap(bitmapWidth < width ? width : bitmapWidth,
|
|
bitmapHeight < height ? height : bitmapHeight, Bitmap.Config.RGB_565);
|
|
centered.setDensity(bitmap.getDensity());
|
|
Canvas canvas = new Canvas(centered);
|
|
canvas.drawColor(color);
|
|
canvas.drawBitmap(bitmap, (width - bitmapWidth) / 2.0f, (height - bitmapHeight) / 2.0f,
|
|
null);
|
|
|
|
bitmap = centered;
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
/**
|
|
* Returns a Drawable representing the thumbnail of the specified Drawable.
|
|
* The size of the thumbnail is defined by the dimension
|
|
* android.R.dimen.launcher_application_icon_size.
|
|
*
|
|
* @param icon The icon to get a thumbnail of.
|
|
* @param context The application's context.
|
|
*
|
|
* @return A thumbnail for the specified icon or the icon itself if the
|
|
* thumbnail could not be created.
|
|
*/
|
|
static Drawable createIconThumbnail(Drawable icon, Context context) {
|
|
synchronized (sCanvas) { // we share the statics :-(
|
|
if (sIconWidth == -1) {
|
|
initStatics(context);
|
|
}
|
|
|
|
int width = sIconWidth;
|
|
int height = sIconHeight;
|
|
|
|
float scale = 1.0f;
|
|
if (icon instanceof PaintDrawable) {
|
|
PaintDrawable painter = (PaintDrawable) icon;
|
|
painter.setIntrinsicWidth(width);
|
|
painter.setIntrinsicHeight(height);
|
|
} else if (icon instanceof BitmapDrawable) {
|
|
// Ensure the bitmap has a density.
|
|
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
|
|
Bitmap bitmap = bitmapDrawable.getBitmap();
|
|
if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
|
|
bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
|
|
}
|
|
}
|
|
int iconWidth = icon.getIntrinsicWidth();
|
|
int iconHeight = icon.getIntrinsicHeight();
|
|
|
|
if (iconWidth > 0 && iconWidth > 0) {
|
|
if (width < iconWidth || height < iconHeight || scale != 1.0f) {
|
|
final float ratio = (float) iconWidth / iconHeight;
|
|
|
|
if (iconWidth > iconHeight) {
|
|
height = (int) (width / ratio);
|
|
} else if (iconHeight > iconWidth) {
|
|
width = (int) (height * ratio);
|
|
}
|
|
|
|
final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
|
|
Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
|
final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
|
|
final Canvas canvas = sCanvas;
|
|
canvas.setBitmap(thumb);
|
|
// Copy the old bounds to restore them later
|
|
// If we were to do oldBounds = icon.getBounds(),
|
|
// the call to setBounds() that follows would
|
|
// change the same instance and we would lose the
|
|
// old bounds
|
|
sOldBounds.set(icon.getBounds());
|
|
final int x = (sIconWidth - width) / 2;
|
|
final int y = (sIconHeight - height) / 2;
|
|
icon.setBounds(x, y, x + width, y + height);
|
|
icon.draw(canvas);
|
|
icon.setBounds(sOldBounds);
|
|
icon = new FastBitmapDrawable(thumb);
|
|
} else if (iconWidth < width && iconHeight < height) {
|
|
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
|
|
final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
|
|
final Canvas canvas = sCanvas;
|
|
canvas.setBitmap(thumb);
|
|
sOldBounds.set(icon.getBounds());
|
|
final int x = (width - iconWidth) / 2;
|
|
final int y = (height - iconHeight) / 2;
|
|
icon.setBounds(x, y, x + iconWidth, y + iconHeight);
|
|
icon.draw(canvas);
|
|
icon.setBounds(sOldBounds);
|
|
icon = new FastBitmapDrawable(thumb);
|
|
}
|
|
}
|
|
|
|
return icon;
|
|
}
|
|
}
|
|
|
|
static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
|
|
static int sColorIndex = 0;
|
|
|
|
/**
|
|
* Returns a bitmap suitable for the all apps view. The bitmap will be a power
|
|
* of two sized ARGB_8888 bitmap that can be used as a gl texture.
|
|
*/
|
|
static Bitmap createAllAppsBitmap(Drawable icon, Context context) {
|
|
synchronized (sCanvas) { // we share the statics :-(
|
|
if (sIconWidth == -1) {
|
|
initStatics(context);
|
|
}
|
|
|
|
int width = sIconWidth;
|
|
int height = sIconHeight;
|
|
|
|
float scale = 1.0f;
|
|
if (icon instanceof PaintDrawable) {
|
|
PaintDrawable painter = (PaintDrawable) icon;
|
|
painter.setIntrinsicWidth(width);
|
|
painter.setIntrinsicHeight(height);
|
|
} else if (icon instanceof BitmapDrawable) {
|
|
// Ensure the bitmap has a density.
|
|
BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
|
|
Bitmap bitmap = bitmapDrawable.getBitmap();
|
|
if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
|
|
bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
|
|
}
|
|
}
|
|
int sourceWidth = icon.getIntrinsicWidth();
|
|
int sourceHeight = icon.getIntrinsicHeight();
|
|
|
|
if (sourceWidth > 0 && sourceWidth > 0) {
|
|
// There are intrinsic sizes.
|
|
if (width < sourceWidth || height < sourceHeight || scale != 1.0f) {
|
|
// It's too big, scale it down.
|
|
final float ratio = (float) sourceWidth / sourceHeight;
|
|
if (sourceWidth > sourceHeight) {
|
|
height = (int) (width / ratio);
|
|
} else if (sourceHeight > sourceWidth) {
|
|
width = (int) (height * ratio);
|
|
}
|
|
} else if (sourceWidth < width && sourceHeight < height) {
|
|
// It's small, use the size they gave us.
|
|
width = sourceWidth;
|
|
height = sourceWidth;
|
|
}
|
|
}
|
|
|
|
// no intrinsic size --> use default size
|
|
int textureWidth = sIconTextureWidth;
|
|
int textureHeight = sIconTextureHeight;
|
|
|
|
final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
|
|
Bitmap.Config.ARGB_8888);
|
|
final Canvas canvas = sCanvas;
|
|
canvas.setBitmap(bitmap);
|
|
|
|
final int left = (textureWidth-width) / 2;
|
|
final int top = (textureHeight-height) / 2;
|
|
|
|
if (false) {
|
|
// draw a big box for the icon for debugging
|
|
canvas.drawColor(sColors[sColorIndex]);
|
|
if (++sColorIndex >= sColors.length) sColorIndex = 0;
|
|
Paint debugPaint = new Paint();
|
|
debugPaint.setColor(0xffcccc00);
|
|
canvas.drawRect(left, top, left+width, top+height, debugPaint);
|
|
}
|
|
|
|
sOldBounds.set(icon.getBounds());
|
|
icon.setBounds(left, top, left+width, top+height);
|
|
icon.draw(canvas);
|
|
icon.setBounds(sOldBounds);
|
|
|
|
return bitmap;
|
|
}
|
|
}
|
|
|
|
static void drawSelectedAllAppsBitmap(Canvas dest, int destWidth, int destHeight, Bitmap src) {
|
|
synchronized (sCanvas) { // we share the statics :-(
|
|
if (sIconWidth == -1) {
|
|
// We can't have gotten to here without src being initialized, which
|
|
// comes from this file already. So just assert.
|
|
//initStatics(context);
|
|
throw new RuntimeException("Assertion failed: Utilities not initialized");
|
|
}
|
|
|
|
dest.drawColor(0, PorterDuff.Mode.CLEAR);
|
|
|
|
final float scale = 1.55f;
|
|
Bitmap scaled = Bitmap.createScaledBitmap(src, (int)(src.getWidth()*scale),
|
|
(int)(src.getHeight()*scale), true);
|
|
|
|
int[] xy = new int[2];
|
|
Bitmap mask = scaled.extractAlpha(sBlurPaint, xy);
|
|
|
|
dest.drawBitmap(mask, (destWidth - mask.getWidth()) / 2,
|
|
(destHeight - mask.getHeight()) / 2, sGlowColorPaint);
|
|
dest.drawBitmap(src, (destWidth - src.getWidth()) / 2,
|
|
(destHeight - src.getHeight()) / 2, sEmptyPaint);
|
|
|
|
mask.recycle();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a Bitmap representing the thumbnail of the specified Bitmap.
|
|
* The size of the thumbnail is defined by the dimension
|
|
* android.R.dimen.launcher_application_icon_size.
|
|
*
|
|
* @param bitmap The bitmap to get a thumbnail of.
|
|
* @param context The application's context.
|
|
*
|
|
* @return A thumbnail for the specified bitmap or the bitmap itself if the
|
|
* thumbnail could not be created.
|
|
*/
|
|
static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) {
|
|
synchronized (sCanvas) { // we share the statics :-(
|
|
if (sIconWidth == -1) {
|
|
initStatics(context);
|
|
}
|
|
|
|
int width = sIconWidth;
|
|
int height = sIconHeight;
|
|
|
|
final int bitmapWidth = bitmap.getWidth();
|
|
final int bitmapHeight = bitmap.getHeight();
|
|
|
|
if (width > 0 && height > 0 && (width < bitmapWidth || height < bitmapHeight)) {
|
|
final float ratio = (float) bitmapWidth / bitmapHeight;
|
|
|
|
if (bitmapWidth > bitmapHeight) {
|
|
height = (int) (width / ratio);
|
|
} else if (bitmapHeight > bitmapWidth) {
|
|
width = (int) (height * ratio);
|
|
}
|
|
|
|
final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ?
|
|
bitmap.getConfig() : Bitmap.Config.ARGB_8888;
|
|
final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c);
|
|
final Canvas canvas = sCanvas;
|
|
final Paint paint = sPaint;
|
|
canvas.setBitmap(thumb);
|
|
paint.setDither(false);
|
|
paint.setFilterBitmap(true);
|
|
sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height);
|
|
sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
|
|
canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
|
|
return thumb;
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
}
|
|
|
|
private static void initStatics(Context context) {
|
|
final Resources resources = context.getResources();
|
|
final DisplayMetrics metrics = resources.getDisplayMetrics();
|
|
final float density = metrics.density;
|
|
|
|
sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
|
|
sIconTextureWidth = sIconTextureHeight = roundToPow2(sIconWidth);
|
|
|
|
sBlurPaint.setMaskFilter(new BlurMaskFilter(7 * density, BlurMaskFilter.Blur.NORMAL));
|
|
sGlowColorPaint.setColor(0xffff9000);
|
|
}
|
|
|
|
static class BubbleText {
|
|
private static final int MAX_LINES = 2;
|
|
private TextPaint mTextPaint;
|
|
private Paint mRectPaint;
|
|
|
|
private float mBubblePadding;
|
|
private float mCornerRadius;
|
|
private RectF mBubbleRect = new RectF();
|
|
|
|
private float mTextWidth;
|
|
private int mLeading;
|
|
private int mFirstLineY;
|
|
private int mLineHeight;
|
|
|
|
private int mBitmapWidth;
|
|
private int mBitmapHeight;
|
|
|
|
BubbleText(Context context) {
|
|
final Resources resources = context.getResources();
|
|
|
|
final float scale = resources.getDisplayMetrics().density;
|
|
|
|
final float paddingLeft = 5.0f * scale;
|
|
final float paddingRight = 5.0f * scale;
|
|
final float cellWidth = resources.getDimension(R.dimen.workspace_cell_width);
|
|
final float bubbleWidth = cellWidth - paddingLeft - paddingRight;
|
|
mBubblePadding = 3.0f * scale;
|
|
|
|
RectF bubbleRect = mBubbleRect;
|
|
bubbleRect.left = 0;
|
|
bubbleRect.top = 0;
|
|
bubbleRect.right = (int)(bubbleWidth+0.5f);
|
|
|
|
mCornerRadius = BubbleTextView.CORNER_RADIUS * scale;
|
|
mTextWidth = bubbleWidth - mBubblePadding - mBubblePadding;
|
|
|
|
Paint rectPaint = mRectPaint = new Paint();
|
|
rectPaint.setColor(0xff000000);
|
|
rectPaint.setAntiAlias(true);
|
|
|
|
Log.d(TAG, "scale=" + scale + " textSize=" + (13*scale));
|
|
|
|
TextPaint textPaint = mTextPaint = new TextPaint();
|
|
textPaint.setTypeface(Typeface.DEFAULT);
|
|
textPaint.setTextSize(13*scale);
|
|
textPaint.setColor(0xffffffff);
|
|
textPaint.setAntiAlias(true);
|
|
if (TEXT_BURN) {
|
|
textPaint.setShadowLayer(8, 0, 0, 0xff000000);
|
|
}
|
|
|
|
float ascent = -textPaint.ascent();
|
|
float descent = textPaint.descent();
|
|
float leading = 0.0f;//(ascent+descent) * 0.1f;
|
|
mLeading = (int)(leading + 0.5f);
|
|
mFirstLineY = (int)(leading + ascent + 0.5f);
|
|
mLineHeight = (int)(leading + ascent + descent + 0.5f);
|
|
|
|
mBitmapWidth = roundToPow2((int)(mBubbleRect.width() + 0.5f));
|
|
mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f));
|
|
|
|
Log.d(TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight="
|
|
+ mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f))
|
|
+ " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f)));
|
|
}
|
|
|
|
/** You own the bitmap after this and you must call recycle on it. */
|
|
Bitmap createTextBitmap(String text) {
|
|
Bitmap b = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888);
|
|
Canvas c = new Canvas(b);
|
|
|
|
StaticLayout layout = new StaticLayout(text, mTextPaint, (int)mTextWidth,
|
|
Alignment.ALIGN_CENTER, 1, 0, true);
|
|
int lineCount = layout.getLineCount();
|
|
if (lineCount > MAX_LINES) {
|
|
lineCount = MAX_LINES;
|
|
}
|
|
//if (!TEXT_BURN && lineCount > 0) {
|
|
//RectF bubbleRect = mBubbleRect;
|
|
//bubbleRect.bottom = height(lineCount);
|
|
//c.drawRoundRect(bubbleRect, mCornerRadius, mCornerRadius, mRectPaint);
|
|
//}
|
|
for (int i=0; i<lineCount; i++) {
|
|
int x = (int)((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f);
|
|
int y = mFirstLineY + (i * mLineHeight);
|
|
c.drawText(text.substring(layout.getLineStart(i), layout.getLineEnd(i)),
|
|
x, y, mTextPaint);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
private int height(int lineCount) {
|
|
return (int)((lineCount * mLineHeight) + mLeading + mLeading + 0.0f);
|
|
}
|
|
|
|
int getBubbleWidth() {
|
|
return (int)(mBubbleRect.width() + 0.5f);
|
|
}
|
|
|
|
int getMaxBubbleHeight() {
|
|
return height(MAX_LINES);
|
|
}
|
|
|
|
int getBitmapWidth() {
|
|
return mBitmapWidth;
|
|
}
|
|
|
|
int getBitmapHeight() {
|
|
return mBitmapHeight;
|
|
}
|
|
}
|
|
|
|
/** Only works for positive numbers. */
|
|
static int roundToPow2(int n) {
|
|
int orig = n;
|
|
n >>= 1;
|
|
int mask = 0x8000000;
|
|
while (mask != 0 && (n & mask) == 0) {
|
|
mask >>= 1;
|
|
}
|
|
while (mask != 0) {
|
|
n |= mask;
|
|
mask >>= 1;
|
|
}
|
|
n += 1;
|
|
if (n != orig) {
|
|
n <<= 1;
|
|
}
|
|
return n;
|
|
}
|
|
}
|