On disabled app pairs, set color tint instead of changing alpha

This CL changes the way disabled app pair icons are drawn: instead of setting alpha, it sets a color filter to indicate disabled status. This brings it in line with other apps icons and V's design specs.

Fixes: 326665140
Flag: ACONFIG com.android.wm.shell.enable_app_pairs TRUNKFOOD
Test: Manual
Change-Id: Ifc8ac694f321a6b28996ba9a42860dfc419d5901
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 48d0fbd..c11193a 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.apppairs;
 
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -94,17 +93,18 @@
         icon.setOnClickListener(activity.getItemOnClickListener());
         icon.mInfo = appPairInfo;
 
+        // TODO (b/326664798): Delete this check, instead check at launcher load time
         if (icon.mInfo.contents.size() != 2) {
             Log.wtf(TAG, "AppPair contents not 2, size: " + icon.mInfo.contents.size());
             return icon;
         }
 
-        icon.checkScreenSize();
-
         // Set up icon drawable area
         icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
         icon.mIconGraphic.init(activity.getDeviceProfile(), icon);
 
+        icon.checkDisabledState();
+
         // Set up app pair title
         icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
         icon.mAppPairName.setCompoundDrawablePadding(0);
@@ -183,23 +183,20 @@
     }
 
     /**
-     * Checks if the app pair is launchable in the current device configuration.
-     *
+     * Updates the "disabled" state of the app pair in the current device configuration.
      * App pairs can be "disabled" in two ways:
      * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused
-     * by the user or can't be launched).
+     * by the user or can't be launched for some other reason).
      * 2) This specific instance of an app pair can't be launched due to screen size requirements.
-     *
-     * This method checks and updates #2. Both #1 and #2 are checked when app pairs are drawn
-     * {@link AppPairIconGraphic#dispatchDraw(Canvas)} or clicked on
-     * {@link com.android.launcher3.touch.ItemClickHandler#onClickAppPairIcon(View)}
      */
-    public void checkScreenSize() {
+    public void checkDisabledState() {
         DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
         // If user is on a small screen, we can't launch if either of the apps is non-resizeable
         mIsLaunchableAtScreenSize =
                 dp.isTablet || getInfo().contents.stream().noneMatch(
                         wii -> wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE));
+        // Call applyIcons to check and update icons
+        mIconGraphic.applyIcons();
     }
 
     /**
@@ -209,7 +206,7 @@
         // If either of the app pair icons return true on the predicate (i.e. in the list of
         // updated apps), redraw the icon graphic (icon background and both icons).
         if (getInfo().contents.stream().anyMatch(itemCheck)) {
-            checkScreenSize();
+            checkDisabledState();
             mIconGraphic.invalidate();
         }
     }
diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
index b5011f1..187541f 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconBackground.java
+++ b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
@@ -162,6 +162,6 @@
 
     @Override
     public void setColorFilter(ColorFilter colorFilter) {
-        // Required by Drawable but not used.
+        mBackgroundPaint.setColorFilter(colorFilter);
     }
 }
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index 365edf8..c12aa0c 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -26,8 +26,8 @@
 import android.widget.FrameLayout
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.icons.BitmapInfo
-import com.android.launcher3.icons.PlaceHolderIconDrawable
-import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.icons.FastBitmapDrawable
+import com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter
 import com.android.launcher3.util.Themes
 
 /**
@@ -46,9 +46,6 @@
         private const val CENTER_CHANNEL_SCALE = 1 / 30f
         private const val BIG_RADIUS_SCALE = 1 / 5f
         private const val SMALL_RADIUS_SCALE = 1 / 15f
-        // Disabled alpha is 38%, or 97/255
-        private const val DISABLED_ALPHA = 97
-        private const val ENABLED_ALPHA = 255
     }
 
     // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
@@ -71,8 +68,8 @@
 
     private lateinit var parentIcon: AppPairIcon
     private lateinit var appPairBackground: Drawable
-    private var appIcon1: Drawable? = null
-    private var appIcon2: Drawable? = null
+    private lateinit var appIcon1: FastBitmapDrawable
+    private lateinit var appIcon2: FastBitmapDrawable
 
     fun init(grid: DeviceProfile, icon: AppPairIcon) {
         // Calculate device-specific measurements
@@ -89,7 +86,8 @@
 
         appPairBackground = AppPairIconBackground(context, this)
         appPairBackground.setBounds(0, 0, backgroundSize.toInt(), backgroundSize.toInt())
-        applyIcons(parentIcon.info.contents)
+
+        applyIcons()
 
         // Center the drawable area in the larger icon canvas
         val lp: LayoutParams = layoutParams as LayoutParams
@@ -101,26 +99,29 @@
     }
 
     /** Sets up app pair member icons for drawing. */
