Merging Motorola's patch to disable apps when is safe mode.

issue: 16044192

Change-Id: I10069dcdf459ecc71361271e883eabb743d77822
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3bf6c8d..508c0e0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -34,6 +34,8 @@
     <string name="folder_name"></string>
     <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]-->
     <string name="activity_not_found">App isn\'t installed.</string>
+    <!-- SafeMode shortcut error string -->
+    <string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
     <!--  Labels for the tabs in the customize drawer -->
     <string name="widgets_tab_label">Widgets</string>
 
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 3f619a8..ffa7ec3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -51,8 +51,6 @@
 
     private static final boolean DEBUG = false;
 
-    private int mPrevAlpha = -1;
-
     private HolographicOutlineHelper mOutlineHelper;
     private final Canvas mTempCanvas = new Canvas();
     private final Rect mTempRect = new Rect();
@@ -124,14 +122,22 @@
         }
     }
 
-    public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
+    public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
+            boolean setDefaultPadding) {
         Bitmap b = info.getIcon(iconCache);
         LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
 
-        Drawable iconDrawable = Utilities.createIconDrawable(b);
+        FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
+        if (info.isDisabled) {
+            iconDrawable.setSaturation(0);
+            iconDrawable.setBrightness(20);
+        }
+
         setCompoundDrawables(null, iconDrawable, null, null);
-        setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+        if (setDefaultPadding) {
+            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+            setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+        }
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
         }
@@ -417,10 +423,6 @@
 
     @Override
     protected boolean onSetAlpha(int alpha) {
-        if (mPrevAlpha != alpha) {
-            mPrevAlpha = alpha;
-            super.onSetAlpha(alpha);
-        }
         return true;
     }
 
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 85e9020..ef8d097 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -19,15 +19,24 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 
 class FastBitmapDrawable extends Drawable {
+
+    private static final ColorMatrix sTempSaturationMatrix = new ColorMatrix();
+    private static final ColorMatrix sTempBrightnessMatrix = new ColorMatrix();
+
+    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
     private Bitmap mBitmap;
     private int mAlpha;
-    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+    private float mSatutation = 1;
+    private int mBrightness = 0;
 
     FastBitmapDrawable(Bitmap b) {
         mAlpha = 255;
@@ -44,7 +53,7 @@
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mPaint.setColorFilter(cf);
+        // No op
     }
 
     @Override
@@ -58,6 +67,7 @@
         mPaint.setAlpha(alpha);
     }
 
+    @Override
     public void setFilterBitmap(boolean filterBitmap) {
         mPaint.setFilterBitmap(filterBitmap);
         mPaint.setAntiAlias(filterBitmap);
@@ -90,4 +100,51 @@
     public Bitmap getBitmap() {
         return mBitmap;
     }
+
+    public float getSaturation() {
+        return mSatutation;
+    }
+
+    public void setSaturation(float saturation) {
+        mSatutation = saturation;
+        updateFilter();
+    }
+
+    public int getBrightness() {
+        return mBrightness;
+    }
+
+    public void addBrightness(int amount) {
+        mBrightness += amount;
+        updateFilter();
+    }
+
+    public void setBrightness(int brightness) {
+        mBrightness = brightness;
+        updateFilter();
+    }
+
+    private void updateFilter() {
+        if (mSatutation != 1 || mBrightness != 0) {
+            sTempSaturationMatrix.setSaturation(mSatutation);
+
+            if (mBrightness != 0) {
+                // Brightness: C-new = C-old*(1-amount) + amount
+                float scale = 1 - mBrightness / 255.0f;
+                sTempBrightnessMatrix.setScale(scale, scale, scale, 1);
+                float[] array = sTempBrightnessMatrix.getArray();
+
+                // Add the amount to RGB components of the matrix, as per the above formula.
+                // Fifth elements in the array correspond to the constant being added to
+                // red, blue, green, and alpha channel respectively.
+                array[4] = mBrightness;
+                array[9] = mBrightness;
+                array[14] = mBrightness;
+                sTempSaturationMatrix.preConcat(sTempBrightnessMatrix);
+            }
+            mPaint.setColorFilter(new ColorMatrixColorFilter(sTempSaturationMatrix));
+        } else {
+            mPaint.setColorFilter(null);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 47c8a4a..655e5c3 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -566,15 +566,10 @@
     }
 
     protected View createAndAddShortcut(ShortcutInfo item) {
-        final TextView textView =
-            (TextView) mInflater.inflate(R.layout.folder_application, this, false);
-        textView.setCompoundDrawables(null,
-                Utilities.createIconDrawable(item.getIcon(mIconCache)), null, null);
-        textView.setText(item.title);
-        if (item.contentDescription != null) {
-            textView.setContentDescription(item.contentDescription);
-        }
-        textView.setTag(item);
+        final BubbleTextView textView =
+            (BubbleTextView) mInflater.inflate(R.layout.folder_application, this, false);
+        textView.applyFromShortcutInfo(item, mIconCache, false);
+
         textView.setOnClickListener(this);
         textView.setOnLongClickListener(this);
 
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index 4f674f5..4cf336f 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -580,10 +580,17 @@
         if (d != null) {
             mOldBounds.set(d.getBounds());
             d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize);
-            d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
-                    PorterDuff.Mode.SRC_ATOP);
-            d.draw(canvas);
-            d.clearColorFilter();
+            if (d instanceof FastBitmapDrawable) {
+                FastBitmapDrawable fd = (FastBitmapDrawable) d;
+                fd.addBrightness(params.overlayAlpha);
+                d.draw(canvas);
+                fd.addBrightness(-params.overlayAlpha);
+            } else {
+                d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255),
+                        PorterDuff.Mode.SRC_ATOP);
+                d.draw(canvas);
+                d.clearColorFilter();
+            }
             d.setBounds(mOldBounds);
         }
         canvas.restore();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 951b5d4..a5ca298 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -218,6 +218,8 @@
     private State mState = State.WORKSPACE;
     private AnimatorSet mStateAnimation;
 
