Show screenshot and select in task menu

Hide screenshot and select from menu if thumbnail is null

Bug: 383662632
Flag: com.android.launcher3.enable_show_enabled_shortcuts_in_accessibility_menu
Test: OverviewMenuImageTest & manual. See bug.
Change-Id: Idf41de7e36b63f7bcc8639f5f3932a61e56ebfcd
This commit is contained in:
samcackett
2025-03-06 16:17:02 +00:00
committed by Sam Cackett
parent 865982c634
commit 0946c8c123
6 changed files with 109 additions and 28 deletions
+10
View File
@@ -110,3 +110,13 @@ flag {
description: "Enable wallpaper background for desktop tasks in overview."
bug: "363257721"
}
flag {
name: "enable_show_enabled_shortcuts_in_accessibility_menu"
namespace: "launcher_overview"
description: "Enables showing the same shortcuts in the Task menu as well as the accessibility actions menu"
bug: "383662632"
metadata {
purpose: PURPOSE_BUGFIX
}
}
@@ -42,6 +42,7 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.util.ResourceBasedOverride;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.Snackbar;
import com.android.quickstep.task.thumbnail.TaskOverlayUiState;
import com.android.quickstep.task.util.TaskOverlayHelper;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.views.DesktopTaskView;
@@ -168,9 +169,32 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
: mTaskContainer.getThumbnailViewDeprecated().getThumbnail();
}
protected boolean isRealSnapshot() {
return enableRefactorTaskThumbnail() ? mHelper.getEnabledState().isRealSnapshot()
: mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot();
/**
* Returns whether the snapshot is real. If the device is locked for the user of the task,
* the snapshot used will be an app-theme generated snapshot instead of a real snapshot.
*/
public boolean isRealSnapshot() {
if (enableRefactorTaskThumbnail()) {
if (mHelper.getUiState() instanceof TaskOverlayUiState.Enabled) {
return mHelper.getEnabledState().isRealSnapshot();
} else {
return false;
}
}
return mTaskContainer.getThumbnailViewDeprecated().isRealSnapshot();
}
/**
* Returns whether the snapshot is rotated compared to the current task orientation.
*/
public boolean isThumbnailRotationDifferentFromTask() {
if (enableRefactorTaskThumbnail()) {
return mHelper.getThumbnailPositionState().isRotated();
}
return mTaskContainer.getThumbnailViewDeprecated()
.isThumbnailRotationDifferentFromTask();
}
protected T getActionsView() {
@@ -359,13 +383,10 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
private class ScreenshotSystemShortcut extends SystemShortcut {
private final RecentsViewContainer mContainer;
ScreenshotSystemShortcut(RecentsViewContainer container, ItemInfo itemInfo,
View originalView) {
super(R.drawable.ic_screenshot, R.string.action_screenshot, container, itemInfo,
originalView);
mContainer = container;
}
@Override
@@ -20,7 +20,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
import static com.android.launcher3.Flags.enableShowEnabledShortcutsInAccessibilityMenu;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_CLOSE_APP_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -42,7 +44,6 @@ import android.window.SplashScreen;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
@@ -345,15 +346,20 @@ public interface TaskShortcutFactory {
boolean isTaskSplitNotSupported = !task.isDockable ||
(intentFlags & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode;
boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isTaskInExpectedScrollPosition =
recentsView.isTaskInExpectedScrollPosition(taskView);
if (notEnoughTasksToSplit || isTaskSplitNotSupported || hideForExistingMultiWindow
|| (isLargeTile && isTaskInExpectedScrollPosition)) {
if (notEnoughTasksToSplit || isTaskSplitNotSupported || hideForExistingMultiWindow) {
return null;
}
if (!enableShowEnabledShortcutsInAccessibilityMenu()) {
boolean isLargeTile = deviceProfile.isTablet && taskView.isLargeTile();
boolean isTaskInExpectedScrollPosition =
recentsView.isTaskInExpectedScrollPosition(taskView);
if (isLargeTile && isTaskInExpectedScrollPosition) {
return null;
}
}
return orientationHandler.getSplitPositionOptions(deviceProfile)
.stream()
.map((Function<SplitPositionOption, SystemShortcut>) option ->
@@ -500,16 +506,23 @@ public interface TaskShortcutFactory {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
// Extra conditions if it's not grid-only overview
if (!isGridOnlyOverview) {
RecentsOrientedState orientedState = taskContainer.getTaskView().getOrientedState();
boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
&& orientedState.getTouchRotation() != ROTATION_0;
if (!isFakeLandscape) {
if (enableShowEnabledShortcutsInAccessibilityMenu()) {
if (!taskContainer.getOverlay().isRealSnapshot()) {
return null;
}
} else {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && enableGridOnlyOverview();
// Extra conditions if it's not grid-only overview
if (!isGridOnlyOverview) {
RecentsOrientedState orientedState = taskContainer.getTaskView()
.getOrientedState();
boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
&& orientedState.getTouchRotation() != ROTATION_0;
if (!isFakeLandscape) {
return null;
}
}
}
SystemShortcut screenshotShortcut = taskContainer.getOverlay().getScreenshotShortcut(
@@ -527,10 +540,39 @@ public interface TaskShortcutFactory {
@Override
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
if (!isGridOnlyOverview) {
return null;
if (enableShowEnabledShortcutsInAccessibilityMenu()) {
if (!taskContainer.getOverlay().isRealSnapshot()) {
return null;
}
// Modal only works with grid size tiles with enableGridOnlyOverview enabled on
// tablets / foldables. With enableGridOnlyOverview off, for large tiles it works,
// but the tile needs to be in the center of Recents / Overview.
boolean isTablet = container.getDeviceProfile().isTablet;
RecentsView recentsView = container.getOverviewPanel();
boolean isLargeTileInCenterOfOverview = taskContainer.getTaskView().isLargeTile()
&& recentsView.isFocusedTaskInExpectedScrollPosition();
if (isTablet
&& !isLargeTileInCenterOfOverview
&& !enableGridOnlyOverview()) {
return null;
}
boolean isFakeLandscape = !taskContainer.getTaskView().getPagedOrientationHandler()
.isLayoutNaturalToLauncher();
if (isFakeLandscape) {
return null;
}
if (taskContainer.getOverlay().isThumbnailRotationDifferentFromTask()) {
return null;
}
} else {
boolean isTablet = container.getDeviceProfile().isTablet;
boolean isGridOnlyOverview = isTablet && enableGridOnlyOverview();
if (!isGridOnlyOverview) {
return null;
}
}
SystemShortcut modalStateSystemShortcut =
@@ -46,7 +46,7 @@ class TaskOverlayHelper(val task: Task, val overlay: TaskOverlayFactory.TaskOver
private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
private lateinit var overlayInitializedScope: CoroutineScope
private var uiState: TaskOverlayUiState = Disabled
var uiState: TaskOverlayUiState = Disabled
private lateinit var viewModel: TaskOverlayViewModel
@@ -60,7 +60,7 @@ class TaskOverlayHelper(val task: Task, val overlay: TaskOverlayFactory.TaskOver
fun getThumbnailMatrix() = getThumbnailPositionState().matrix
private fun getThumbnailPositionState() =
fun getThumbnailPositionState() =
viewModel.getThumbnailPositionState(
overlay.snapshotView.width,
overlay.snapshotView.height,
@@ -1578,7 +1578,10 @@ public abstract class RecentsView<
== getPagedOrientationHandler().getPrimaryScroll(this);
}
private boolean isFocusedTaskInExpectedScrollPosition() {
/**
* Returns true if the focused TaskView is in expected scroll position.
*/
public boolean isFocusedTaskInExpectedScrollPosition() {
TaskView focusedTask = getFocusedTaskView();
return focusedTask != null && isTaskInExpectedScrollPosition(focusedTask);
}
@@ -412,7 +412,12 @@ public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusab
thumbnailDataAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
}
private boolean isThumbnailRotationDifferentFromTask() {
/**
* Returns whether or not the current thumbnail is a different orientation to the task.
* <p>
* Used to disable modal state when screenshot doesn't match the device orientation.
*/
public boolean isThumbnailRotationDifferentFromTask() {
RecentsView recents = mTaskView.getRecentsView();
if (recents == null || mThumbnailData == null) {
return false;