-    private fun applyIcons(contents: ArrayList<WorkspaceItemInfo>) {
-        // App pair should always contain 2 members; if not 2, return to avoid a crash loop
-        if (contents.size != 2) {
-            Log.wtf(TAG, "AppPair contents not 2, size: " + contents.size, Throwable())
+    fun applyIcons() {
+        val apps = parentIcon.info.contents
+
+        // TODO (b/326664798): Delete this check, instead check at launcher load time
+        if (apps.size != 2) {
+            Log.wtf(TAG, "AppPair contents not 2, size: " + apps.size, Throwable())
             return
         }
 
         // Generate new icons, using themed flag if needed
         val flags = if (Themes.isThemedIconEnabled(context)) BitmapInfo.FLAG_THEMED else 0
-        val newIcon1 = parentIcon.info.contents[0].newIcon(context, flags)
-        val newIcon2 = parentIcon.info.contents[1].newIcon(context, flags)
+        appIcon1 = apps[0].newIcon(context, flags)
+        appIcon2 = apps[1].newIcon(context, flags)
+        appIcon1.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
+        appIcon2.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
 
-        // If app icons did not draw fully last time, animate to full icon
-        (appIcon1 as? PlaceHolderIconDrawable)?.animateIconUpdate(newIcon1)
-        (appIcon2 as? PlaceHolderIconDrawable)?.animateIconUpdate(newIcon2)
+        // Check disabled state
+        val shouldDrawAsDisabled =
+            parentIcon.info.isDisabled || !parentIcon.isLaunchableAtScreenSize
 
-        appIcon1 = newIcon1
-        appIcon2 = newIcon2
-        appIcon1?.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
-        appIcon2?.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
+        appPairBackground.colorFilter = if (shouldDrawAsDisabled) getDisabledColorFilter() else null
+        appIcon1.setIsDisabled(shouldDrawAsDisabled)
+        appIcon2.setIsDisabled(shouldDrawAsDisabled)
     }
 
     /** Gets this icon graphic's bounds, with respect to the parent icon's coordinate system. */
@@ -137,17 +138,9 @@
     override fun dispatchDraw(canvas: Canvas) {
         super.dispatchDraw(canvas)
 
-        val drawAlpha =
-            if (!parentIcon.isLaunchableAtScreenSize || parentIcon.info.isDisabled) DISABLED_ALPHA
-            else ENABLED_ALPHA
-
         // Draw background
-        appPairBackground.alpha = drawAlpha
         appPairBackground.draw(canvas)
 
-        // Make sure icons are loaded and fresh
-        applyIcons(parentIcon.info.contents)
-
         // Draw first icon
         canvas.save()
         // The app icons are placed differently depending on device orientation.
@@ -156,8 +149,8 @@
         } else {
             canvas.translate(width / 2f - memberIconSize / 2f, innerPadding)
         }
-        appIcon1?.alpha = drawAlpha
-        appIcon1?.draw(canvas)
+
+        appIcon1.draw(canvas)
         canvas.restore()
 
         // Draw second icon
@@ -174,8 +167,8 @@
                 height - (innerPadding + memberIconSize)
             )
         }
-        appIcon2?.alpha = drawAlpha
-        appIcon2?.draw(canvas)
+
+        appIcon2.draw(canvas)
         canvas.restore()
     }
 }