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;
21c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.ComponentName;
22aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.Context;
23a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.content.Intent;
24c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.ApplicationInfo;
25c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageInfo;
26c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageManager;
27c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException;
28c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.ResolveInfo;
29aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.Resources;
3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Bitmap;
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Canvas;
3295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyalimport android.graphics.Color;
33c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.graphics.Matrix;
3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Paint;
35bf15cb44cc8e5ea9a19ab8aaee8e02c96bd6130cJoe Onoratoimport android.graphics.PaintFlagsDrawFilter;
3631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect;
37aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.BitmapDrawable;
38aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.Drawable;
39aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.graphics.drawable.PaintDrawable;
402efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddharthaimport android.os.Build;
41a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.util.Log;
420fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.util.Pair;
4395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyalimport android.util.SparseArray;
44c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.view.View;
45a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.widget.Toast;
46c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
47c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport java.util.ArrayList;
4831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
4931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/**
5031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Various utilities shared amongst the Launcher's classes.
5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
5272fbec17e09a1120971621587d5005f683baafd1Mathew Inwoodpublic final class Utilities {
531291a8c236c84451321438cb68855f6f2eb24959Joe Onorato    private static final String TAG = "Launcher.Utilities";
541291a8c236c84451321438cb68855f6f2eb24959Joe Onorato
5531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static int sIconWidth = -1;
5631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static int sIconHeight = -1;
5761f560d92ab4b11a61beeb8df97b9952027e08e4Adam Cohen    public static int sIconTextureWidth = -1;
5861f560d92ab4b11a61beeb8df97b9952027e08e4Adam Cohen    public static int sIconTextureHeight = -1;
5931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    private static final Rect sOldBounds = new Rect();
6189911d2450f5db92d79e3bcefa9d324e9e8c4900Romain Guy    private static final Canvas sCanvas = new Canvas();
6231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
6331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    static {
6431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
6531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                Paint.FILTER_BITMAP_FLAG));
6631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
676665c0f1fec6ec0962896622986340081df992e7Joe Onorato    static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
686665c0f1fec6ec0962896622986340081df992e7Joe Onorato    static int sColorIndex = 0;
696665c0f1fec6ec0962896622986340081df992e7Joe Onorato
7063f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen    static int[] sLoc0 = new int[2];
7163f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen    static int[] sLoc1 = new int[2];
727ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka
737ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    // To turn on these properties, type
747ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
757ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
767ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
777ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka
786665c0f1fec6ec0962896622986340081df992e7Joe Onorato    /**
790dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     * Returns a FastBitmapDrawable with the icon, accurately sized.
800dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     */
81ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal    public static FastBitmapDrawable createIconDrawable(Bitmap icon) {
820dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        FastBitmapDrawable d = new FastBitmapDrawable(icon);
83540004905a555087e72691aad4479aa52ab5460eWinson Chung        d.setFilterBitmap(true);
840dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        resizeIconDrawable(d);
850dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        return d;
860dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    }
870dbd734384df38960515ce49dfcb5e15a394decaWinson Chung
880dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    /**
890dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     * Resizes an icon drawable to the correct icon size.
900dbd734384df38960515ce49dfcb5e15a394decaWinson Chung     */
910dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    static void resizeIconDrawable(Drawable icon) {
920dbd734384df38960515ce49dfcb5e15a394decaWinson Chung        icon.setBounds(0, 0, sIconTextureWidth, sIconTextureHeight);
930dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    }
940dbd734384df38960515ce49dfcb5e15a394decaWinson Chung
957ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    private static boolean isPropertyEnabled(String propertyName) {
967ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka        return Log.isLoggable(propertyName, Log.VERBOSE);
977ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    }
987ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka
997ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    public static boolean isRotationEnabled(Context c) {
1007ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka        boolean enableRotation = sForceEnableRotation ||
1017ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka                c.getResources().getBoolean(R.bool.allow_rotation);
1027ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka        return enableRotation;
1037ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka    }
1047ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka
1050dbd734384df38960515ce49dfcb5e15a394decaWinson Chung    /**
106d794a3f46521b972fa02826d379d1efa112793d2Kenny Guy     * Indicates if the device is running LMP or higher.
1072efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddhartha     */
108d794a3f46521b972fa02826d379d1efa112793d2Kenny Guy    public static boolean isLmpOrAbove() {
109d794a3f46521b972fa02826d379d1efa112793d2Kenny Guy        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.L;
1102efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddhartha    }
1112efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddhartha
1122efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddhartha    /**
113931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * Returns a bitmap suitable for the all apps view. Used to convert pre-ICS
114931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * icon bitmaps that are stored in the database (which were 74x74 pixels at hdpi size)
115931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * to the proper size (48dp)
116931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     */
117931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    static Bitmap createIconBitmap(Bitmap icon, Context context) {
118931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int textureWidth = sIconTextureWidth;
119931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int textureHeight = sIconTextureHeight;
120931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int sourceWidth = icon.getWidth();
121931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        int sourceHeight = icon.getHeight();
122931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        if (sourceWidth > textureWidth && sourceHeight > textureHeight) {
123931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is bigger than it should be; clip it (solves the GB->ICS migration case)
124931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            return Bitmap.createBitmap(icon,
125931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    (sourceWidth - textureWidth) / 2,
126931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    (sourceHeight - textureHeight) / 2,
127931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka                    textureWidth, textureHeight);
128931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        } else if (sourceWidth == textureWidth && sourceHeight == textureHeight) {
129931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is the right size, no need to change it
130931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            return icon;
131931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        } else {
132931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            // Icon is too small, render to a larger bitmap
1333a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            final Resources resources = context.getResources();
1343a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            return createIconBitmap(new BitmapDrawable(resources, icon), context);
135931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka        }
136931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    }
137931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka
138931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka    /**
139931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka     * Returns a bitmap suitable for the all apps view.
1406665c0f1fec6ec0962896622986340081df992e7Joe Onorato     */
14172fbec17e09a1120971621587d5005f683baafd1Mathew Inwood    public static Bitmap createIconBitmap(Drawable icon, Context context) {
1426665c0f1fec6ec0962896622986340081df992e7Joe Onorato        synchronized (sCanvas) { // we share the statics :-(
1436665c0f1fec6ec0962896622986340081df992e7Joe Onorato            if (sIconWidth == -1) {
1446665c0f1fec6ec0962896622986340081df992e7Joe Onorato                initStatics(context);
1456665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1466665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1476665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int width = sIconWidth;
1486665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int height = sIconHeight;
1496665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1506665c0f1fec6ec0962896622986340081df992e7Joe Onorato            if (icon instanceof PaintDrawable) {
1516665c0f1fec6ec0962896622986340081df992e7Joe Onorato                PaintDrawable painter = (PaintDrawable) icon;
1526665c0f1fec6ec0962896622986340081df992e7Joe Onorato                painter.setIntrinsicWidth(width);
1536665c0f1fec6ec0962896622986340081df992e7Joe Onorato                painter.setIntrinsicHeight(height);
1546665c0f1fec6ec0962896622986340081df992e7Joe Onorato            } else if (icon instanceof BitmapDrawable) {
1556665c0f1fec6ec0962896622986340081df992e7Joe Onorato                // Ensure the bitmap has a density.
1566665c0f1fec6ec0962896622986340081df992e7Joe Onorato                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
1576665c0f1fec6ec0962896622986340081df992e7Joe Onorato                Bitmap bitmap = bitmapDrawable.getBitmap();
1586665c0f1fec6ec0962896622986340081df992e7Joe Onorato                if (bitmap.getDensity() == Bitmap.DENSITY_NONE) {
1596665c0f1fec6ec0962896622986340081df992e7Joe Onorato                    bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics());
1606665c0f1fec6ec0962896622986340081df992e7Joe Onorato                }
1616665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1626665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int sourceWidth = icon.getIntrinsicWidth();
1636665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int sourceHeight = icon.getIntrinsicHeight();
164931dc9779dab5071efc21163647f5f004991bfb3Michael Jurka            if (sourceWidth > 0 && sourceHeight > 0) {
1655f8afe6280eae34620067696173e71943e1a30a3Winson Chung                // Scale the icon proportionally to the icon dimensions
1665f8afe6280eae34620067696173e71943e1a30a3Winson Chung                final float ratio = (float) sourceWidth / sourceHeight;
1675f8afe6280eae34620067696173e71943e1a30a3Winson Chung                if (sourceWidth > sourceHeight) {
1685f8afe6280eae34620067696173e71943e1a30a3Winson Chung                    height = (int) (width / ratio);
1695f8afe6280eae34620067696173e71943e1a30a3Winson Chung                } else if (sourceHeight > sourceWidth) {
1705f8afe6280eae34620067696173e71943e1a30a3Winson Chung                    width = (int) (height * ratio);
1716665c0f1fec6ec0962896622986340081df992e7Joe Onorato                }
1726665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1736665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1746665c0f1fec6ec0962896622986340081df992e7Joe Onorato            // no intrinsic size --> use default size
1756665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int textureWidth = sIconTextureWidth;
1766665c0f1fec6ec0962896622986340081df992e7Joe Onorato            int textureHeight = sIconTextureHeight;
1776665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1786665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
1796665c0f1fec6ec0962896622986340081df992e7Joe Onorato                    Bitmap.Config.ARGB_8888);
1806665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final Canvas canvas = sCanvas;
1816665c0f1fec6ec0962896622986340081df992e7Joe Onorato            canvas.setBitmap(bitmap);
1826665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1836665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final int left = (textureWidth-width) / 2;
1846665c0f1fec6ec0962896622986340081df992e7Joe Onorato            final int top = (textureHeight-height) / 2;
1856665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1863a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            @SuppressWarnings("all") // suppress dead code warning
1873a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            final boolean debug = false;
1883a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka            if (debug) {
1896665c0f1fec6ec0962896622986340081df992e7Joe Onorato                // draw a big box for the icon for debugging
1906665c0f1fec6ec0962896622986340081df992e7Joe Onorato                canvas.drawColor(sColors[sColorIndex]);
1916665c0f1fec6ec0962896622986340081df992e7Joe Onorato                if (++sColorIndex >= sColors.length) sColorIndex = 0;
1926665c0f1fec6ec0962896622986340081df992e7Joe Onorato                Paint debugPaint = new Paint();
1936665c0f1fec6ec0962896622986340081df992e7Joe Onorato                debugPaint.setColor(0xffcccc00);
1946665c0f1fec6ec0962896622986340081df992e7Joe Onorato                canvas.drawRect(left, top, left+width, top+height, debugPaint);
1956665c0f1fec6ec0962896622986340081df992e7Joe Onorato            }
1966665c0f1fec6ec0962896622986340081df992e7Joe Onorato
1976665c0f1fec6ec0962896622986340081df992e7Joe Onorato            sOldBounds.set(icon.getBounds());
1986665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.setBounds(left, top, left+width, top+height);
1996665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.draw(canvas);
2006665c0f1fec6ec0962896622986340081df992e7Joe Onorato            icon.setBounds(sOldBounds);
201aaf473c2bb6329b3b09ed2e19de6aae26077050cAdam Cohen            canvas.setBitmap(null);
2026665c0f1fec6ec0962896622986340081df992e7Joe Onorato
2036665c0f1fec6ec0962896622986340081df992e7Joe Onorato            return bitmap;
2046665c0f1fec6ec0962896622986340081df992e7Joe Onorato        }
2056665c0f1fec6ec0962896622986340081df992e7Joe Onorato    }
2066665c0f1fec6ec0962896622986340081df992e7Joe Onorato
20731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    /**
20831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * Returns a Bitmap representing the thumbnail of the specified Bitmap.
20931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
21031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param bitmap The bitmap to get a thumbnail of.
21131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @param context The application's context.
21231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *
21331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     * @return A thumbnail for the specified bitmap or the bitmap itself if the
21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     *         thumbnail could not be created.
21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project     */
2160589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato    static Bitmap resampleIconBitmap(Bitmap bitmap, Context context) {
2179c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato        synchronized (sCanvas) { // we share the statics :-(
2189c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato            if (sIconWidth == -1) {
2196665c0f1fec6ec0962896622986340081df992e7Joe Onorato                initStatics(context);
2209c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato            }
22131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2220589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            if (bitmap.getWidth() == sIconWidth && bitmap.getHeight() == sIconHeight) {
2230589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato                return bitmap;
2240589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato            } else {
2253a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                final Resources resources = context.getResources();
2263a9fcedbcd235372cd2ab64f825a0b5b3937f59eMichael Jurka                return createIconBitmap(new BitmapDrawable(resources, bitmap), context);
22731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
22831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
22931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
230bf15cb44cc8e5ea9a19ab8aaee8e02c96bd6130cJoe Onorato
231c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    /**
232c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * Given a coordinate relative to the descendant, find the coordinate in a parent view's
233c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * coordinates.
234c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *
235c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param descendant The descendant to which the passed coordinate is relative.
236c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param root The root view to make the coordinates relative to.
237c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param coord The coordinate that we want mapped.
238c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @param includeRootScroll Whether or not to account for the scroll of the descendant:
239c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *          sometimes this is relevant as in a child's coordinates within the descendant.
240c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
241c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
242c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     *         assumption fails, we will need to return a pair of scale factors.
243c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     */
244c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    public static float getDescendantCoordRelativeToParent(View descendant, View root,
245c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                                                           int[] coord, boolean includeRootScroll) {
246c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ArrayList<View> ancestorChain = new ArrayList<View>();
247c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
248c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float[] pt = {coord[0], coord[1]};
249c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
250c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        View v = descendant;
251c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        while(v != root && v != null) {
252c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            ancestorChain.add(v);
253c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v = (View) v.getParent();
254c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
255c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ancestorChain.add(root);
256c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
257c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float scale = 1.0f;
258c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        int count = ancestorChain.size();
259c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        for (int i = 0; i < count; i++) {
260c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View v0 = ancestorChain.get(i);
261c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            // For TextViews, scroll has a meaning which relates to the text position
262c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            // which is very strange... ignore the scroll.
263c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            if (v0 != descendant || includeRootScroll) {
264c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[0] -= v0.getScrollX();
265c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[1] -= v0.getScrollY();
266c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            }
267c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
268c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v0.getMatrix().mapPoints(pt);
269c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[0] += v0.getLeft();
270c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[1] += v0.getTop();
271c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            scale *= v0.getScaleX();
272c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
273c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
274c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[0] = (int) Math.round(pt[0]);
275c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[1] = (int) Math.round(pt[1]);
276c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return scale;
277c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    }
278c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
279c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    /**
280c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
281c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung     */
282c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    public static float mapCoordInSelfToDescendent(View descendant, View root,
283c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                                                   int[] coord) {
284c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ArrayList<View> ancestorChain = new ArrayList<View>();
285c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
286c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float[] pt = {coord[0], coord[1]};
287c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
288c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        View v = descendant;
289c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        while(v != root) {
290c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            ancestorChain.add(v);
291c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            v = (View) v.getParent();
292c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
293c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        ancestorChain.add(root);
294c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
295c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        float scale = 1.0f;
296c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        Matrix inverse = new Matrix();
297c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        int count = ancestorChain.size();
298c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        for (int i = count - 1; i >= 0; i--) {
299c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View ancestor = ancestorChain.get(i);
300c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            View next = i > 0 ? ancestorChain.get(i-1) : null;
301c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
302c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[0] += ancestor.getScrollX();
303c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            pt[1] += ancestor.getScrollY();
304c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
305c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            if (next != null) {
306c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[0] -= next.getLeft();
307c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                pt[1] -= next.getTop();
308c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                next.getMatrix().invert(inverse);
309c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                inverse.mapPoints(pt);
310c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung                scale *= next.getScaleX();
311c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung            }
312c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        }
313c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
314c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[0] = (int) Math.round(pt[0]);
315c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        coord[1] = (int) Math.round(pt[1]);
316c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung        return scale;
317c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung    }
318c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung
31902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    /**
32002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk     * Utility method to determine whether the given point, in local coordinates,
32102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk     * is inside the view, where the area of the view is expanded by the slop factor.
32202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk     * This method is called while processing touch-move events to determine if the event
32302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk     * is still within the view.
32402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk     */
32502dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    public static boolean pointInView(View v, float localX, float localY, float slop) {
32602dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk        return localX >= -slop && localY >= -slop && localX < (v.getWidth() + slop) &&
32702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk                localY < (v.getHeight() + slop);
32802dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk    }
32902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk
3306665c0f1fec6ec0962896622986340081df992e7Joe Onorato    private static void initStatics(Context context) {
3316665c0f1fec6ec0962896622986340081df992e7Joe Onorato        final Resources resources = context.getResources();
332c9a961952d1a057029874f8426b90181f6876034Michael Jurka        sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
3334b825dcd5f64a5ebb60271844fbc5257374422bcWinson Chung        sIconTextureWidth = sIconTextureHeight = sIconWidth;
3346665c0f1fec6ec0962896622986340081df992e7Joe Onorato    }
3356665c0f1fec6ec0962896622986340081df992e7Joe Onorato
3365f8afe6280eae34620067696173e71943e1a30a3Winson Chung    public static void setIconSize(int widthPx) {
3375f8afe6280eae34620067696173e71943e1a30a3Winson Chung        sIconWidth = sIconHeight = widthPx;
3385f8afe6280eae34620067696173e71943e1a30a3Winson Chung        sIconTextureWidth = sIconTextureHeight = widthPx;
33997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
340a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka
3413a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    public static void scaleRect(Rect r, float scale) {
3423a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        if (scale != 1.0f) {
3433a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.left = (int) (r.left * scale + 0.5f);
3443a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.top = (int) (r.top * scale + 0.5f);
3453a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.right = (int) (r.right * scale + 0.5f);
3463a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung            r.bottom = (int) (r.bottom * scale + 0.5f);
3473a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        }
3483a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    }
3493a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung
35063f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen    public static int[] getCenterDeltaInScreenSpace(View v0, View v1, int[] delta) {
35163f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        v0.getLocationInWindow(sLoc0);
35263f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        v1.getLocationInWindow(sLoc1);
35363f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen
35463f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        sLoc0[0] += (v0.getMeasuredWidth() * v0.getScaleX()) / 2;
35563f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        sLoc0[1] += (v0.getMeasuredHeight() * v0.getScaleY()) / 2;
35663f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        sLoc1[0] += (v1.getMeasuredWidth() * v1.getScaleX()) / 2;
35763f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        sLoc1[1] += (v1.getMeasuredHeight() * v1.getScaleY()) / 2;
35863f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen
35963f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        if (delta == null) {
36063f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen            delta = new int[2];
36163f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        }
36263f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen
36363f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        delta[0] = sLoc1[0] - sLoc0[0];
36463f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        delta[1] = sLoc1[1] - sLoc0[1];
36563f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen
36663f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen        return delta;
36763f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen    }
36863f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen
3693a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    public static void scaleRectAboutCenter(Rect r, float scale) {
3703a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        int cx = r.centerX();
3713a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        int cy = r.centerY();
3723a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        r.offset(-cx, -cy);
3733a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        Utilities.scaleRect(r, scale);
3743a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung        r.offset(cx, cy);
3753a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung    }
3763a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung
377a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka    public static void startActivityForResultSafely(
378a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Activity activity, Intent intent, int requestCode) {
379a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        try {
380a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            activity.startActivityForResult(intent, requestCode);
381a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        } catch (ActivityNotFoundException e) {
382a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
383a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        } catch (SecurityException e) {
384a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
385a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
386a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
387a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka                    "or use the exported attribute for this activity.", e);
388a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka        }
389a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurka    }
390c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal
391c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal    static boolean isSystemApp(Context context, Intent intent) {
392c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        PackageManager pm = context.getPackageManager();
393c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        ComponentName cn = intent.getComponent();
394c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        String packageName = null;
395c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        if (cn == null) {
396c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
397c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            if ((info != null) && (info.activityInfo != null)) {
398c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                packageName = info.activityInfo.packageName;
399c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            }
400c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        } else {
401c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            packageName = cn.getPackageName();
402c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        }
403c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        if (packageName != null) {
404c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            try {
405c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                PackageInfo info = pm.getPackageInfo(packageName, 0);
406c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                return (info != null) && (info.applicationInfo != null) &&
407c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                        ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
408c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            } catch (NameNotFoundException e) {
409c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal                return false;
410c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            }
411c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        } else {
412c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal            return false;
413c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal        }
414c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal    }
41595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
41695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal    /**
41795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal     * This picks a dominant color, looking for high-saturation, high-value, repeated hues.
41895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal     * @param bitmap The bitmap to scan
41995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal     * @param samples The approximate max number of samples to use.
42095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal     */
42195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal    static int findDominantColorByHue(Bitmap bitmap, int samples) {
42295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        final int height = bitmap.getHeight();
42395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        final int width = bitmap.getWidth();
42495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        int sampleStride = (int) Math.sqrt((height * width) / samples);
42595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        if (sampleStride < 1) {
42695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            sampleStride = 1;
42795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        }
42895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
42995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // This is an out-param, for getting the hsv values for an rgb
43095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        float[] hsv = new float[3];
43195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
43295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // First get the best hue, by creating a histogram over 360 hue buckets,
43395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // where each pixel contributes a score weighted by saturation, value, and alpha.
43495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        float[] hueScoreHistogram = new float[360];
43595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        float highScore = -1;
43695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        int bestHue = -1;
43795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
43895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        for (int y = 0; y < height; y += sampleStride) {
43995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            for (int x = 0; x < width; x += sampleStride) {
44095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int argb = bitmap.getPixel(x, y);
44195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int alpha = 0xFF & (argb >> 24);
44295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                if (alpha < 0x80) {
44395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    // Drop mostly-transparent pixels.
44495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    continue;
44595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                }
44695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                // Remove the alpha channel.
44795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int rgb = argb | 0xFF000000;
44895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                Color.colorToHSV(rgb, hsv);
44995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                // Bucket colors by the 360 integer hues.
45095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int hue = (int) hsv[0];
45195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                if (hue < 0 || hue >= hueScoreHistogram.length) {
45295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    // Defensively avoid array bounds violations.
45395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    continue;
45495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                }
45595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                float score = hsv[1] * hsv[2];
45695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                hueScoreHistogram[hue] += score;
45795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                if (hueScoreHistogram[hue] > highScore) {
45895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    highScore = hueScoreHistogram[hue];
45995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    bestHue = hue;
46095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                }
46195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
46295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        }
46395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal
46495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        SparseArray<Float> rgbScores = new SparseArray<Float>();
46595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        int bestColor = 0xff000000;
46695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        highScore = -1;
46795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // Go back over the RGB colors that match the winning hue,
46895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets.
46995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        // The highest-scoring RGB color wins.
47095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        for (int y = 0; y < height; y += sampleStride) {
47195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            for (int x = 0; x < width; x += sampleStride) {
47295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int rgb = bitmap.getPixel(x, y) | 0xff000000;
47395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                Color.colorToHSV(rgb, hsv);
47495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                int hue = (int) hsv[0];
47595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                if (hue == bestHue) {
47695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    float s = hsv[1];
47795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    float v = hsv[2];
47895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    int bucket = (int) (s * 100) + (int) (v * 10000);
47995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    // Score by cumulative saturation * value.
48095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    float score = s * v;
48195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    Float oldTotal = rgbScores.get(bucket);
48295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    float newTotal = oldTotal == null ? score : oldTotal + score;
48395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    rgbScores.put(bucket, newTotal);
48495abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    if (newTotal > highScore) {
48595abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                        highScore = newTotal;
48695abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                        // All the colors in the winning bucket are very similar. Last in wins.
48795abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                        bestColor = rgb;
48895abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                    }
48995abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal                }
49095abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal            }
49195abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        }
49295abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal        return bestColor;
49395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal    }
4940fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal
4950fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    /*
4960fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * Finds a system apk which had a broadcast receiver listening to a particular action.
4970fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * @param action intent action used to find the apk
4980fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     * @return a pair of apk package name and the resources.
4990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal     */
5000fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    static Pair<String, Resources> findSystemApk(String action, PackageManager pm) {
5010fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        final Intent intent = new Intent(action);
5020fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) {
5030fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            if (info.activityInfo != null &&
5040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
5050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                final String packageName = info.activityInfo.packageName;
5060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                try {
5070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    final Resources res = pm.getResourcesForApplication(packageName);
5080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    return Pair.create(packageName, res);
5090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                } catch (NameNotFoundException e) {
5100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                    Log.w(TAG, "Failed to find resources for " + packageName);
5110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal                }
5120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal            }
5130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        }
5140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal        return null;
5150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal    }
51631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
517