Merge "Animate new bubble when the bar is expanded" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 9147e4c..fecc43d 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -284,3 +284,21 @@
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
+ }
+}
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 1115ff2..797ea45 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -29,6 +29,7 @@
android:id="@+id/split_instructions_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:maxWidth="@dimen/split_instructions_view_max_width"
android:textColor="?androidprv:attr/textColorOnAccent"
android:text="@string/toast_split_select_app" />
@@ -36,6 +37,7 @@
android:id="@+id/split_instructions_text_cancel"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
android:textColor="?androidprv:attr/textColorOnAccent"
android:layout_marginStart="@dimen/split_instructions_start_margin_cancel"
android:text="@string/toast_split_select_app_cancel"
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index f9528b3..e24d8fe 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -45,4 +45,8 @@
<dimen name="allset_page_allset_text_size">38sp</dimen>
<dimen name="allset_page_swipe_up_text_size">15sp</dimen>
+ <!-- Splitscreen -->
+ <!-- Max width of the split instructions view -->
+ <dimen name="split_instructions_view_max_width">300dp</dimen>
+
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6bbf7f6..6b76311 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -490,4 +490,8 @@
<!-- Digital Wellbeing -->
<dimen name="digital_wellbeing_toast_height">48dp</dimen>
+ <!-- Splitscreen -->
+ <!-- Max width of the split instructions view -->
+ <dimen name="split_instructions_view_max_width">220dp</dimen>
+
</resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0de0550..61877f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -41,8 +41,6 @@
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 @@
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 @@
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);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index f9ddc3d..58c5e83 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -180,8 +180,9 @@
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
- voiceInteractionWindowController, taskbarTranslationController,
- taskbarEduTooltipController, keyboardQuickSwitchController, taskbarPinningController
+ voiceInteractionWindowController, taskbarRecentAppsController,
+ taskbarTranslationController, taskbarEduTooltipController,
+ keyboardQuickSwitchController, taskbarPinningController,
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index eac4eaa..911140a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -5,9 +5,6 @@
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 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 @@
*/
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 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;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ead1a8a..cb9f24a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -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.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 @@
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
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 35e1c7b..2b0e169 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -79,7 +79,7 @@
public void init(TaskbarControllers controllers) {
mControllers = controllers;
- if (mControllers.taskbarRecentAppsController.isEnabled()) {
+ if (mControllers.taskbarRecentAppsController.getCanShowRunningApps()) {
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
if (shouldShowRunningAppsInDesktopMode()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
deleted file mode 100644
index 606ba5b..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
+++ /dev/null
@@ -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();
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
similarity index 62%
rename from quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
rename to quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index d4bef28..0946caf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -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 @@
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 @@
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 @@
.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
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 8fdb460..995a652 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -25,7 +25,6 @@
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_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.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 @@
&& 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);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index fbd1b88..efc747c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -153,6 +153,7 @@
@Override
protected void onDragDismiss() {
mBubblePinController.onDragEnd();
+ mBubbleBarViewController.onBubbleDragEnd();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 463222d..3199076 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1614,7 +1614,8 @@
mSwipePipToHomeAnimator.getComponentName(),
mSwipePipToHomeAnimator.getDestinationBounds(),
mSwipePipToHomeAnimator.getContentOverlay(),
- mSwipePipToHomeAnimator.getAppBounds());
+ mSwipePipToHomeAnimator.getAppBounds(),
+ mSwipePipToHomeAnimator.getSourceRectHint());
windowAnim = mSwipePipToHomeAnimators;
} else {
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 9c3fbaa..433baa9 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -684,11 +684,11 @@
* 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");
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 2348f28..28fa81a 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -26,6 +26,8 @@
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.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 @@
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) {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7aa99d9..e9046b9 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -47,8 +47,6 @@
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 @@
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);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index b13e52d..2d606f3 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -267,6 +267,10 @@
return mAppBounds;
}
+ public Rect getSourceRectHint() {
+ return mSourceRectHint;
+ }
+
@Nullable
public SurfaceControl getContentOverlay() {
return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
diff --git a/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
new file mode 100644
index 0000000..5f4388c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
@@ -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
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 604d072..d9468c7 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -278,7 +278,7 @@
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);
}
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index a56d51e..3d994e8 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -18,13 +18,16 @@
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.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 @@
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.
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
similarity index 82%
rename from quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
rename to quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 5b56710..104263a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -37,7 +37,7 @@
import org.mockito.kotlin.whenever
@RunWith(AndroidTestingRunner::class)
-class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
@get:Rule val mockitoRule = MockitoJUnit.rule()
@@ -46,19 +46,18 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
)
)
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> {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index fa10b61..b7fd8be 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -88,6 +88,8 @@
}
private void createAndLaunchASplitPair() {
+ clearAllRecentTasks();
+
startTestActivity(2);
startTestActivity(3);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 729452a..23a29f7 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -49,6 +49,7 @@
private static final String PRIVATE_PROFILE_NAME = "LauncherPrivateProfile";
private static final String INSTALLED_APP_NAME = "Aardwolf";
+ private static final int MAX_STATE_TOGGLE_TRIES = 2;
private static final String TAG = "TaplPrivateSpaceTest";
@Override
@@ -172,7 +173,9 @@
HomeAllApps homeAllApps = mLauncher.getAllApps();
// Disable Private Space
- togglePrivateSpace(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+ togglePrivateSpaceWithRetry(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
homeAllApps.freeze();
try {
@@ -184,7 +187,9 @@
}
// Enable Private Space
- togglePrivateSpace(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+ togglePrivateSpaceWithRetry(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
homeAllApps.freeze();
try {
@@ -217,6 +222,25 @@
waitForLauncherUIUpdate();
}
+ private void togglePrivateSpaceWithRetry(int state, HomeAllApps homeAllApps) {
+ int togglePsCount = 0;
+ boolean shouldRetry;
+ do {
+ togglePsCount ++;
+ try {
+ togglePrivateSpace(state, homeAllApps);
+ // No need to retry if the toggle was successful.
+ shouldRetry = false;
+ } catch (AssertionError error) {
+ if (togglePsCount < MAX_STATE_TOGGLE_TRIES) {
+ shouldRetry = true;
+ } else {
+ throw error;
+ }
+ }
+ } while (shouldRetry);
+ }
+
private void waitForPrivateSpaceSetup() {
waitForLauncherCondition("Private Profile not setup",
launcher -> launcher.getAppsView().hasPrivateProfile(),
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 6be082a..8adf793 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -33,9 +33,7 @@
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 @@
}
@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 @@
// 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 @@
}
private void createAndLaunchASplitPair() {
+ clearAllRecentTasks();
+
startTestActivity(2);
startTestActivity(3);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
deleted file mode 100644
index 208920a..0000000
--- a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2019 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;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE;
-import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER;
-import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
-
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.RemoteViews;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.Suppress;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.tapl.LaunchedAppState;
-import com.android.launcher3.testcomponent.ListViewService;
-import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
-import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.Executors;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.lang.reflect.Field;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.IntConsumer;
-
-/**
- * Test to verify view inflation does not happen during swipe up.
- * To verify view inflation, we setup a stub ViewConfiguration and check if any call to that class
- * does from a View.init method or not.
- *
- * Alternative approaches considered:
- * Overriding LayoutInflater: This does not cover views initialized
- * directly (ex: new LinearLayout)
- * Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes
- * the main thread extremely slow and untestable
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class TaplViewInflationDuringSwipeUp extends AbstractQuickStepTest {
-
- private SparseArray<ViewConfiguration> mConfigMap;
- private InitTracker mInitTracker;
- private LauncherModel mModel;
-
- @Before
- public void setUp() throws Exception {
- // Workaround for b/142351228, when there are no activities, the system may not destroy the
- // activity correctly for activities under instrumentation, which can leave two concurrent
- // activities, which changes the order in which the activities are cleaned up (overlapping
- // stop and start) leading to all sort of issues. To workaround this, ensure that the test
- // is started only after starting another app.
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
-
- super.setUp();
-
- mModel = LauncherAppState.getInstance(mTargetContext).getModel();
- Executors.MODEL_EXECUTOR.submit(mModel.getModelDbController()::createEmptyDB).get();
-
- // Get static configuration map
- Field field = ViewConfiguration.class.getDeclaredField("sConfigurations");
- field.setAccessible(true);
- mConfigMap = (SparseArray<ViewConfiguration>) field.get(null);
-
- mInitTracker = new InitTracker();
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190618549 is fixed
- public void testSwipeUpFromApp() throws Exception {
- try {
- // Go to overview once so that all views are initialized and cached
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
-
- // Track view creations
- mInitTracker.startTracking();
-
- startTestActivity(2);
- mLauncher.getLaunchedAppState().switchToOverview();
-
- assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
- } finally {
- mConfigMap.clear();
- }
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190729479 is fixed
- public void testSwipeUpFromApp_widget_update() {
- String stubText = "Some random stub text";
-
- executeSwipeUpTestWithWidget(
- widgetId -> { },
- widgetId -> AppWidgetManager.getInstance(getContext())
- .updateAppWidget(widgetId, createMainWidgetViews(stubText)),
- stubText);
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190729479 is fixed
- public void testSwipeUp_with_list_widgets() {
- SimpleViewsFactory viewFactory = new SimpleViewsFactory();
- viewFactory.viewCount = 1;
- Bundle args = new Bundle();
- args.putBinder(EXTRA_VALUE, viewFactory.toBinder());
- TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, args);
-
- try {
- executeSwipeUpTestWithWidget(
- widgetId -> {
- // Initialize widget
- RemoteViews views = createMainWidgetViews("List widget title");
- views.setRemoteAdapter(android.R.id.list,
- new Intent(getContext(), ListViewService.class));
- AppWidgetManager.getInstance(getContext()).updateAppWidget(widgetId, views);
- verifyWidget(viewFactory.getLabel(0));
- },
- widgetId -> {
- // Update widget
- viewFactory.viewCount = 2;
- AppWidgetManager.getInstance(getContext())
- .notifyAppWidgetViewDataChanged(widgetId, android.R.id.list);
- },
- viewFactory.getLabel(1)
- );
- } finally {
- TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, new Bundle());
- }
- }
-
- private void executeSwipeUpTestWithWidget(IntConsumer widgetIdCreationCallback,
- IntConsumer updateBeforeSwipeUp, String finalWidgetText) {
- try {
- LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
-
- // Make sure the widget is big enough to show a list of items
- info.minSpanX = 2;
- info.minSpanY = 2;
- info.spanX = 2;
- info.spanY = 2;
- AtomicInteger widgetId = new AtomicInteger();
-
- commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
- .addItem(() -> {
- LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, true);
- item.screenId = FIRST_SCREEN_ID;
- widgetId.set(item.appWidgetId);
- return item;
- }));
-
- assertTrue("Widget is not present",
- mLauncher.goHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
-
- // Verify widget id
- widgetIdCreationCallback.accept(widgetId.get());
-
- // Go to overview once so that all views are initialized and cached
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
-
- // Track view creations
- mInitTracker.startTracking();
-
- startTestActivity(2);
- LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState();
-
- // Update widget
- updateBeforeSwipeUp.accept(widgetId.get());
-
- launchedAppState.switchToOverview();
- assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
-
- // Widget is updated when going home
- mInitTracker.disableLog();
- mLauncher.goHome();
- verifyWidget(finalWidgetText);
- assertNotEquals(1, mInitTracker.viewInitCount);
- } finally {
- mConfigMap.clear();
- }
- }
-
- private void verifyWidget(String text) {
- assertNotNull("Widget not updated",
- UiDevice.getInstance(getInstrumentation())
- .wait(Until.findObject(By.text(text)), DEFAULT_UI_TIMEOUT));
- }
-
- private RemoteViews createMainWidgetViews(String title) {
- Context c = getContext();
- int layoutId = c.getResources().getIdentifier(
- "test_layout_widget_list", "layout", c.getPackageName());
- RemoteViews views = new RemoteViews(c.getPackageName(), layoutId);
- views.setTextViewText(android.R.id.text1, title);
- return views;
- }
-
- private class InitTracker implements Answer {
-
- public int viewInitCount = 0;
-
- public boolean log = true;
-
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Exception ex = new Exception();
-
- boolean found = false;
- for (StackTraceElement ste : ex.getStackTrace()) {
- if ("<init>".equals(ste.getMethodName())
- && View.class.getName().equals(ste.getClassName())) {
- found = true;
- break;
- }
- }
- if (found) {
- viewInitCount++;
- if (log) {
- Log.d("InitTracker", "New view inflated", ex);
- }
-
- }
- return invocation.callRealMethod();
- }
-
- public void disableLog() {
- log = false;
- }
-
- public void startTracking() {
- ViewConfiguration vc = ViewConfiguration.get(mTargetContext);
- ViewConfiguration spyVC = spy(vc);
- mConfigMap.put(mConfigMap.keyAt(mConfigMap.indexOfValue(vc)), spyVC);
- doAnswer(this).when(spyVC).getScaledTouchSlop();
- }
- }
-}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index a810331..5d03a93 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -337,6 +337,8 @@
&& !mPrivateApps.isEmpty()) {
// Always add PS Header if Space is present and visible.
position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+ mFastScrollerSections.add(new FastScrollSectionInfo(
+ mPrivateProfileAppScrollerBadge, position));
int privateSpaceState = mPrivateProviderManager.getCurrentState();
switch (privateSpaceState) {
case PrivateProfileManager.STATE_DISABLED:
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 7ef3209..9824992 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -242,11 +242,26 @@
// Create reveal animator for the folder content (capture the top 4 icons 2x2)
int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x
+ mDeviceProfile.folderCellWidthPx * 2;
+ int rtlExtraWidth = 0;
int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y
+ mDeviceProfile.folderCellHeightPx * 2;
int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
+ // In RTL we want to move to the last 2 columns of icons in the folder.
+ if (Utilities.isRtl(mContext.getResources())) {
+ page = (mContent.getPageCount() - 1) - page;
+ CellLayout clAtPage = mContent.getPageAt(page);
+ if (clAtPage != null) {
+ int numExtraRows = clAtPage.getCountX() - 2;
+ rtlExtraWidth = (int) Math.max(numExtraRows * (mDeviceProfile.folderCellWidthPx
+ + mDeviceProfile.folderCellLayoutBorderSpacePx.x), rtlExtraWidth);
+ }
+ }
int left = mContent.getPaddingLeft() + page * lp.width;
- Rect contentStart = new Rect(left, 0, left + width, height);
+ Rect contentStart = new Rect(
+ left + rtlExtraWidth,
+ 0,
+ left + width + mContent.getPaddingRight() + rtlExtraWidth,
+ height);
Rect contentEnd = new Rect(left, 0, left + lp.width, lp.height);
play(a, shapeDelegate.createRevealAnimator(
mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index df8f635..fa17b7b 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -109,6 +109,13 @@
private float mLastTouchY;
private boolean mIsDragging;
+ /**
+ * Tracks whether a keyboard hide request has been sent due to downward scrolling.
+ * <p>
+ * Set to true when scrolling down and reset when scrolling up to prevents redundant hide
+ * requests during continuous downward scrolls.
+ */
+ private boolean mRequestedHideKeyboard;
private boolean mIsThumbDetached;
private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
@@ -127,6 +134,7 @@
protected FastScrollRecyclerView mRv;
private RecyclerView.OnScrollListener mOnScrollListener;
+ private final ActivityContext mActivityContext;
private int mDownX;
private int mDownY;
@@ -163,7 +171,7 @@
mDeltaThreshold = res.getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
mScrollbarLeftOffsetTouchDelegate = res.getDisplayMetrics().density
* SCROLLBAR_LEFT_OFFSET_TOUCH_DELEGATE_DP;
-
+ mActivityContext = ActivityContext.lookupContext(context);
TypedArray ta =
context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewFastScroller, defStyleAttr, 0);
mCanThumbDetach = ta.getBoolean(R.styleable.RecyclerViewFastScroller_canThumbDetach, false);
@@ -248,6 +256,7 @@
mDownX = x;
mDownY = mLastY = y;
mDownTimeStampMillis = ev.getDownTime();
+ mRequestedHideKeyboard = false;
if ((Math.abs(mDy) < mDeltaThreshold &&
mRv.getScrollState() != SCROLL_STATE_IDLE)) {
@@ -260,6 +269,7 @@
}
break;
case MotionEvent.ACTION_MOVE:
+ boolean isScrollingDown = y > mLastY;
mLastY = y;
int absDeltaY = Math.abs(y - mDownY);
int absDeltaX = Math.abs(x - mDownX);
@@ -275,6 +285,14 @@
}
}
if (mIsDragging) {
+ if (isScrollingDown) {
+ if (!mRequestedHideKeyboard) {
+ mActivityContext.hideKeyboard();
+ }
+ mRequestedHideKeyboard = true;
+ } else {
+ mRequestedHideKeyboard = false;
+ }
updateFastScrollSectionNameAndThumbOffset(y);
}
break;
@@ -294,7 +312,6 @@
}
private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
- ActivityContext.lookupContext(getContext()).hideKeyboard();
mIsDragging = true;
if (mCanThumbDetach) {
mIsThumbDetached = true;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 3be6faa..9929892 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -330,8 +330,7 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- LauncherAppState.getInstance(mActivityContext).getModel()
- .refreshAndBindWidgetsAndShortcuts(null);
+ onWidgetsBound();
}
@Override
diff --git a/tests/Android.bp b/tests/Android.bp
index 1dcb2a6..e51242f 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -211,6 +211,7 @@
"Launcher3TestResources",
"SystemUISharedLib",
"launcher-testing-shared",
+ "android.appwidget.flags-aconfig-java",
],
libs: [
"android.test.runner",
diff --git a/tests/src/com/android/launcher3/AppFilterTest.kt b/tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
similarity index 89%
rename from tests/src/com/android/launcher3/AppFilterTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
index f2150a2..f1c6343 100644
--- a/tests/src/com/android/launcher3/AppFilterTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
@@ -19,15 +19,18 @@
import android.content.ComponentName
import android.content.Context
import android.content.res.Resources
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnitRunner
+import org.mockito.MockitoAnnotations
-@RunWith(MockitoJUnitRunner::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
class AppFilterTest {
@Mock private lateinit var mockContext: Context
@@ -39,6 +42,7 @@
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
`when`(mockContext.resources).thenReturn(mockResources) // Link the context and resources
`when`(mockResources.getStringArray(R.array.filtered_components))
.thenReturn(arrayOf("com.example.app1/Activity1"))
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
index 460058b..b239aed 100644
--- a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -18,12 +18,12 @@
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 @@
"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 @@
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 @@
@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 @@
@RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetCell_showGeneratedPreview_flagDisabled() {
widgetCell.applyFromCellItem(widgetItem)
+ DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
assertThat(widgetCell.appWidgetHostViewPreview).isNull()
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 115a6e6..a6f4441 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -699,4 +699,11 @@
UiDevice.getInstance(getInstrumentation()).pressHome();
mLauncher.waitForLauncherInitialized();
}
+
+ /** Clears all recent tasks */
+ protected void clearAllRecentTasks() {
+ if (!mLauncher.getRecentTasks().isEmpty()) {
+ mLauncher.goHome().switchToOverview().dismissAllTasks();
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index e10893e..567a8bd 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -23,6 +23,7 @@
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 @@
* 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 @@
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 @@
}
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()) {