Snap for 11954976 from a8f0155c89 to 24Q3-release

Change-Id: Ic44cd683f66940661c2a6d3a7274b1438ed3098c
This commit is contained in:
Android Build Coastguard Worker
2024-06-11 23:23:15 +00:00
25 changed files with 322 additions and 272 deletions
+18
View File
@@ -284,3 +284,21 @@ flag {
description: "Enables folders in all apps"
bug: "341582436"
}
flag {
name: "enable_recents_in_taskbar"
namespace: "launcher"
description: "Replace hybrid hotseat app predictions with strictly Recent Apps"
bug: "315354060"
}
flag {
name: "enable_first_screen_broadcast_archiving_extras"
namespace: "launcher"
description: "adds Extras to first screen broadcast for archived apps"
bug: "322314760"
is_fixed_read_only: true
metadata {
purpose: PURPOSE_BUGFIX
}
}
@@ -41,8 +41,6 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.animation.AnimatorSet;
@@ -304,7 +302,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
createTaskbarRecentAppsController(),
new TaskbarRecentAppsController(
RecentsModel.INSTANCE.get(this),
LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this, () ->
@@ -314,16 +314,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mLauncherPrefs = LauncherPrefs.get(this);
}
private TaskbarRecentAppsController createTaskbarRecentAppsController() {
// TODO(b/335401172): unify DesktopMode checks in Launcher
if (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()) {
return new DesktopTaskbarRunningAppsController(
RecentsModel.INSTANCE.get(this),
LauncherActivityInterface.INSTANCE::getDesktopVisibilityController);
}
return TaskbarRecentAppsController.DEFAULT;
}
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
@@ -180,8 +180,9 @@ public class TaskbarControllers {
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
voiceInteractionWindowController, taskbarTranslationController,
taskbarEduTooltipController, keyboardQuickSwitchController, taskbarPinningController
voiceInteractionWindowController, taskbarRecentAppsController,
taskbarTranslationController, taskbarEduTooltipController,
keyboardQuickSwitchController, taskbarPinningController,
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
@@ -5,9 +5,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
@@ -16,6 +13,7 @@ import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_A
import android.app.KeyguardManager;
import com.android.launcher3.AbstractFloatingView;
import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -26,19 +24,6 @@ import java.io.PrintWriter;
*/
public class TaskbarKeyguardController implements TaskbarControllers.LoggableTaskbarController {
private static final long KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING
| SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED
| SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
| SYSUI_STATE_WAKEFULNESS_MASK;
// If any of these SysUi flags (via QuickstepContract) is set, the device to be considered
// locked.
public static final long MASK_ANY_SYSUI_LOCKED = SYSUI_STATE_BOUNCER_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
| SYSUI_STATE_DEVICE_DREAMING;
private final TaskbarActivityContext mContext;
private long mKeyguardSysuiFlags;
private boolean mBouncerShowing;
@@ -55,7 +40,7 @@ public class TaskbarKeyguardController implements TaskbarControllers.LoggableTas
}
public void updateStateForSysuiFlags(@SystemUiStateFlags long systemUiStateFlags) {
long interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
long interestingKeyguardFlags = systemUiStateFlags & SystemUiFlagUtils.KEYGUARD_SYSUI_FLAGS;
if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
// No change in keyguard relevant flags
return;
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
@@ -51,6 +50,7 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.animation.ViewRootSync;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -343,8 +343,7 @@ public class TaskbarLauncherStateController {
prevIsAwake && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
}
boolean isDeviceLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
updateStateForFlag(FLAG_DEVICE_LOCKED, isDeviceLocked);
updateStateForFlag(FLAG_DEVICE_LOCKED, SystemUiFlagUtils.isLocked(systemUiStateFlags));
// Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
// interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
@@ -79,7 +79,7 @@ public class TaskbarModelCallbacks implements
public void init(TaskbarControllers controllers) {
mControllers = controllers;
if (mControllers.taskbarRecentAppsController.isEnabled()) {
if (mControllers.taskbarRecentAppsController.getCanShowRunningApps()) {
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
if (shouldShowRunningAppsInDesktopMode()) {
@@ -1,77 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.taskbar;
import static java.util.Collections.emptySet;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import java.util.Set;
/**
* Base class for providing recent apps functionality
*/
public class TaskbarRecentAppsController {
public static final TaskbarRecentAppsController DEFAULT = new TaskbarRecentAppsController();
// Initialized in init.
protected TaskbarControllers mControllers;
@CallSuper
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
}
@CallSuper
protected void onDestroy() {
mControllers = null;
}
/** Stores the current {@link AppInfo} instances, no-op except in desktop environment. */
protected void setApps(AppInfo[] apps) {
}
/**
* Indicates whether recent apps functionality is enabled, should return false except in
* desktop environment.
*/
protected boolean isEnabled() {
return false;
}
/** Called to update hotseatItems, no-op except in desktop environment. */
protected ItemInfo[] updateHotseatItemInfos(@NonNull ItemInfo[] hotseatItems) {
return hotseatItems;
}
/** Called to update the list of currently running apps, no-op except in desktop environment. */
protected void updateRunningApps() {}
/** Returns the currently running apps, or an empty Set if outside of Desktop environment. */
public Set<String> getRunningApps() {
return emptySet();
}
/** Returns the set of apps whose tasks are all minimized. */
public Set<String> getMinimizedApps() {
return emptySet();
}
}
@@ -13,37 +13,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.taskbar
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration
import android.util.Log
import android.util.SparseArray
import androidx.annotation.VisibleForTesting
import androidx.core.util.valueIterator
import com.android.launcher3.Flags.enableRecentsInTaskbar
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.quickstep.RecentsModel
import kotlin.collections.filterNotNull
import com.android.window.flags.Flags.enableDesktopWindowingMode
import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
import java.io.PrintWriter
/**
* Shows running apps when in Desktop Mode.
*
* Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
* recent-apps behaviour when outside of Desktop Mode.
*
* This class should only be used if
* [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
* Provides recent apps functionality, when the Taskbar Recent Apps section is enabled. Behavior:
* - When in Fullscreen mode: show the N most recent Tasks
* - When in Desktop Mode: show the currently running (open) Tasks
*/
class DesktopTaskbarRunningAppsController(
class TaskbarRecentAppsController(
private val recentsModel: RecentsModel,
// Pass a provider here instead of the actual DesktopVisibilityController instance since that
// instance might not be available when this constructor is called.
private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
) : TaskbarRecentAppsController() {
) : LoggableTaskbarController {
// TODO(b/335401172): unify DesktopMode checks in Launcher.
val canShowRunningApps =
enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()
// TODO(b/343532825): Add a setting to disable Recents even when the flag is on.
@VisibleForTesting
var isEnabled = enableRecentsInTaskbar() || canShowRunningApps
// Initialized in init.
private lateinit var controllers: TaskbarControllers
private var apps: Array<AppInfo>? = null
private var allRunningDesktopAppInfos: List<AppInfo>? = null
@@ -55,22 +62,40 @@ class DesktopTaskbarRunningAppsController(
private val isInDesktopMode: Boolean
get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
override fun onDestroy() {
super.onDestroy()
val runningApps: Set<String>
get() {
if (!isEnabled || !isInDesktopMode) {
return emptySet()
}
return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
}
val minimizedApps: Set<String>
get() {
if (!isInDesktopMode) {
return emptySet()
}
return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet()
?: emptySet()
}
fun init(taskbarControllers: TaskbarControllers) {
controllers = taskbarControllers
}
fun onDestroy() {
apps = null
}
@VisibleForTesting
public override fun setApps(apps: Array<AppInfo>?) {
/** Stores the current [AppInfo] instances, no-op except in desktop environment. */
fun setApps(apps: Array<AppInfo>?) {
this.apps = apps
}
override fun isEnabled() = true
@VisibleForTesting
public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
if (!isInDesktopMode) {
Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
/** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */
// TODO(next CL): add new section of Tasks instead of changing Hotseat items
fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
if (!isEnabled || !isInDesktopMode) {
return hotseatItems
}
val newHotseatItemInfos =
@@ -89,55 +114,6 @@ class DesktopTaskbarRunningAppsController(
return newHotseatItemInfos.toTypedArray()
}
override fun getRunningApps(): Set<String> {
if (!isInDesktopMode) {
return emptySet()
}
return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
}
override fun getMinimizedApps(): Set<String> {
if (!isInDesktopMode) {
return emptySet()
}
return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
}
@VisibleForTesting
public override fun updateRunningApps() {
if (!isInDesktopMode) {
Log.d(TAG, "updateRunningApps: not in Desktop Mode")
mControllers.taskbarViewController.commitRunningAppsToUI()
return
}
val runningTasks = getDesktopRunningTasks()
val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
allRunningDesktopAppInfos = runningAppInfo
updateMinimizedApps(runningTasks, runningAppInfo)
mControllers.taskbarViewController.commitRunningAppsToUI()
}
private fun updateMinimizedApps(
runningTasks: List<RunningTaskInfo>,
runningAppInfo: List<AppInfo>,
) {
val allRunningAppTasks =
runningAppInfo
.mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } }
.associate { (appInfo, targetPackage) ->
appInfo to
runningTasks
.filter { it.realActivity?.packageName == targetPackage }
.map { it.taskId }
}
val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible }
allMinimizedDesktopAppInfos =
allRunningAppTasks
.filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } }
.keys
.toList()
}
private fun getRunningDesktopAppInfosExceptHotseatApps(
allRunningDesktopAppInfos: List<AppInfo>,
hotseatItems: List<ItemInfo>
@@ -165,12 +141,43 @@ class DesktopTaskbarRunningAppsController(
.filterNotNull()
}
private fun getAppInfosFromRunningTask(task: RunningTaskInfo): AppInfo? =
apps?.firstOrNull { it.targetPackage == task.realActivity?.packageName }
/** Called to update the list of currently running apps, no-op except in desktop environment. */
fun updateRunningApps() {
if (!isEnabled || !isInDesktopMode) {
return controllers.taskbarViewController.commitRunningAppsToUI()
}
val runningTasks = getDesktopRunningTasks()
val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
allRunningDesktopAppInfos = runningAppInfo
updateMinimizedApps(runningTasks, runningAppInfo)
controllers.taskbarViewController.commitRunningAppsToUI()
}
private fun <E> SparseArray<E>.toList(): List<E> = valueIterator().asSequence().toList()
private fun updateMinimizedApps(
runningTasks: List<RunningTaskInfo>,
runningAppInfo: List<AppInfo>,
) {
val allRunningAppTasks =
runningAppInfo
.mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } }
.associate { (appInfo, targetPackage) ->
appInfo to
runningTasks
.filter { it.realActivity?.packageName == targetPackage }
.map { it.taskId }
}
val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible }
allMinimizedDesktopAppInfos =
allRunningAppTasks
.filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } }
.keys
.toList()
}
companion object {
private const val TAG = "TabletDesktopTaskbarRunningAppsController"
override fun dumpLogs(prefix: String, pw: PrintWriter) {
pw.println("$prefix TaskbarRecentAppsController:")
pw.println("$prefix\tisEnabled=$isEnabled")
pw.println("$prefix\tcanShowRunningApps=$canShowRunningApps")
// TODO(next CL): add more logs
}
}
@@ -25,7 +25,6 @@ import static com.android.internal.jank.InteractionJankMonitor.Configuration;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -35,7 +34,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_I
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -66,6 +64,7 @@ import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.SystemUiFlagUtils;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -950,9 +949,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
&& DisplayController.isTransientTaskbar(mActivity);
updateStateForFlag(FLAG_STASHED_SYSUI,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING) || stashForBubbles);
boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED)
&& !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY);
updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked);
updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED,
SystemUiFlagUtils.isLocked(systemUiStateFlags));
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
@@ -153,6 +153,7 @@ public class BubbleDragController {
@Override
protected void onDragDismiss() {
mBubblePinController.onDragEnd();
mBubbleBarViewController.onBubbleDragEnd();
}
@Override
@@ -1614,7 +1614,8 @@ public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
mSwipePipToHomeAnimator.getComponentName(),
mSwipePipToHomeAnimator.getDestinationBounds(),
mSwipePipToHomeAnimator.getContentOverlay(),
mSwipePipToHomeAnimator.getAppBounds());
mSwipePipToHomeAnimator.getAppBounds(),
mSwipePipToHomeAnimator.getSourceRectHint());
windowAnim = mSwipePipToHomeAnimators;
} else {
@@ -684,11 +684,11 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
* should be responsible for cleaning up the overlay.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
SurfaceControl overlay, Rect appBounds) {
SurfaceControl overlay, Rect appBounds, Rect sourceRectHint) {
if (mPip != null) {
try {
mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
appBounds);
appBounds, sourceRectHint);
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopSwipePipToHome");
}
@@ -26,6 +26,8 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINI
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -44,9 +46,11 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -373,20 +377,54 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
return mCallbacks;
}
public void endLiveTile() {
if (mLastGestureState == null) {
return;
}
BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
if (containerInterface.isInLiveTileMode()
&& containerInterface.getCreatedContainer() != null) {
RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel();
if (recentsView != null) {
recentsView.switchToScreenshot(null,
() -> recentsView.finishRecentsAnimation(true /* toRecents */,
false /* shouldPip */, null));
public void onSystemUiFlagsChanged(@QuickStepContract.SystemUiStateFlags long lastSysUIFlags,
@QuickStepContract.SystemUiStateFlags long newSysUIFlags) {
long isShadeExpandedFlagMask =
SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean wasExpanded = hasAnyFlag(lastSysUIFlags, isShadeExpandedFlagMask);
boolean isExpanded = hasAnyFlag(newSysUIFlags, isShadeExpandedFlagMask);
if (wasExpanded != isExpanded && isExpanded) {
// End live tile when expanding the notification panel for the first time from
// overview.
if (endLiveTile()) {
return;
}
}
boolean wasLocked = SystemUiFlagUtils.isLocked(lastSysUIFlags);
boolean isLocked = SystemUiFlagUtils.isLocked(newSysUIFlags);
if (wasLocked != isLocked && isLocked) {
// Finish the running recents animation when locking the device.
finishRunningRecentsAnimation(
mController != null && mController.getFinishTargetIsLauncher());
}
}
private boolean hasAnyFlag(long flags, long flagMask) {
return (flags & flagMask) != 0;
}
/**
* Switches the {@link RecentsView} to screenshot if in live tile mode.
*
* @return true iff the {@link RecentsView} was in live tile mode and was switched to screenshot
*/
public boolean endLiveTile() {
if (mLastGestureState == null) {
return false;
}
BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
if (!containerInterface.isInLiveTileMode()
|| containerInterface.getCreatedContainer() == null) {
return false;
}
RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel();
if (recentsView == null) {
return false;
}
recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation(
true /* toRecents */, false /* shouldPip */, null));
return true;
}
public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
@@ -47,8 +47,6 @@ import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SY
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
@@ -719,16 +717,7 @@ public class TouchInteractionService extends Service {
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
long isShadeExpandedFlag =
SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0;
boolean isExpanded = (systemUiStateFlags & isShadeExpandedFlag) != 0;
if (wasExpanded != isExpanded && isExpanded) {
// End live tile when expanding the notification panel for the first time from
// overview.
mTaskAnimationManager.endLiveTile();
}
mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags);
}
}
@@ -267,6 +267,10 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
return mAppBounds;
}
public Rect getSourceRectHint() {
return mSourceRectHint;
}
@Nullable
public SurfaceControl getContentOverlay() {
return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
/** Util class for holding and checking [SystemUiStateFlags] masks. */
object SystemUiFlagUtils {
const val KEYGUARD_SYSUI_FLAGS =
(QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or
QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or
QuickStepContract.SYSUI_STATE_DEVICE_DOZING or
QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED or
QuickStepContract.SYSUI_STATE_HOME_DISABLED or
QuickStepContract.SYSUI_STATE_BACK_DISABLED or
QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or
QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK)
// If any of these SysUi flags (via QuickstepContract) is set, the device to be considered
// locked.
private const val MASK_ANY_SYSUI_LOCKED =
(QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or
QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or
QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or
QuickStepContract.SYSUI_STATE_DEVICE_DREAMING)
/**
* Returns true iff the given [SystemUiStateFlags] imply that the device is considered locked.
*/
@JvmStatic
fun isLocked(@SystemUiStateFlags flags: Long): Boolean {
return hasAnyFlag(flags, MASK_ANY_SYSUI_LOCKED) &&
!hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY)
}
private fun hasAnyFlag(@SystemUiStateFlags flags: Long, flagMask: Long): Boolean {
return (flags and flagMask) != 0L
}
}
@@ -278,7 +278,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
boolean showSingleTaskActions = !mIsGroupedTask;
boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
Log.d(TAG, "updateActionButtonsVisibility() called: showSingleTaskActions = ["
+ showSingleTaskActions + ", showGroupActions = [" + showGroupActions + "]");
+ showSingleTaskActions + "], showGroupActions = [" + showGroupActions + "]");
getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
}
@@ -18,13 +18,16 @@ package com.android.quickstep.views;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON;
import static com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.TouchDelegate;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -41,9 +44,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.util.SplitSelectStateController;
/**
@@ -133,6 +134,28 @@ public class SplitInstructionsView extends LinearLayout {
cancelTextView.setVisibility(VISIBLE);
cancelTextView.setOnClickListener((v) -> exitSplitSelection());
instructionTextView.setText(R.string.toast_contextual_split_select_app);
// After layout, expand touch target of cancel button to meet minimum a11y measurements.
post(() -> {
int minTouchSize = getResources()
.getDimensionPixelSize(settingslib_preferred_minimum_touch_target);
Rect r = new Rect();
cancelTextView.getHitRect(r);
if (r.width() < minTouchSize) {
// add 1 to ensure ceiling on int division
int expandAmount = (minTouchSize + 1 - r.width()) / 2;
r.left -= expandAmount;
r.right += expandAmount;
}
if (r.height() < minTouchSize) {
int expandAmount = (minTouchSize + 1 - r.height()) / 2;
r.top -= expandAmount;
r.bottom += expandAmount;
}
setTouchDelegate(new TouchDelegate(r, cancelTextView));
});
}
// Set accessibility title, will be announced by a11y tools.
@@ -37,7 +37,7 @@ import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.whenever
@RunWith(AndroidTestingRunner::class)
class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
@get:Rule val mockitoRule = MockitoJUnit.rule()
@@ -46,19 +46,18 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
private var nextTaskId: Int = 500
private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
private lateinit var recentAppsController: TaskbarRecentAppsController
private lateinit var userHandle: UserHandle
@Before
fun setUp() {
super.setup()
userHandle = Process.myUserHandle()
taskbarRunningAppsController =
DesktopTaskbarRunningAppsController(mockRecentsModel) {
mockDesktopVisibilityController
}
taskbarRunningAppsController.init(taskbarControllers)
taskbarRunningAppsController.setApps(
recentAppsController =
TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController }
recentAppsController.init(taskbarControllers)
recentAppsController.isEnabled = true
recentAppsController.setApps(
ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
)
}
@@ -69,7 +68,7 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val hotseatItems =
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
.isEqualTo(hotseatItems.toTypedArray())
}
@@ -81,10 +80,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
val newHotseatItems =
taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
assertThat(newHotseatItems.map { it?.targetPackage })
.containsExactlyElementsIn(hotseatPackages)
@@ -96,7 +95,7 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val hotseatItems =
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
.isEqualTo(hotseatItems.toTypedArray())
}
@@ -108,10 +107,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
val newHotseatItems =
taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
val expectedPackages =
listOf(
@@ -134,10 +133,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
)
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
val newHotseatItems =
taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
val expectedPackages =
listOf(
@@ -156,10 +155,10 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
assertThat(taskbarRunningAppsController.runningApps).isEmpty()
assertThat(taskbarRunningAppsController.minimizedApps).isEmpty()
assertThat(recentAppsController.runningApps).isEmpty()
assertThat(recentAppsController.minimizedApps).isEmpty()
}
@Test
@@ -168,11 +167,11 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
assertThat(taskbarRunningAppsController.runningApps)
assertThat(recentAppsController.runningApps)
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
assertThat(taskbarRunningAppsController.minimizedApps).isEmpty()
assertThat(recentAppsController.minimizedApps).isEmpty()
}
@Test
@@ -187,12 +186,11 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
)
)
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
taskbarRunningAppsController.updateRunningApps()
recentAppsController.updateRunningApps()
assertThat(taskbarRunningAppsController.runningApps)
assertThat(recentAppsController.runningApps)
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
assertThat(taskbarRunningAppsController.minimizedApps)
.containsExactly(RUNNING_APP_PACKAGE_3)
assertThat(recentAppsController.minimizedApps).containsExactly(RUNNING_APP_PACKAGE_3)
}
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
@@ -88,6 +88,8 @@ public class TaplOverviewIconTest extends AbstractLauncherUiTest<QuickstepLaunch
}
private void createAndLaunchASplitPair() {
clearAllRecentTasks();
startTestActivity(2);
startTestActivity(3);
@@ -33,9 +33,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.tapl.TaskbarAppIcon;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import com.android.wm.shell.Flags;
import org.junit.After;
@@ -74,14 +72,6 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
}
@Test
@PortraitLandscape
public void testSplitFromOverview() {
createAndLaunchASplitPair();
}
@Test
@PortraitLandscape
@TaskbarModeSwitch
@TestStabilityRule.Stability(flavors = PLATFORM_POSTSUBMIT | LOCAL) // b/295225524
public void testSplitAppFromHomeWithItself() throws Exception {
// Currently only tablets have Taskbar in Overview, so test is only active on tablets
@@ -152,11 +142,7 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
// Currently only tablets have Taskbar in Overview, so test is only active on tablets
assumeTrue(mLauncher.isTablet());
if (!mLauncher.getRecentTasks().isEmpty()) {
// Clear all recent tasks
mLauncher.goHome().switchToOverview().dismissAllTasks();
}
clearAllRecentTasks();
startAppFast(getAppPackageName());
Overview overview = mLauncher.goHome().switchToOverview();
@@ -173,6 +159,8 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
}
private void createAndLaunchASplitPair() {
clearAllRecentTasks();
startTestActivity(2);
startTestActivity(3);
+1
View File
@@ -211,6 +211,7 @@ android_robolectric_test {
"Launcher3TestResources",
"SystemUISharedLib",
"launcher-testing-shared",
"android.appwidget.flags-aconfig-java",
],
libs: [
"android.test.runner",
@@ -18,12 +18,12 @@ import android.widget.RemoteViews
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.IconProvider
import com.android.launcher3.model.WidgetItem
import com.android.launcher3.tests.R
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.Executors
import com.google.common.truth.Truth.assertThat
@@ -41,7 +41,10 @@ class GeneratedPreviewTest {
"com.android.launcher3.tests",
"com.android.launcher3.testcomponent.AppWidgetNoConfig"
)
private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue
private val generatedPreviewLayout =
getInstrumentation().context.run {
resources.getIdentifier("test_layout_appwidget_blue", "layout", packageName)
}
private lateinit var context: Context
private lateinit var generatedPreview: RemoteViews
private lateinit var widgetCell: WidgetCell
@@ -137,6 +140,7 @@ class GeneratedPreviewTest {
assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
}
@Test
@RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetItem_getGeneratedPreview() {
@@ -148,6 +152,7 @@ class GeneratedPreviewTest {
@RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetCell_showGeneratedPreview() {
widgetCell.applyFromCellItem(widgetItem)
DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
.isEqualTo(appWidgetProviderInfo)
@@ -157,6 +162,7 @@ class GeneratedPreviewTest {
@RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetCell_showGeneratedPreview_flagDisabled() {
widgetCell.applyFromCellItem(widgetItem)
DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
assertThat(widgetCell.appWidgetHostViewPreview).isNull()
}
}
@@ -699,4 +699,11 @@ public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher> {
UiDevice.getInstance(getInstrumentation()).pressHome();
mLauncher.waitForLauncherInitialized();
}
/** Clears all recent tasks */
protected void clearAllRecentTasks() {
if (!mLauncher.getRecentTasks().isEmpty()) {
mLauncher.goHome().switchToOverview().dismissAllTasks();
}
}
}
@@ -23,6 +23,7 @@ import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import android.graphics.Rect;
import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
@@ -44,6 +45,7 @@ import java.util.stream.Collectors;
* Common overview panel for both Launcher and fallback recents
*/
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
private static final String TAG = "BaseOverview";
protected static final String TASK_RES_ID = "task";
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
@@ -384,25 +386,31 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
protected boolean isActionsViewVisible() {
if (!hasTasks() || isClearAllVisible()) {
Log.d(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
return false;
}
boolean isTablet = mLauncher.isTablet();
if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
Log.d(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
return false;
}
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
if (task == null) {
Log.d(TAG, "Not expecting an actions bar: no current task");
return false;
}
// In tablets, if focused task is not in center, overview actions aren't visible.
if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
Log.d(TAG, "Not expecting an actions bar: device is tablet and task is not centered");
return false;
}
if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
Log.d(TAG, "Not expecting an actions bar: device is phone and task is split");
// Overview actions aren't visible for split screen tasks, except for save app pair
// button on tablets.
return false;
}
Log.d(TAG, "Expecting an actions bar");
return true;
}
@@ -447,10 +455,20 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
}
private void verifyActionsViewVisibility() {
// If no running tasks, no need to verify actions view visibility.
if (getTasks().isEmpty()) {
return;
}
boolean isTablet = mLauncher.isTablet();
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to assert overview actions view visibility")) {
boolean isTablet = mLauncher.isTablet();
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
"want to assert overview actions view visibility="
+ isActionsViewVisible()
+ ", focused task is "
+ (task == null ? "null" : (task.isTaskSplit() ? "split" : "not split"))
)) {
if (isActionsViewVisible()) {
if (task.isTaskSplit()) {