Home | History | Annotate | Download | only in launcher2
      1 /*
      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 
     17 package com.android.launcher2;
     18 
     19 import android.graphics.drawable.BitmapDrawable;
     20 import android.graphics.drawable.Drawable;
     21 import android.graphics.drawable.PaintDrawable;
     22 import android.graphics.Bitmap;
     23 import android.graphics.BlurMaskFilter;
     24 import android.graphics.Canvas;
     25 import android.graphics.ColorMatrix;
     26 import android.graphics.ColorMatrixColorFilter;
     27 import android.graphics.Paint;
     28 import android.graphics.PaintFlagsDrawFilter;
     29 import android.graphics.PixelFormat;
     30 import android.graphics.PorterDuff;
     31 import android.graphics.Rect;
     32 import android.graphics.RectF;
     33 import android.graphics.TableMaskFilter;
     34 import android.graphics.Typeface;
     35 import android.text.Layout.Alignment;
     36 import android.text.StaticLayout;
     37 import android.text.TextPaint;
     38 import android.util.DisplayMetrics;
     39 import android.util.Log;
     40 import android.content.res.Resources;
     41 import android.content.Context;
     42 
     43 import com.android.launcher.R;
     44 
     45 /**
     46  * Various utilities shared amongst the Launcher's classes.
     47  */
     48 final class Utilities {
     49     private static final String TAG = "Launcher.Utilities";
     50 
     51     private static final boolean TEXT_BURN = false;
     52 
     53     private static int sIconWidth = -1;
     54     private static int sIconHeight = -1;
     55     private static int sIconTextureWidth = -1;
     56     private static int sIconTextureHeight = -1;
     57 
     58     private static final Paint sPaint = new Paint();
     59     private static final Paint sBlurPaint = new Paint();
     60     private static final Paint sGlowColorPressedPaint = new Paint();
     61     private static final Paint sGlowColorFocusedPaint = new Paint();
     62     private static final Paint sDisabledPaint = new Paint();
     63     private static final Rect sBounds = new Rect();
     64     private static final Rect sOldBounds = new Rect();
     65     private static final Canvas sCanvas = new Canvas();
     66 
     67     static {
     68         sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
     69                 Paint.FILTER_BITMAP_FLAG));
     70     }
     71 
     72     static Bitmap centerToFit(Bitmap bitmap, int width, int height, Context context) {
     73         final int bitmapWidth = bitmap.getWidth();
     74         final int bitmapHeight = bitmap.getHeight();
     75 
     76         if (bitmapWidth < width || bitmapHeight < height) {
     77             int color = context.getResources().getColor(R.color.window_background);
     78 
     79             Bitmap centered = Bitmap.createBitmap(bitmapWidth < width ? width : bitmapWidth,
     80                     bitmapHeight < height ? height : bitmapHeight, Bitmap.Config.RGB_565);
     81             centered.setDensity(bitmap.getDensity());
     82             Canvas canvas = new Canvas(centered);
     83             canvas.drawColor(color);
     84             canvas.drawBitmap(bitmap, (width - bitmapWidth) / 2.0f, (height - bitmapHeight) / 2.0f,
     85                     null);
     86 
     87             bitmap = centered;
     88         }
     89 
     90         return bitmap;
     91     }
     92 
     93     static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
     94     static int sColorIndex = 0;
     95 
     96     /**
     97      * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
     98      * of two sized ARGB_8888 bitmap that can be used as a gl texture.
     99      */
    100     static Bitmap createIconBitmap(Drawable icon, Context context) {
    101         synchronized (sCanvas) { // we share the statics :-(
    102             if (sIconWidth == -1) {
    103                 initStatics(context);
    104             }
    105 
    106             int width = sIconWidth;
    107             int height = sIconHeight;
    108 
    109             if (icon instanceof PaintDrawable) {
    110                 PaintDrawable painter = (PaintDrawable) icon;
    111                 painter.setIntrinsicWidth(width);
    112                 painter.setIntrinsicHeight(height);
    113             } else if (icon instanceof BitmapDrawable) {
    114                 // Ensure the bitmap has a density.
    115                 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
    116                 Bitmap bitmap = bitmapDrawable.getBitmap();
    117                 if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
    118                     bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
    119                 }
    120             }
    121             int sourceWidth = icon.getIntrinsicWidth();
    122             int sourceHeight = icon.getIntrinsicHeight();
    123 
    124             if (sourceWidth > 0 && sourceWidth > 0) {
    125                 // There are intrinsic sizes.
    126                 if (width < sourceWidth || height < sourceHeight) {
    127                     // It's too big, scale it down.
    128                     final float ratio = (float) sourceWidth / sourceHeight;
    129                     if (sourceWidth > sourceHeight) {
    130                         height = (int) (width / ratio);
    131                     } else if (sourceHeight > sourceWidth) {
    132                         width = (int) (height * ratio);
    133                     }
    134                 } else if (sourceWidth < width && sourceHeight < height) {
    135                     // It's small, use the size they gave us.
    136                     width = sourceWidth;
    137                     height = sourceHeight;
    138                 }
    139             }
    140 
    141             // no intrinsic size --> use default size
    142             int textureWidth = sIconTextureWidth;
    143             int textureHeight = sIconTextureHeight;
    144 
    145             final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
    146                     Bitmap.Config.ARGB_8888);
    147             final Canvas canvas = sCanvas;
    148             canvas.setBitmap(bitmap);
    149 
    150             final int left = (textureWidth-width) / 2;
    151             final int top = (textureHeight-height) / 2;
    152 
    153             if (false) {
    154                 // draw a big box for the icon for debugging
    155                 canvas.drawColor(sColors[sColorIndex]);
    156                 if (++sColorIndex >= sColors.length) sColorIndex = 0;
    157                 Paint debugPaint = new Paint();
    158                 debugPaint.setColor(0xffcccc00);
    159                 canvas.drawRect(left, top, left+width, top+height, debugPaint);
    160             }
    161 
    162             sOldBounds.set(icon.getBounds());
    163             icon.setBounds(left, top, left+width, top+height);
    164             icon.draw(canvas);
    165             icon.setBounds(sOldBounds);
    166 
    167             return bitmap;
    168         }
    169     }
    170 
    171     static void drawSelectedAllAppsBitmap(Canvas dest, int destWidth, int destHeight,
    172             boolean pressed, Bitmap src) {
    173         synchronized (sCanvas) { // we share the statics :-(
    174             if (sIconWidth == -1) {
    175                 // We can't have gotten to here without src being initialized, which
    176                 // comes from this file already.  So just assert.
    177                 //initStatics(context);
    178                 throw new RuntimeException("Assertion failed: Utilities not initialized");
    179             }
    180 
    181             dest.drawColor(0, PorterDuff.Mode.CLEAR);
    182 
    183             int[] xy = new int[2];
    184             Bitmap mask = src.extractAlpha(sBlurPaint, xy);
    185 
    186             float px = (destWidth - src.getWidth()) / 2;
    187             float py = (destHeight - src.getHeight()) / 2;
    188             dest.drawBitmap(mask, px + xy[0], py + xy[1],
    189                     pressed ? sGlowColorPressedPaint : sGlowColorFocusedPaint);
    190 
    191             mask.recycle();
    192         }
    193     }
    194 
    195     /**
    196      * Returns a Bitmap representing the thumbnail of the specified Bitmap.
    197      * The size of the thumbnail is defined by the dimension
    198      * android.R.dimen.launcher_application_icon_size.
    199      *
    200      * @param bitmap The bitmap to get a thumbnail of.
    201      * @param context The application's context.
    202      *
    203      * @return A thumbnail for the specified bitmap or the bitmap itself if the
    204      *         thumbnail could not be created.
    205      */
    206     static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
    207         synchronized (sCanvas) { // we share the statics :-(
    208             if (sIconWidth == -1) {
    209                 initStatics(context);
    210             }
    211 
    212             if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
    213                 return bitmap;
    214             } else {
    215                 return createIconBitmap(new BitmapDrawable(bitmap), context);
    216             }
    217         }
    218     }
    219 
    220     static Bitmap drawDisabledBitmap(Bitmap bitmap, Context context) {
    221         synchronized (sCanvas) { // we share the statics :-(
    222             if (sIconWidth == -1) {
    223                 initStatics(context);
    224             }
    225             final Bitmap disabled = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
    226                     Bitmap.Config.ARGB_8888);
    227             final Canvas canvas = sCanvas;
    228             canvas.setBitmap(disabled);
    229 
    230             canvas.drawBitmap(bitmap, 0.0f, 0.0f, sDisabledPaint);
    231 
    232             return disabled;
    233         }
    234     }
    235 
    236     private static void initStatics(Context context) {
    237         final Resources resources = context.getResources();
    238         final DisplayMetrics metrics = resources.getDisplayMetrics();
    239         final float density = metrics.density;
    240 
    241         sIconWidth = sIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
    242         sIconTextureWidth = sIconTextureHeight = sIconWidth + 2;
    243 
    244         sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
    245         sGlowColorPressedPaint.setColor(0xffffc300);
    246         sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
    247         sGlowColorFocusedPaint.setColor(0xffff8e00);
    248         sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
    249 
    250         ColorMatrix cm = new ColorMatrix();
    251         cm.setSaturation(0.2f);
    252         sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
    253         sDisabledPaint.setAlpha(0x88);
    254     }
    255 
    256     static class BubbleText {
    257         private static final int MAX_LINES = 2;
    258 
    259         private final TextPaint mTextPaint;
    260 
    261         private final RectF mBubbleRect = new RectF();
    262 
    263         private final float mTextWidth;
    264         private final int mLeading;
    265         private final int mFirstLineY;
    266         private final int mLineHeight;
    267 
    268         private final int mBitmapWidth;
    269         private final int mBitmapHeight;
    270         private final int mDensity;
    271 
    272         BubbleText(Context context) {
    273             final Resources resources = context.getResources();
    274 
    275             final DisplayMetrics metrics = resources.getDisplayMetrics();
    276             final float scale = metrics.density;
    277             mDensity = metrics.densityDpi;
    278 
    279             final float paddingLeft = 2.0f * scale;
    280             final float paddingRight = 2.0f * scale;
    281             final float cellWidth = resources.getDimension(R.dimen.title_texture_width);
    282 
    283             RectF bubbleRect = mBubbleRect;
    284             bubbleRect.left = 0;
    285             bubbleRect.top = 0;
    286             bubbleRect.right = (int) cellWidth;
    287 
    288             mTextWidth = cellWidth - paddingLeft - paddingRight;
    289 
    290             TextPaint textPaint = mTextPaint = new TextPaint();
    291             textPaint.setTypeface(Typeface.DEFAULT);
    292             textPaint.setTextSize(13*scale);
    293             textPaint.setColor(0xffffffff);
    294             textPaint.setAntiAlias(true);
    295             if (TEXT_BURN) {
    296                 textPaint.setShadowLayer(8, 0, 0, 0xff000000);
    297             }
    298 
    299             float ascent = -textPaint.ascent();
    300             float descent = textPaint.descent();
    301             float leading = 0.0f;//(ascent+descent) * 0.1f;
    302             mLeading = (int)(leading + 0.5f);
    303             mFirstLineY = (int)(leading + ascent + 0.5f);
    304             mLineHeight = (int)(leading + ascent + descent + 0.5f);
    305 
    306             mBitmapWidth = (int)(mBubbleRect.width() + 0.5f);
    307             mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f));
    308 
    309             mBubbleRect.offsetTo((mBitmapWidth-mBubbleRect.width())/2, 0);
    310 
    311             if (false) {
    312                 Log.d(TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight="
    313                         + mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f))
    314                         + " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f)));
    315             }
    316         }
    317 
    318         /** You own the bitmap after this and you must call recycle on it. */
    319         Bitmap createTextBitmap(String text) {
    320             Bitmap b = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ALPHA_8);
    321             b.setDensity(mDensity);
    322             Canvas c = new Canvas(b);
    323 
    324             StaticLayout layout = new StaticLayout(text, mTextPaint, (int)mTextWidth,
    325                     Alignment.ALIGN_CENTER, 1, 0, true);
    326             int lineCount = layout.getLineCount();
    327             if (lineCount > MAX_LINES) {
    328                 lineCount = MAX_LINES;
    329             }
    330             //if (!TEXT_BURN && lineCount > 0) {
    331                 //RectF bubbleRect = mBubbleRect;
    332                 //bubbleRect.bottom = height(lineCount);
    333                 //c.drawRoundRect(bubbleRect, mCornerRadius, mCornerRadius, mRectPaint);
    334             //}
    335             for (int i=0; i<lineCount; i++) {
    336                 //int x = (int)((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f);
    337                 //int y = mFirstLineY + (i * mLineHeight);
    338                 final String lineText = text.substring(layout.getLineStart(i), layout.getLineEnd(i));
    339                 int x = (int)(mBubbleRect.left
    340                         + ((mBubbleRect.width() - mTextPaint.measureText(lineText)) * 0.5f));
    341                 int y = mFirstLineY + (i * mLineHeight);
    342                 c.drawText(lineText, x, y, mTextPaint);
    343             }
    344 
    345             return b;
    346         }
    347 
    348         private int height(int lineCount) {
    349             return (int)((lineCount * mLineHeight) + mLeading + mLeading + 0.0f);
    350         }
    351 
    352         int getBubbleWidth() {
    353             return (int)(mBubbleRect.width() + 0.5f);
    354         }
    355 
    356         int getMaxBubbleHeight() {
    357             return height(MAX_LINES);
    358         }
    359 
    360         int getBitmapWidth() {
    361             return mBitmapWidth;
    362         }
    363 
    364         int getBitmapHeight() {
    365             return mBitmapHeight;
    366         }
    367     }
    368 
    369     /** Only works for positive numbers. */
    370     static int roundToPow2(int n) {
    371         int orig = n;
    372         n >>= 1;
    373         int mask = 0x8000000;
    374         while (mask != 0 && (n & mask) == 0) {
    375             mask >>= 1;
    376         }
    377         while (mask != 0) {
    378             n |= mask;
    379             mask >>= 1;
    380         }
    381         n += 1;
    382         if (n != orig) {
    383             n <<= 1;
    384         }
    385         return n;
    386     }
    387 }
    388