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
This commit is contained in:
Jeremy Sim
2024-03-04 17:09:53 -08:00
parent 7e0703eca0
commit 09fe96b95a
3 changed files with 36 additions and 46 deletions
@@ -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 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab
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 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab
}
/**
* 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 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab
// 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();
}
}
@@ -162,6 +162,6 @@ class AppPairIconBackground extends Drawable {
@Override
public void setColorFilter(ColorFilter colorFilter) {
// Required by Drawable but not used.
mBackgroundPaint.setColorFilter(colorFilter);
}
}
@@ -26,8 +26,8 @@ import android.view.Gravity
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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
}
/** 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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
} 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 @@ class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: Attr
height - (innerPadding + memberIconSize)
)
}
appIcon2?.alpha = drawAlpha
appIcon2?.draw(canvas)
appIcon2.draw(canvas)
canvas.restore()
}
}