131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
19a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.app.Activity;
20a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.content.ActivityNotFoundException;
21aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.Context;
22a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.content.Intent;
23aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.Resources;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Bitmap;
251291a8c236c84451321438cb68855f6f2eb24959Joe Onoratoimport android.graphics.BlurMaskFilter;
2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Canvas;
2756d8291af6a28c6ba64113120efdf84a785e816cJoe Onoratoimport android.graphics.ColorMatrix;
2856d8291af6a28c6ba64113120efdf84a785e816cJoe Onoratoimport android.graphics.ColorMatrixColorFilter;
29c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.graphics.Matrix;
3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Paint;
31bf15cb44cc8e5ea9a19ab8aaee8e02c96bd6130cJoe Onoratoimport android.graphics.PaintFlagsDrawFilter;
3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
33aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.BitmapDrawable;
34aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.Drawable;
35aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.PaintDrawable;
3632ce7f17a85abf9b175f773371308876f7401547Dianne Hackbornimport android.util.DisplayMetrics;
37a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.util.Log;
38c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.view.View;
39a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.widget.Toast;
40c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
41c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport java.util.ArrayList;
4231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
4431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Various utilities shared amongst the Launcher's classes.
4531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
4631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectfinal class Utilities {
471291a8c236c84451321438cb68855f6f2eb24959Joe Onorato    private static final String TAG = "Launcher.Utilities";
481291a8c236c84451321438cb68855f6f2eb24959Joe Onorato
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static int sIconWidth = -1;
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static int sIconHeight = -1;
5161f560d92ab4b11a61beeb8df97b9952027e08e4Adam Cohen    public static int sIconTextureWidth = -1;
5261f560d92ab4b11a61beeb8df97b9952027e08e4Adam Cohen    public static int sIconTextureHeight = -1;
5331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
541291a8c236c84451321438cb68855f6f2eb24959Joe Onorato    private static final Paint sBlurPaint = new Paint();
55eb8325a9e24cda47720152e1e95f5d86ab11f200Joe Onorato    private static final Paint sGlowColorPressedPaint = new Paint();
56c61cff9299a54599c2b214de7c819b6be0412f4eJoe Onorato    private static final Paint sGlowColorFocusedPaint = new Paint();
5756d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato    private static final Paint sDisabledPaint = new Paint();
5831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static final Rect sOldBounds = new Rect();
5989911d2450f5db92d79e3bcefa9d324e9e8c4900Romain Guy    private static final Canvas sCanvas = new Canvas();
6031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static {
6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                Paint.FILTER_BITMAP_FLAG));
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
656665c0f1fec6ec0962896622986340081df992e7Joe Onorato    static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
666665c0f1fec6ec0962896622986340081df992e7Joe Onorato    static int sColorIndex = 0;
676665c0f1fec6ec0962896622986340081df992e7Joe Onorato
686665c0f1fec6ec0962896622986340081df992e7Joe Onorato    /**
690dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     * Returns a FastBitmapDrawable with the icon, accurately sized.
700dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     */
710dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    static Drawable createIconDrawable(Bitmap icon) {
720dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        FastBitmapDrawable d = new FastBitmapDrawable(icon);
73540004905a555087e72691aad4479aa52ab5460eWinson Chung        d.setFilterBitmap(true);
740dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        resizeIconDrawable(d);
750dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        return d;
760dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    }
770dbd734384df38960515ce49dfcb5e15a394decaWinson Chung
780dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    /**
790dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     * Resizes an icon drawable to the correct icon size.
800dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     */
810dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    static void resizeIconDrawable(Drawable icon) {
820dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        icon.setBounds(0, 0, sIconTextureWidth, sIconTextureHeight);
830dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    }
840dbd734384df38960515ce49dfcb5e15a394decaWinson Chung
850dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    /**
86931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * Returns a bitmap suitable for the all apps view. Used to convert pre-ICS
87931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * icon bitmaps that are stored in the database (which were 74x74 pixels at hdpi size)
88931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * to the proper size (48dp)
89931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     */
90931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    static Bitmap createIconBitmap(Bitmap icon, Context context) {
91931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int textureWidth = sIconTextureWidth;
92931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int textureHeight = sIconTextureHeight;
93931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int sourceWidth = icon.getWidth();
94931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int sourceHeight = icon.getHeight();
95931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        if (sourceWidth > textureWidth && sourceHeight > textureHeight) {
96931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is bigger than it should be; clip it (solves the GB->ICS migration case)
97931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            return Bitmap.createBitmap(icon,
98931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    (sourceWidth - textureWidth) / 2,
99931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    (sourceHeight - textureHeight) / 2,
100931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    textureWidth, textureHeight);
101931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        } else if (sourceWidth == textureWidth && sourceHeight == textureHeight) {
102931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is the right size, no need to change it
103931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            return icon;
104931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        } else {
105931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is too small, render to a larger bitmap
1063a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            final Resources resources = context.getResources();
1073a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            return createIconBitmap(new BitmapDrawable(resources, icon), context);
108931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        }
109931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    }
110931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka
111931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    /**
112931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * Returns a bitmap suitable for the all apps view.
1136665c0f1fec6ec0962896622986340081df992e7Joe Onorato     */
1140589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    static Bitmap createIconBitmap(Drawable icon, Context context) {
1156665c0f1fec6ec0962896622986340081df992e7Joe Onorato        synchronized (sCanvas) { // we share the statics :-(
1166665c0f1fec6ec0962896622986340081df992e7Joe Onorato            if (sIconWidth == -1) {
1176665c0f1fec6ec0962896622986340081df992e7Joe Onorato                initStatics(context);
1186665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1196665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1206665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int width = sIconWidth;
1216665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int height = sIconHeight;
1226665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1236665c0f1fec6ec0962896622986340081df992e7Joe Onorato            if (icon instanceof PaintDrawable) {
1246665c0f1fec6ec0962896622986340081df992e7Joe Onorato                PaintDrawable painter = (PaintDrawable) icon;
1256665c0f1fec6ec0962896622986340081df992e7Joe Onorato                painter.setIntrinsicWidth(width);
1266665c0f1fec6ec0962896622986340081df992e7Joe Onorato                painter.setIntrinsicHeight(height);
1276665c0f1fec6ec0962896622986340081df992e7Joe Onorato            } else if (icon instanceof BitmapDrawable) {
1286665c0f1fec6ec0962896622986340081df992e7Joe Onorato                // Ensure the bitmap has a density.
1296665c0f1fec6ec0962896622986340081df992e7Joe Onorato                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
1306665c0f1fec6ec0962896622986340081df992e7Joe Onorato                Bitmap bitmap = bitmapDrawable.getBitmap();
1316665c0f1fec6ec0962896622986340081df992e7Joe Onorato                if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
1326665c0f1fec6ec0962896622986340081df992e7Joe Onorato                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
1336665c0f1fec6ec0962896622986340081df992e7Joe Onorato                }
1346665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1356665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int sourceWidth = icon.getIntrinsicWidth();
1366665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int sourceHeight = icon.getIntrinsicHeight();
137931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            if (sourceWidth > 0 && sourceHeight > 0) {
1385f8afe6280eae34620067696173e71943e1a30a3Winson Chung                // Scale the icon proportionally to the icon dimensions
1395f8afe6280eae34620067696173e71943e1a30a3Winson Chung                final float ratio = (float) sourceWidth / sourceHeight;
1405f8afe6280eae34620067696173e71943e1a30a3Winson Chung                if (sourceWidth > sourceHeight) {
1415f8afe6280eae34620067696173e71943e1a30a3Winson Chung                    height = (int) (width / ratio);
1425f8afe6280eae34620067696173e71943e1a30a3Winson Chung                } else if (sourceHeight > sourceWidth) {
1435f8afe6280eae34620067696173e71943e1a30a3Winson Chung                    width = (int) (height * ratio);
1446665c0f1fec6ec0962896622986340081df992e7Joe Onorato                }
1456665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1466665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1476665c0f1fec6ec0962896622986340081df992e7Joe Onorato            // no intrinsic size --> use default size
1486665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int textureWidth = sIconTextureWidth;
1496665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int textureHeight = sIconTextureHeight;
1506665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1516665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
1526665c0f1fec6ec0962896622986340081df992e7Joe Onorato                    Bitmap.Config.ARGB_8888);
1536665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final Canvas canvas = sCanvas;
1546665c0f1fec6ec0962896622986340081df992e7Joe Onorato            canvas.setBitmap(bitmap);
1556665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1566665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final int left = (textureWidth-width) / 2;
1576665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final int top = (textureHeight-height) / 2;
1586665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1593a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            @SuppressWarnings("all") // suppress dead code warning
1603a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            final boolean debug = false;
1613a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            if (debug) {
1626665c0f1fec6ec0962896622986340081df992e7Joe Onorato                // draw a big box for the icon for debugging
1636665c0f1fec6ec0962896622986340081df992e7Joe Onorato                canvas.drawColor(sColors[sColorIndex]);
1646665c0f1fec6ec0962896622986340081df992e7Joe Onorato                if (++sColorIndex >= sColors.length) sColorIndex = 0;
1656665c0f1fec6ec0962896622986340081df992e7Joe Onorato                Paint debugPaint = new Paint();
1666665c0f1fec6ec0962896622986340081df992e7Joe Onorato                debugPaint.setColor(0xffcccc00);
1676665c0f1fec6ec0962896622986340081df992e7Joe Onorato                canvas.drawRect(left, top, left+width, top+height, debugPaint);
1686665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1696665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1706665c0f1fec6ec0962896622986340081df992e7Joe Onorato            sOldBounds.set(icon.getBounds());
1716665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.setBounds(left, top, left+width, top+height);
1726665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.draw(canvas);
1736665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.setBounds(sOldBounds);
174aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen            canvas.setBitmap(null);
1756665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1766665c0f1fec6ec0962896622986340081df992e7Joe Onorato            return bitmap;
1776665c0f1fec6ec0962896622986340081df992e7Joe Onorato        }
1786665c0f1fec6ec0962896622986340081df992e7Joe Onorato    }
1796665c0f1fec6ec0962896622986340081df992e7Joe Onorato
18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Returns a Bitmap representing the thumbnail of the specified Bitmap.
18231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param bitmap The bitmap to get a thumbnail of.
18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
18531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
18631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return A thumbnail for the specified bitmap or the bitmap itself if the
18731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *         thumbnail could not be created.
18831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
1890589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
1909c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato        synchronized (sCanvas) { // we share the statics :-(
1919c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato            if (sIconWidth == -1) {
1926665c0f1fec6ec0962896622986340081df992e7Joe Onorato                initStatics(context);
1939c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato            }
19431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1950589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
1960589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato                return bitmap;
1970589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            } else {
1983a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                final Resources resources = context.getResources();
1993a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                return createIconBitmap(new BitmapDrawable(resources, bitmap), context);
20031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
20131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
20231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
203bf15cb44cc8e5ea9a19ab8aaee8e02c96bd6130cJoe Onorato
204c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    /**
205c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * Given a coordinate relative to the descendant, find the coordinate in a parent view's
206c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * coordinates.
207c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *
208c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param descendant The descendant to which the passed coordinate is relative.
209c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param root The root view to make the coordinates relative to.
210c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param coord The coordinate that we want mapped.
211c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param includeRootScroll Whether or not to account for the scroll of the descendant:
212c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *          sometimes this is relevant as in a child's coordinates within the descendant.
213c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
214c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
215c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *         assumption fails, we will need to return a pair of scale factors.
216c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     */
217c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    public static float getDescendantCoordRelativeToParent(View descendant, View root,
218c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                                                           int[] coord, boolean includeRootScroll) {
219c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ArrayList<View> ancestorChain = new ArrayList<View>();
220c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
221c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float[] pt = {coord[0], coord[1]};
222c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
223c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        View v = descendant;
224c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        while(v != root && v != null) {
225c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            ancestorChain.add(v);
226c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v = (View) v.getParent();
227c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
228c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ancestorChain.add(root);
229c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
230c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float scale = 1.0f;
231c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        int count = ancestorChain.size();
232c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        for (int i = 0; i < count; i++) {
233c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View v0 = ancestorChain.get(i);
234c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            // For TextViews, scroll has a meaning which relates to the text position
235c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            // which is very strange... ignore the scroll.
236c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            if (v0 != descendant || includeRootScroll) {
237c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[0] -= v0.getScrollX();
238c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[1] -= v0.getScrollY();
239c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            }
240c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
241c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v0.getMatrix().mapPoints(pt);
242c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[0] += v0.getLeft();
243c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[1] += v0.getTop();
244c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            scale *= v0.getScaleX();
245c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
246c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
247c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[0] = (int) Math.round(pt[0]);
248c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[1] = (int) Math.round(pt[1]);
249c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return scale;
250c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    }
251c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
252c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    /**
253c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
254c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     */
255c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    public static float mapCoordInSelfToDescendent(View descendant, View root,
256c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                                                   int[] coord) {
257c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ArrayList<View> ancestorChain = new ArrayList<View>();
258c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
259c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float[] pt = {coord[0], coord[1]};
260c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
261c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        View v = descendant;
262c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        while(v != root) {
263c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            ancestorChain.add(v);
264c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v = (View) v.getParent();
265c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
266c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ancestorChain.add(root);
267c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
268c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float scale = 1.0f;
269c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        Matrix inverse = new Matrix();
270c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        int count = ancestorChain.size();
271c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        for (int i = count - 1; i >= 0; i--) {
272c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View ancestor = ancestorChain.get(i);
273c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View next = i > 0 ? ancestorChain.get(i-1) : null;
274c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
275c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[0] += ancestor.getScrollX();
276c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[1] += ancestor.getScrollY();
277c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
278c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            if (next != null) {
279c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[0] -= next.getLeft();
280c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[1] -= next.getTop();
281c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                next.getMatrix().invert(inverse);
282c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                inverse.mapPoints(pt);
283c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                scale *= next.getScaleX();
284c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            }
285c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
286c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
287c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[0] = (int) Math.round(pt[0]);
288c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[1] = (int) Math.round(pt[1]);
289c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return scale;
290c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    }
291c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
2926665c0f1fec6ec0962896622986340081df992e7Joe Onorato    private static void initStatics(Context context) {
2936665c0f1fec6ec0962896622986340081df992e7Joe Onorato        final Resources resources = context.getResources();
2941291a8c236c84451321438cb68855f6f2eb24959Joe Onorato        final DisplayMetrics metrics = resources.getDisplayMetrics();
2951291a8c236c84451321438cb68855f6f2eb24959Joe Onorato        final float density = metrics.density;
2961291a8c236c84451321438cb68855f6f2eb24959Joe Onorato
297c9a961952d1a057029874f8426b90181f6876034Michael Jurka        sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
2984b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        sIconTextureWidth = sIconTextureHeight = sIconWidth;
2991291a8c236c84451321438cb68855f6f2eb24959Joe Onorato
300a4c0cb965575b7a0832d92bc0b33e06c7c66cb10Joe Onorato        sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
301eb8325a9e24cda47720152e1e95f5d86ab11f200Joe Onorato        sGlowColorPressedPaint.setColor(0xffffc300);
302c61cff9299a54599c2b214de7c819b6be0412f4eJoe Onorato        sGlowColorFocusedPaint.setColor(0xffff8e00);
30356d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato
30456d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato        ColorMatrix cm = new ColorMatrix();
30556d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato        cm.setSaturation(0.2f);
30656d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato        sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
30756d8291af6a28c6ba64113120efdf84a785e816cJoe Onorato        sDisabledPaint.setAlpha(0x88);
3086665c0f1fec6ec0962896622986340081df992e7Joe Onorato    }
3096665c0f1fec6ec0962896622986340081df992e7Joe Onorato
3105f8afe6280eae34620067696173e71943e1a30a3Winson Chung    public static void setIconSize(int widthPx) {
3115f8afe6280eae34620067696173e71943e1a30a3Winson Chung        sIconWidth = sIconHeight = widthPx;
3125f8afe6280eae34620067696173e71943e1a30a3Winson Chung        sIconTextureWidth = sIconTextureHeight = widthPx;
31397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
314a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka
3153a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    public static void scaleRect(Rect r, float scale) {
3163a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        if (scale != 1.0f) {
3173a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.left = (int) (r.left * scale + 0.5f);
3183a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.top = (int) (r.top * scale + 0.5f);
3193a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.right = (int) (r.right * scale + 0.5f);
3203a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.bottom = (int) (r.bottom * scale + 0.5f);
3213a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        }
3223a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    }
3233a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung
3243a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    public static void scaleRectAboutCenter(Rect r, float scale) {
3253a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        int cx = r.centerX();
3263a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        int cy = r.centerY();
3273a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        r.offset(-cx, -cy);
3283a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        Utilities.scaleRect(r, scale);
3293a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        r.offset(cx, cy);
3303a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    }
3313a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung
332a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka    public static void startActivityForResultSafely(
333a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Activity activity, Intent intent, int requestCode) {
334a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        try {
335a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            activity.startActivityForResult(intent, requestCode);
336a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        } catch (ActivityNotFoundException e) {
337a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
338a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        } catch (SecurityException e) {
339a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
340a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
341a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
342a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka                    "or use the exported attribute for this activity.", e);
343a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        }
344a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka    }
34531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
346