diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java index 0e955adb56..1f73241ed0 100644 --- a/src/com/android/launcher3/apppairs/AppPairIcon.java +++ b/src/com/android/launcher3/apppairs/AppPairIcon.java @@ -143,7 +143,7 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab CharSequence app2 = getInfo().getSecondApp().title; String a11yTitle = getContext().getString(R.string.app_pair_name_format, app1, app2); setContentDescription( - getInfo().shouldDrawAsDisabled(getContext()) + getInfo().shouldReportDisabled(getContext()) ? getContext().getString(R.string.disabled_app_label, a11yTitle) : a11yTitle); } diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt index 7809102150..dce97eb594 100644 --- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt +++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt @@ -55,6 +55,12 @@ constructor(context: Context, attrs: AttributeSet? = null) : appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt()) appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt()) + // If icons are unlaunchable due to screen size, manually override disabled appearance. + // (otherwise, leave disabled state alone; icons will naturally inherit the app's state) + val (isApp1Launchable, isApp2Launchable) = appPairInfo.isLaunchable(p.context) + if (!isApp1Launchable) appIcon1.setIsDisabled(true) + if (!isApp2Launchable) appIcon2.setIsDisabled(true) + // Create icon drawable. val fullIconDrawable = AppPairIconDrawable(p, appIcon1, appIcon2) fullIconDrawable.setBounds(0, 0, p.iconSize, p.iconSize) diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt index fad365c43d..3dbd45b0f4 100644 --- a/src/com/android/launcher3/model/data/AppPairInfo.kt +++ b/src/com/android/launcher3/model/data/AppPairInfo.kt @@ -68,12 +68,15 @@ class AppPairInfo() : CollectionInfo() { /** Returns if either of the app pair members is currently disabled. */ override fun isDisabled() = anyMatch { it.isDisabled } - /** Checks if the app pair is launchable at the current screen size. */ - fun isLaunchable(context: Context) = - (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet || - getAppContents().stream().noneMatch { - it.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) - } + /** Checks if member apps are launchable at the current screen size. */ + fun isLaunchable(context: Context): Pair { + val isTablet = + (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet + return Pair( + isTablet || !getFirstApp().hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE), + isTablet || !getSecondApp().hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) + ) + } /** Fetches high-res icons for member apps if needed. */ fun fetchHiResIconsIfNeeded(iconCache: IconCache) { @@ -83,13 +86,14 @@ class AppPairInfo() : CollectionInfo() { } /** - * App pairs will draw as "disabled" if either of the following is true: + * App pairs will report itself as "disabled" (for accessibility) if either of the following is + * true: * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused * or can't be launched for some other reason). * 2) One of the member apps can't be launched due to screen size requirements. */ - fun shouldDrawAsDisabled(context: Context): Boolean { - return isDisabled || !isLaunchable(context) + fun shouldReportDisabled(context: Context): Boolean { + return isDisabled || !isLaunchable(context).first || !isLaunchable(context).second } /** Generates a default title for the app pair and sets it. */ diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 816d5e9f44..f226b8dd12 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -149,9 +149,12 @@ public class ItemClickHandler { */ private static void onClickAppPairIcon(View v) { Launcher launcher = Launcher.getLauncher(v.getContext()); - AppPairIcon appPairIcon = (AppPairIcon) v; - if (!appPairIcon.getInfo().isLaunchable(launcher)) { - // Display a message for app pairs that are disabled due to screen size + AppPairIcon icon = (AppPairIcon) v; + AppPairInfo info = icon.getInfo(); + boolean isApp1Launchable = info.isLaunchable(launcher).getFirst(), + isApp2Launchable = info.isLaunchable(launcher).getSecond(); + if (!isApp1Launchable || !isApp2Launchable) { + // App pair is unlaunchable due to screen size. boolean isFoldable = InvariantDeviceProfile.INSTANCE.get(launcher) .supportedProfiles.stream().anyMatch(dp -> dp.isTwoPanels); Toast.makeText(launcher, isFoldable @@ -159,26 +162,27 @@ public class ItemClickHandler { : R.string.app_pair_unlaunchable_at_screen_size, Toast.LENGTH_SHORT).show(); return; - } else if (appPairIcon.getInfo().isDisabled()) { - WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp(); - WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp(); + } else if (info.isDisabled()) { + // App pair is disabled for another reason. + WorkspaceItemInfo app1 = info.getFirstApp(); + WorkspaceItemInfo app2 = info.getSecondApp(); // Show the user why the app pair is disabled. if (app1.isDisabled() && app2.isDisabled()) { - // Both apps are disabled, show "app pair is not available" toast. + // Both apps are disabled, show generic "app pair is not available" toast. Toast.makeText(launcher, R.string.app_pair_not_available, Toast.LENGTH_SHORT) .show(); return; } else if ((app1.isDisabled() && handleDisabledItemClicked(app1, launcher)) || (app2.isDisabled() && handleDisabledItemClicked(app2, launcher))) { - // Only one is disabled, and handleDisabledItemClicked() will show a toast, so we - // are done. + // Only one is disabled, and handleDisabledItemClicked() showed a specific toast + // explaining why, so we are done. return; } } // Either the app pair is not disabled, or it is a disabled state that can be handled by // framework directly (e.g. one app is paused), so go ahead and launch. - launcher.launchAppPair(appPairIcon); + launcher.launchAppPair(icon); } /**