+    private boolean mIsSafeModeEnabled;
+
     static final int APPWIDGET_HOST_ID = 1024;
     public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
     private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@@ -421,6 +423,7 @@
         // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet
         mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
                 Context.MODE_PRIVATE);
+        mIsSafeModeEnabled = getPackageManager().isSafeMode();
         mModel = app.setLauncher(this);
         mIconCache = app.getIconCache();
         mIconCache.flushInvalidIcons(grid);
@@ -1395,7 +1398,7 @@
      */
     View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
         BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
-        favorite.applyFromShortcutInfo(info, mIconCache);
+        favorite.applyFromShortcutInfo(info, mIconCache, true);
         favorite.setOnClickListener(this);
         return favorite;
     }
@@ -2775,6 +2778,7 @@
                 // Could be launching some bookkeeping activity
                 startActivity(intent, optsBundle);
             } else {
+                // TODO Component can be null when shortcuts are supported for secondary user
                 launcherApps.startActivityForProfile(intent.getComponent(), user,
                         intent.getSourceBounds(), optsBundle);
             }
@@ -2791,6 +2795,10 @@
 
     boolean startActivitySafely(View v, Intent intent, Object tag) {
         boolean success = false;
+        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
+            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
+            return false;
+        }
         try {
             success = startActivity(v, intent, tag);
         } catch (ActivityNotFoundException e) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index b01db71..a8bace8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2047,6 +2047,8 @@
                                     info.spanX = 1;
                                     info.spanY = 1;
                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+                                    info.isDisabled = isSafeMode
+                                            && !Utilities.isSystemApp(context, intent);
 
                                     // check & update map of what's occupied
                                     deleteOnInvalidPlacement.set(false);
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 7e1f0d6..266e9e0 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -79,6 +79,12 @@
     private Bitmap mIcon;
 
     /**
+     * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
+     * sd-card is not available).
+     */
+    boolean isDisabled = false;
+
+    /**
      * The installation state of the package that this shortcut represents.
      */
     protected int mState;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 74b6e47..0a711c5 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -18,14 +18,17 @@
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
@@ -52,10 +55,6 @@
     public static int sIconTextureWidth = -1;
     public static int sIconTextureHeight = -1;
 
-    private static final Paint sBlurPaint = new Paint();
-    private static final Paint sGlowColorPressedPaint = new Paint();
-    private static final Paint sGlowColorFocusedPaint = new Paint();
-    private static final Paint sDisabledPaint = new Paint();
     private static final Rect sOldBounds = new Rect();
     private static final Canvas sCanvas = new Canvas();
 
@@ -75,7 +74,7 @@
     /**
      * Returns a FastBitmapDrawable with the icon, accurately sized.
      */
-    static Drawable createIconDrawable(Bitmap icon) {
+    static FastBitmapDrawable createIconDrawable(Bitmap icon) {
         FastBitmapDrawable d = new FastBitmapDrawable(icon);
         d.setFilterBitmap(true);
         resizeIconDrawable(d);
@@ -332,15 +331,6 @@
 
         sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
         sIconTextureWidth = sIconTextureHeight = sIconWidth;
-
-        sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL));
-        sGlowColorPressedPaint.setColor(0xffffc300);
-        sGlowColorFocusedPaint.setColor(0xffff8e00);
-
-        ColorMatrix cm = new ColorMatrix();
-        cm.setSaturation(0.2f);
-        sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm));
-        sDisabledPaint.setAlpha(0x88);
     }
 
     public static void setIconSize(int widthPx) {
@@ -378,4 +368,29 @@
                     "or use the exported attribute for this activity.", e);
         }
     }
+
+    static boolean isSystemApp(Context context, Intent intent) {
+        PackageManager pm = context.getPackageManager();
+        ComponentName cn = intent.getComponent();
+        String packageName = null;
+        if (cn == null) {
+            ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+            if ((info != null) && (info.activityInfo != null)) {
+                packageName = info.activityInfo.packageName;
+            }
+        } else {
+            packageName = cn.getPackageName();
+        }
+        if (packageName != null) {
+            try {
+                PackageInfo info = pm.getPackageInfo(packageName, 0);
+                return (info != null) && (info.applicationInfo != null) &&
+                        ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+            } catch (NameNotFoundException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a8e7580..eb7fc36 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -4790,7 +4790,7 @@
                 shortcutInfo.updateIcon(mIconCache);
                 shortcutInfo.title = appInfo.title.toString();
                 shortcutInfo.contentDescription = appInfo.contentDescription;
-                shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);
+                shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true);
             }
         }
     }