Merge "Revert "Completely destroy Launcher's Taskbar."" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 15ac9e3..31a9009 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -323,3 +323,11 @@
description: "Search bar persists at the bottom of the screen across Launcher states"
bug: "346408388"
}
+
+flag {
+ name: "multiline_search_bar"
+ namespace: "launcher"
+ description: "Search bar can wrap to multi-line"
+ bug: "341795751"
+}
+
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 26ca06a..68558fa 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -56,7 +56,7 @@
import com.android.quickstep.util.AssistContentRequester;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.views.GoOverviewActionsView;
-import com.android.quickstep.views.TaskView.TaskContainer;
+import com.android.quickstep.views.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
diff --git a/quickstep/res/drawable-hdpi/nav_background.9.png b/quickstep/res/drawable-hdpi/nav_background.9.png
new file mode 100644
index 0000000..a09e654
--- /dev/null
+++ b/quickstep/res/drawable-hdpi/nav_background.9.png
Binary files differ
diff --git a/quickstep/res/drawable-mdpi/nav_background.9.png b/quickstep/res/drawable-mdpi/nav_background.9.png
new file mode 100644
index 0000000..aa74153
--- /dev/null
+++ b/quickstep/res/drawable-mdpi/nav_background.9.png
Binary files differ
diff --git a/quickstep/res/drawable-xhdpi/nav_background.9.png b/quickstep/res/drawable-xhdpi/nav_background.9.png
new file mode 100644
index 0000000..3b52195
--- /dev/null
+++ b/quickstep/res/drawable-xhdpi/nav_background.9.png
Binary files differ
diff --git a/quickstep/res/drawable-xxhdpi/nav_background.9.png b/quickstep/res/drawable-xxhdpi/nav_background.9.png
new file mode 100644
index 0000000..b35183c
--- /dev/null
+++ b/quickstep/res/drawable-xxhdpi/nav_background.9.png
Binary files differ
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 63e1e01..0fa3fbc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -41,6 +41,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
@@ -106,6 +107,7 @@
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
import com.android.systemui.shared.rotation.RotationButtonController;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -154,6 +156,8 @@
public static final int ALPHA_INDEX_SUW = 2;
private static final int NUM_ALPHA_CHANNELS = 3;
+ private static final long AUTODIM_TIMEOUT_MS = 2250;
+
private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
private final ArrayList<ImageView> mAllButtons = new ArrayList<>();
private int mState;
@@ -162,6 +166,7 @@
private final @Nullable Context mNavigationBarPanelContext;
private final WindowManagerProxy mWindowManagerProxy;
private final NearestTouchFrame mNavButtonsView;
+ private final Handler mHandler;
private final LinearLayout mNavButtonContainer;
// Used for IME+A11Y buttons
private final ViewGroup mEndContextualContainer;
@@ -183,7 +188,7 @@
this::updateNavButtonInAppDisplayProgressForSysui);
/** Expected nav button dark intensity communicated via the framework. */
private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
- this::updateNavButtonColor);
+ this::onDarkIntensityChanged);
/** {@code 1} if the Taskbar background color is fully opaque. */
private final AnimatedFloat mOnTaskbarBackgroundNavButtonColorOverride = new AnimatedFloat(
this::updateNavButtonColor);
@@ -219,12 +224,19 @@
private ImageView mRecentsButton;
private Space mSpace;
+ private TaskbarTransitions mTaskbarTransitions;
+ private @BarTransitions.TransitionMode int mTransitionMode;
+
+ private final Runnable mAutoDim = () -> mTaskbarTransitions.setAutoDim(true);
+
public NavbarButtonsViewController(TaskbarActivityContext context,
- @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
+ @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView,
+ Handler handler) {
mContext = context;
mNavigationBarPanelContext = navigationBarPanelContext;
mWindowManagerProxy = WindowManagerProxy.INSTANCE.get(mContext);
mNavButtonsView = navButtonsView;
+ mHandler = handler;
mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
@@ -234,6 +246,10 @@
mOnBackgroundIconColor = Utilities.isDarkTheme(context)
? context.getColor(R.color.taskbar_nav_icon_light_color)
: context.getColor(R.color.taskbar_nav_icon_dark_color);
+
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions = new TaskbarTransitions(mContext, mNavButtonsView);
+ }
}
/**
@@ -345,6 +361,9 @@
R.bool.floating_rotation_button_position_left);
mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
mRotationButtonListener);
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.init();
+ }
applyState();
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
@@ -605,6 +624,48 @@
mBackButton.setAccessibilityDelegate(accessibilityDelegate);
}
+ public void setWallpaperVisible(boolean isVisible) {
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.setWallpaperVisibility(isVisible);
+ }
+ }
+
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ mTransitionMode = barMode;
+ if (checkBarModes) {
+ checkNavBarModes();
+ }
+ }
+
+ public void checkNavBarModes() {
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ boolean isBarHidden = (mSysuiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
+ mTaskbarTransitions.transitionTo(mTransitionMode, !isBarHidden);
+ }
+ }
+
+ public void finishBarAnimations() {
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.finishAnimations();
+ }
+ }
+
+ public void touchAutoDim(boolean reset) {
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.setAutoDim(false);
+ mHandler.removeCallbacks(mAutoDim);
+ if (reset) {
+ mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
+ }
+ }
+ }
+
+ public void transitionTo(@BarTransitions.TransitionMode int barMode, boolean animate) {
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.transitionTo(barMode, animate);
+ }
+ }
+
/** Use to set the translationY for the all nav+contextual buttons */
public AnimatedFloat getTaskbarNavButtonTranslationY() {
return mTaskbarNavButtonTranslationY;
@@ -680,8 +741,7 @@
mDarkIconColorOnHome);
final int iconColor;
- if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && enableTaskbarOnPhones()
- && mContext.isPhoneMode()) {
+ if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mContext.isPhoneMode()) {
iconColor = sysUiNavButtonIconColorOnHome;
} else {
// Override the color from framework if nav buttons are over an opaque Taskbar surface.
@@ -703,6 +763,13 @@
}
}
+ private void onDarkIntensityChanged() {
+ updateNavButtonColor();
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.onDarkIntensityChanged(mTaskbarNavButtonDarkIntensity.value);
+ }
+ }
+
protected ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
ViewGroup parent, TaskbarNavButtonController navButtonController, @IdRes int id) {
return addButton(drawableId, buttonType, parent, navButtonController, id,
@@ -1048,6 +1115,9 @@
+ mOnBackgroundNavButtonColorOverrideMultiplier.value);
mNavButtonsView.dumpLogs(prefix + "\t", pw);
+ if (enableTaskbarOnPhones() && mContext.isPhoneButtonNavMode()) {
+ mTaskbarTransitions.dumpLogs(prefix + "\t", pw);
+ }
}
private static String getStateString(int flags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5020206..21a8268 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -139,6 +139,7 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.rotation.RotationButtonController;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.unfold.updates.RotationChangeProvider;
@@ -275,7 +276,8 @@
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
buttonController,
- new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView),
+ new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView,
+ getMainThreadHandler()),
rotationButtonController,
new TaskbarDragLayerController(this, mDragLayer),
new TaskbarViewController(this, taskbarView),
@@ -799,6 +801,27 @@
mControllers.taskbarStashController.setSetupUIVisible(isVisible);
}
+ public void setWallpaperVisible(boolean isVisible) {
+ mControllers.navbarButtonsViewController.setWallpaperVisible(isVisible);
+ }
+
+ public void checkNavBarModes() {
+ mControllers.navbarButtonsViewController.checkNavBarModes();
+ }
+
+ public void finishBarAnimations() {
+ mControllers.navbarButtonsViewController.finishBarAnimations();
+ }
+
+ public void touchAutoDim(boolean reset) {
+ mControllers.navbarButtonsViewController.touchAutoDim(reset);
+ }
+
+ public void transitionTo(@BarTransitions.TransitionMode int barMode,
+ boolean animate) {
+ mControllers.navbarButtonsViewController.transitionTo(barMode, animate);
+ }
+
/**
* Called when this instance of taskbar is no longer needed
*/
@@ -876,6 +899,9 @@
mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
}
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ mControllers.navbarButtonsViewController.onTransitionModeUpdated(barMode, checkBarModes);
+ }
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
.updateValue(darkIntensity);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
index c45c667..7f9d8a3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
@@ -27,6 +27,7 @@
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.animation.Interpolator
+import android.window.OnBackInvokedDispatcher
import androidx.core.view.updateLayoutParams
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
@@ -66,11 +67,14 @@
/** Container where the tooltip's body should be inflated. */
lateinit var content: ViewGroup
private set
+
private lateinit var arrow: View
/** Callback invoked when the tooltip is being closed. */
var onCloseCallback: () -> Unit = {}
private var openCloseAnimator: AnimatorSet? = null
+ /** Used to set whether users can tap outside the current tooltip window to dismiss it */
+ var allowTouchDismissal = true
/** Animates the tooltip into view. */
fun show() {
@@ -134,14 +138,25 @@
override fun isOfType(type: Int): Boolean = type and TYPE_TASKBAR_EDUCATION_DIALOG != 0
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
- if (ev?.action == ACTION_DOWN && !activityContext.dragLayer.isEventOverView(this, ev)) {
+ if (
+ ev?.action == ACTION_DOWN &&
+ !activityContext.dragLayer.isEventOverView(this, ev) &&
+ allowTouchDismissal
+ ) {
close(true)
}
return false
}
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ findOnBackInvokedDispatcher()
+ ?.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, this)
+ }
+
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
+ findOnBackInvokedDispatcher()?.unregisterOnBackInvokedCallback(this)
Settings.Secure.putInt(mContext.contentResolver, LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index 5cbd5c9..d57c483 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -86,10 +86,13 @@
!activityContext.isPhoneMode &&
!activityContext.isTinyTaskbar
}
+
private val isOpen: Boolean
get() = tooltip?.isOpen ?: false
+
val isBeforeTooltipFeaturesStep: Boolean
get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
+
private lateinit var controllers: TaskbarControllers
// Keep track of whether the user has seen the Search Edu
@@ -152,6 +155,7 @@
tooltipStep = TOOLTIP_STEP_NONE
inflateTooltip(R.layout.taskbar_edu_features)
tooltip?.run {
+ allowTouchDismissal = false
val splitscreenAnim = requireViewById<LottieAnimationView>(R.id.splitscreen_animation)
val suggestionsAnim = requireViewById<LottieAnimationView>(R.id.suggestions_animation)
val pinningAnim = requireViewById<LottieAnimationView>(R.id.pinning_animation)
@@ -216,6 +220,7 @@
inflateTooltip(R.layout.taskbar_edu_pinning)
tooltip?.run {
+ allowTouchDismissal = true
requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
.supportLightTheme()
@@ -260,6 +265,7 @@
userHasSeenSearchEdu = true
inflateTooltip(R.layout.taskbar_edu_search)
tooltip?.run {
+ allowTouchDismissal = true
requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
showDisclosureText(eduSubtitle)
@@ -332,7 +338,9 @@
}
/** Closes the current [tooltip]. */
- fun hide() = tooltip?.close(true)
+ fun hide() {
+ tooltip?.close(true)
+ }
/** Initializes [tooltip] with content from [contentResId]. */
private fun inflateTooltip(@LayoutRes contentResId: Int) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 5d6591b..ee79fbf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -72,6 +72,7 @@
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.AssistUtils;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
@@ -519,6 +520,36 @@
}
}
+ public void setWallpaperVisible(boolean isVisible) {
+ mSharedState.wallpaperVisible = isVisible;
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.setWallpaperVisible(isVisible);
+ }
+ }
+
+ public void checkNavBarModes() {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.checkNavBarModes();
+ }
+ }
+
+ public void finishBarAnimations() {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.finishBarAnimations();
+ }
+ }
+
+ public void touchAutoDim(boolean reset) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.touchAutoDim(reset);
+ }
+ }
+
+ public void transitionTo(@BarTransitions.TransitionMode int barMode,
+ boolean animate) {
+ mTaskbarActivityContext.transitionTo(barMode, animate);
+ }
+
private boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
@@ -546,6 +577,13 @@
}
}
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ mSharedState.barMode = barMode;
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onTransitionModeUpdated(barMode, checkBarModes);
+ }
+ }
+
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
mSharedState.navButtonsDarkIntensity = darkIntensity;
if (mTaskbarActivityContext != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index fc3b4c7..0a81f78 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -149,20 +149,39 @@
taskListChangeId =
recentsModel.getTasks { tasks ->
allRecentTasks = tasks
+ val oldRunningPackages = runningAppPackages
+ val oldMinimizedPackages = minimizedAppPackages
desktopTask = allRecentTasks.filterIsInstance<DesktopTask>().firstOrNull()
- onRecentsOrHotseatChanged()
- controllers.taskbarViewController.commitRunningAppsToUI()
+ val runningPackagesChanged = oldRunningPackages != runningAppPackages
+ val minimizedPackagessChanged = oldMinimizedPackages != minimizedAppPackages
+ if (
+ onRecentsOrHotseatChanged() ||
+ runningPackagesChanged ||
+ minimizedPackagessChanged
+ ) {
+ controllers.taskbarViewController.commitRunningAppsToUI()
+ }
}
}
}
- private fun onRecentsOrHotseatChanged() {
+ /**
+ * Updates [shownTasks] when Recents or Hotseat changes.
+ *
+ * @return Whether [shownTasks] changed.
+ */
+ private fun onRecentsOrHotseatChanged(): Boolean {
+ val oldShownTasks = shownTasks
shownTasks =
if (isInDesktopMode) {
computeShownRunningTasks()
} else {
computeShownRecentTasks()
}
+ val shownTasksChanged = oldShownTasks != shownTasks
+ if (!shownTasksChanged) {
+ return shownTasksChanged
+ }
for (groupTask in shownTasks) {
for (task in groupTask.tasks) {
@@ -174,6 +193,7 @@
}
}
}
+ return shownTasksChanged
}
private fun computeShownRunningTasks(): List<GroupTask> {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index edaeb63..77bd35f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -56,12 +56,17 @@
// TaskbarManager#onNavButtonsDarkIntensityChanged()
public float navButtonsDarkIntensity;
+ // TaskbarManager#onTransitionModeUpdated()
+ public int barMode;
+
// TaskbarManager#onNavigationBarLumaSamplingEnabled()
public int mLumaSamplingDisplayId = DEFAULT_DISPLAY;
public boolean mIsLumaSamplingEnabled = true;
public boolean setupUIVisible = false;
+ public boolean wallpaperVisible = false;
+
public boolean allAppsVisible = false;
// LauncherTaskbarUIController#mTaskbarInAppDisplayProgressMultiProp
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTransitions.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTransitions.java
new file mode 100644
index 0000000..615db01
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTransitions.java
@@ -0,0 +1,135 @@
+/*
+ * 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.launcher3.taskbar;
+
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
+
+import java.io.PrintWriter;
+
+/** Manages task bar transitions */
+public class TaskbarTransitions extends BarTransitions implements
+ TaskbarControllers.LoggableTaskbarController {
+
+ private final TaskbarActivityContext mContext;
+
+ private boolean mWallpaperVisible;
+
+ private boolean mLightsOut;
+ private boolean mAutoDim;
+ private View mNavButtons;
+ private float mDarkIntensity;
+
+ private final NearestTouchFrame mView;
+
+ public TaskbarTransitions(TaskbarActivityContext context, NearestTouchFrame view) {
+ super(view, R.drawable.nav_background);
+
+ mContext = context;
+ mView = view;
+ }
+
+ void init() {
+ mView.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ mNavButtons = mView.findViewById(R.id.end_nav_buttons);
+ applyLightsOut(false, true);
+ });
+ mNavButtons = mView.findViewById(R.id.end_nav_buttons);
+
+ applyModeBackground(-1, getMode(), false /*animate*/);
+ applyLightsOut(false /*animate*/, true /*force*/);
+ if (mContext.isPhoneButtonNavMode()) {
+ mBarBackground.setOverrideAlpha(1);
+ }
+ }
+
+ void setWallpaperVisibility(boolean visible) {
+ mWallpaperVisible = visible;
+ applyLightsOut(true, false);
+ }
+
+ @Override
+ public void setAutoDim(boolean autoDim) {
+ // Ensure we aren't in gestural nav if we are triggering auto dim
+ if (autoDim && !mContext.isPhoneButtonNavMode()) {
+ return;
+ }
+ if (mAutoDim == autoDim) return;
+ mAutoDim = autoDim;
+ applyLightsOut(true, false);
+ }
+
+ @Override
+ protected void onTransition(int oldMode, int newMode, boolean animate) {
+ super.onTransition(oldMode, newMode, animate);
+ applyLightsOut(animate, false /*force*/);
+ }
+
+ private void applyLightsOut(boolean animate, boolean force) {
+ // apply to lights out
+ applyLightsOut(isLightsOut(getMode()), animate, force);
+ }
+
+ private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
+ if (!force && lightsOut == mLightsOut) return;
+
+ mLightsOut = lightsOut;
+ if (mNavButtons == null) return;
+
+ // ok, everyone, stop it right there
+ mNavButtons.animate().cancel();
+
+ // Bump percentage by 10% if dark.
+ float darkBump = mDarkIntensity / 10;
+ final float navButtonsAlpha = lightsOut ? 0.6f + darkBump : 1f;
+
+ if (!animate) {
+ mNavButtons.setAlpha(navButtonsAlpha);
+ } else {
+ final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
+ mNavButtons.animate()
+ .alpha(navButtonsAlpha)
+ .setDuration(duration)
+ .start();
+ }
+ }
+
+ void onDarkIntensityChanged(float darkIntensity) {
+ mDarkIntensity = darkIntensity;
+ if (mAutoDim) {
+ applyLightsOut(false, true);
+ }
+ }
+
+ @Override
+ public void dumpLogs(String prefix, PrintWriter pw) {
+ pw.println(prefix + "TaskbarTransitions:");
+
+ pw.println(prefix + "\tmMode=" + getMode());
+ pw.println(prefix + "\tmAlwaysOpaque: " + isAlwaysOpaque());
+ pw.println(prefix + "\tmWallpaperVisible: " + mWallpaperVisible);
+ pw.println(prefix + "\tmLightsOut: " + mLightsOut);
+ pw.println(prefix + "\tmAutoDim: " + mAutoDim);
+ pw.println(prefix + "\tbg overrideAlpha: " + mBarBackground.getOverrideAlpha());
+ pw.println(prefix + "\tbg color: " + mBarBackground.getColor());
+ pw.println(prefix + "\tbg frame: " + mBarBackground.getFrame());
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index f24bc21..170e018 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -43,8 +43,8 @@
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 15e4578..f6b1328 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -322,27 +322,45 @@
|| mImeVisibilityChecker.isImeVisible();
BubbleBarBubble bubbleToSelect = null;
- if (!update.removedBubbles.isEmpty()) {
- for (int i = 0; i < update.removedBubbles.size(); i++) {
- RemovedBubble removedBubble = update.removedBubbles.get(i);
- BubbleBarBubble bubble = mBubbles.remove(removedBubble.getKey());
- if (bubble != null) {
- mBubbleBarViewController.removeBubble(bubble);
- } else {
- Log.w(TAG, "trying to remove bubble that doesn't exist: "
- + removedBubble.getKey());
+
+ if (update.addedBubble != null && update.removedBubbles.size() == 1) {
+ // we're adding and removing a bubble at the same time. handle this as a single update.
+ RemovedBubble removedBubble = update.removedBubbles.get(0);
+ BubbleBarBubble bubbleToRemove = mBubbles.remove(removedBubble.getKey());
+ mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+ if (bubbleToRemove != null) {
+ mBubbleBarViewController.addBubbleAndRemoveBubble(update.addedBubble,
+ bubbleToRemove, isExpanding, suppressAnimation);
+ } else {
+ mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
+ suppressAnimation);
+ Log.w(TAG, "trying to remove bubble that doesn't exist: " + removedBubble.getKey());
+ }
+ } else {
+ if (!update.removedBubbles.isEmpty()) {
+ for (int i = 0; i < update.removedBubbles.size(); i++) {
+ RemovedBubble removedBubble = update.removedBubbles.get(i);
+ BubbleBarBubble bubble = mBubbles.remove(removedBubble.getKey());
+ if (bubble != null) {
+ mBubbleBarViewController.removeBubble(bubble);
+ } else {
+ Log.w(TAG, "trying to remove bubble that doesn't exist: "
+ + removedBubble.getKey());
+ }
}
}
- }
- if (update.addedBubble != null) {
- mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
- mBubbleBarViewController.addBubble(update.addedBubble, isExpanding, suppressAnimation);
- if (isCollapsed) {
- // If we're collapsed, the most recently added bubble will be selected.
- bubbleToSelect = update.addedBubble;
+ if (update.addedBubble != null) {
+ mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
+ mBubbleBarViewController.addBubble(update.addedBubble, isExpanding,
+ suppressAnimation);
}
-
}
+
+ if (update.addedBubble != null && isCollapsed) {
+ // If we're collapsed, the most recently added bubble will be selected.
+ bubbleToSelect = update.addedBubble;
+ }
+
if (update.currentBubbles != null && !update.currentBubbles.isEmpty()) {
// Iterate in reverse because new bubbles are added in front and the list is in order.
for (int i = update.currentBubbles.size() - 1; i >= 0; i--) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 0ea5031..753237a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -626,6 +626,7 @@
/**
* Set bubble bar relative pivot value for X and Y, applied as a fraction of view width/height
* respectively. If the value is not in range of 0 to 1 it will be normalized.
+ *
* @param x relative X pivot value in range 0..1
* @param y relative Y pivot value in range 0..1
*/
@@ -665,7 +666,9 @@
}
/** Add a new bubble to the bubble bar. */
- public void addBubble(View bubble, FrameLayout.LayoutParams lp) {
+ public void addBubble(View bubble) {
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
+ Gravity.LEFT);
if (isExpanded()) {
// if we're expanded scale the new bubble in
bubble.setScaleX(0f);
@@ -702,14 +705,58 @@
}
}
+ /** Add a new bubble and remove an old bubble from the bubble bar. */
+ public void addBubbleAndRemoveBubble(View addedBubble, View removedBubble) {
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams((int) mIconSize, (int) mIconSize,
+ Gravity.LEFT);
+ if (!isExpanded()) {
+ removeView(removedBubble);
+ addView(addedBubble, 0, lp);
+ return;
+ }
+ addedBubble.setScaleX(0f);
+ addedBubble.setScaleY(0f);
+ addView(addedBubble, 0, lp);
+
+ int indexOfSelectedBubble = indexOfChild(mSelectedBubbleView);
+ int indexOfBubbleToRemove = indexOfChild(removedBubble);
+
+ mBubbleAnimator = new BubbleAnimator(mIconSize, mExpandedBarIconsSpacing,
+ getChildCount(), mBubbleBarLocation.isOnLeft(isLayoutRtl()));
+ BubbleAnimator.Listener listener = new BubbleAnimator.Listener() {
+
+ @Override
+ public void onAnimationEnd() {
+ removeView(removedBubble);
+ updateWidth();
+ mBubbleAnimator = null;
+ }
+
+ @Override
+ public void onAnimationCancel() {
+ addedBubble.setScaleX(1);
+ addedBubble.setScaleY(1);
+ removedBubble.setScaleX(0);
+ removedBubble.setScaleY(0);
+ }
+
+ @Override
+ public void onAnimationUpdate(float animatedFraction) {
+ addedBubble.setScaleX(animatedFraction);
+ addedBubble.setScaleY(animatedFraction);
+ removedBubble.setScaleX(1 - animatedFraction);
+ removedBubble.setScaleY(1 - animatedFraction);
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ }
+ };
+ mBubbleAnimator.animateNewAndRemoveOld(indexOfSelectedBubble, indexOfBubbleToRemove,
+ listener);
+ }
+
// TODO: (b/280605790) animate it
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
- if (getChildCount() + 1 > MAX_BUBBLES) {
- // the last child view is the overflow bubble and we shouldn't remove that. remove the
- // second to last child view.
- removeViewInLayout(getChildAt(getChildCount() - 2));
- }
super.addView(child, index, params);
updateWidth();
updateBubbleAccessibilityStates();
@@ -848,16 +895,18 @@
// where the bubble will end up when the animation ends
final float targetX = expandedX + expandedBarShift;
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
- // When we're expanded, we're not stacked so we're not behind the stack
- bv.setBehindStack(false, animate);
+ // When we're expanded, the badge is visible for all bubbles
+ bv.updateBadgeVisibility(/* show= */ true);
+ bv.setDotScale(widthState);
bv.setAlpha(1);
} else {
// If bar is on the right, account for bubble bar expanding and shifting left
final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
final float targetX = collapsedX + collapsedBarShift;
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
- // If we're not the first bubble we're behind the stack
- bv.setBehindStack(i > 0, animate);
+ // The badge is always visible for the first bubble
+ bv.updateBadgeVisibility(/* show= */ i == 0);
+ bv.setDotScale(widthState);
// If we're fully collapsed, hide all bubbles except for the first 2. If there are
// only 2 bubbles, hide the second bubble as well because it's the overflow.
if (widthState == 0) {
@@ -911,7 +960,7 @@
final float iconAndSpacing = getScaledIconSize() + mExpandedBarIconsSpacing;
float translationX;
if (mBubbleAnimator != null && mBubbleAnimator.isRunning()) {
- return mBubbleAnimator.getExpandedBubbleTranslationX(bubbleIndex) + mBubbleBarPadding;
+ return mBubbleAnimator.getBubbleTranslationX(bubbleIndex) + mBubbleBarPadding;
} else if (onLeft) {
translationX = mBubbleBarPadding + (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index da0826b..dbc78db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -25,10 +25,8 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -386,7 +384,7 @@
/**
* Removes the provided bubble from the bubble bar.
*/
- public void removeBubble(BubbleBarItem b) {
+ public void removeBubble(BubbleBarBubble b) {
if (b != null) {
mBarView.removeBubble(b.getView());
} else {
@@ -394,13 +392,23 @@
}
}
+ /** Adds a new bubble and removes an old bubble at the same time. */
+ public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble,
+ BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation) {
+ mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView());
+ addedBubble.getView().setOnClickListener(mBubbleClickListener);
+ mBubbleDragController.setupBubbleView(addedBubble.getView());
+ if (!suppressAnimation) {
+ animateBubbleNotification(addedBubble, isExpanding);
+ }
+ }
+
/**
* Adds the provided bubble to the bubble bar.
*/
public void addBubble(BubbleBarItem b, boolean isExpanding, boolean suppressAnimation) {
if (b != null) {
- mBarView.addBubble(
- b.getView(), new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT));
+ mBarView.addBubble(b.getView());
b.getView().setOnClickListener(mBubbleClickListener);
mBubbleDragController.setupBubbleView(b.getView());
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 2f92fbb..0e26c54 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -35,8 +35,6 @@
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.animation.Interpolators;
-import java.util.EnumSet;
-
// TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
/**
@@ -47,22 +45,6 @@
public static final int DEFAULT_PATH_SIZE = 100;
- /**
- * Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
- * another. If any of these flags are set, the dot will not be shown.
- * If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
- */
- enum SuppressionFlag {
- // TODO: (b/277815200) implement flyout
- // Suppressed because the flyout is visible - it will morph into the dot via animation.
- FLYOUT_VISIBLE,
- // Suppressed because this bubble is behind others in the collapsed stack.
- BEHIND_STACK,
- }
-
- private final EnumSet<SuppressionFlag> mSuppressionFlags =
- EnumSet.noneOf(SuppressionFlag.class);
-
private final ImageView mBubbleIcon;
private final ImageView mAppIcon;
private final int mBubbleSize;
@@ -230,7 +212,7 @@
}
}
- void updateBadgeVisibility() {
+ void updateBadgeVisibility(boolean show) {
if (mBubble instanceof BubbleBarOverflow) {
// The overflow bubble does not have a badge, so just bail.
return;
@@ -241,39 +223,24 @@
? -(bubble.getIcon().getWidth() - appBadgeBitmap.getWidth())
: 0;
mAppIcon.setTranslationX(translationX);
- mAppIcon.setVisibility(isBehindStack() ? GONE : VISIBLE);
- }
-
- /** Sets whether this bubble is in the stack & not the first bubble. **/
- void setBehindStack(boolean behindStack, boolean animate) {
- if (behindStack) {
- mSuppressionFlags.add(SuppressionFlag.BEHIND_STACK);
- } else {
- mSuppressionFlags.remove(SuppressionFlag.BEHIND_STACK);
- }
- updateDotVisibility(animate);
- updateBadgeVisibility();
- }
-
- /** Whether this bubble is in the stack & not the first bubble. **/
- boolean isBehindStack() {
- return mSuppressionFlags.contains(SuppressionFlag.BEHIND_STACK);
+ mAppIcon.setVisibility(show ? VISIBLE : GONE);
}
/** Whether the dot indicating unseen content in a bubble should be shown. */
private boolean shouldDrawDot() {
boolean bubbleHasUnseenContent = mBubble != null
&& mBubble instanceof BubbleBarBubble
- && mSuppressionFlags.isEmpty()
&& !((BubbleBarBubble) mBubble).getInfo().isNotificationSuppressed();
-
// Always render the dot if it's animating, since it could be animating out. Otherwise, show
// it if the bubble wants to show it, and we aren't suppressing it.
return bubbleHasUnseenContent || mDotIsAnimating;
}
/** How big the dot should be, fraction from 0 to 1. */
- private void setDotScale(float fraction) {
+ void setDotScale(float fraction) {
+ if (!shouldDrawDot()) {
+ return;
+ }
mDotScale = fraction;
invalidate();
}
@@ -283,14 +250,14 @@
*/
private void animateDotScale() {
float toScale = shouldDrawDot() ? 1f : 0f;
- mDotIsAnimating = true;
+ boolean isDotScaleChanging = Float.compare(mDotScale, toScale) != 0;
- // Don't restart the animation if we're already animating to the given value.
- if (mAnimatingToDotScale == toScale || !shouldDrawDot()) {
- mDotIsAnimating = false;
+ // Don't restart the animation if we're already animating to the given value or if the dot
+ // scale is not changing
+ if ((mDotIsAnimating && mAnimatingToDotScale == toScale) || !isDotScaleChanging) {
return;
}
-
+ mDotIsAnimating = true;
mAnimatingToDotScale = toScale;
final boolean showDot = toScale > 0f;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
index 7672743..8af8ffb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimator.kt
@@ -56,6 +56,20 @@
animator.start()
}
+ fun animateNewAndRemoveOld(
+ selectedBubbleIndex: Int,
+ removedBubbleIndex: Int,
+ listener: Listener
+ ) {
+ animator = createAnimator(listener)
+ state =
+ State.AddingAndRemoving(
+ selectedBubbleIndex = selectedBubbleIndex,
+ removedBubbleIndex = removedBubbleIndex
+ )
+ animator.start()
+ }
+
private fun createAnimator(listener: Listener): ValueAnimator {
val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS)
animator.addUpdateListener { animation ->
@@ -83,28 +97,35 @@
}
/**
- * The translation X of the bubble at index [bubbleIndex] according to the progress of the
- * animation.
+ * The translation X of the bubble at index [bubbleIndex] when the bubble bar is expanded
+ * according to the progress of this animation.
*
* Callers should verify that the animation is running before calling this.
*
* @see isRunning
*/
- fun getExpandedBubbleTranslationX(bubbleIndex: Int): Float {
+ fun getBubbleTranslationX(bubbleIndex: Int): Float {
return when (val state = state) {
State.Idle -> 0f
is State.AddingBubble ->
- getExpandedBubbleTranslationXWhileScalingBubble(
+ getBubbleTranslationXWhileScalingBubble(
bubbleIndex = bubbleIndex,
scalingBubbleIndex = 0,
bubbleScale = animator.animatedFraction
)
is State.RemovingBubble ->
- getExpandedBubbleTranslationXWhileScalingBubble(
+ getBubbleTranslationXWhileScalingBubble(
bubbleIndex = bubbleIndex,
scalingBubbleIndex = state.bubbleIndex,
bubbleScale = 1 - animator.animatedFraction
)
+ is State.AddingAndRemoving ->
+ getBubbleTranslationXWhileAddingBubbleAtLimit(
+ bubbleIndex = bubbleIndex,
+ removedBubbleIndex = state.removedBubbleIndex,
+ addedBubbleScale = animator.animatedFraction,
+ removedBubbleScale = 1 - animator.animatedFraction
+ )
}
}
@@ -121,6 +142,14 @@
State.Idle -> 0f
is State.AddingBubble -> animator.animatedFraction
is State.RemovingBubble -> 1 - animator.animatedFraction
+ is State.AddingAndRemoving -> {
+ // since we're adding a bubble and removing another bubble, their sizes together
+ // equal to a single bubble. the width is the same as having bubbleCount - 1
+ // bubbles at full scale.
+ val totalSpace = (bubbleCount - 2) * expandedBarIconSpacing
+ val totalIconSize = (bubbleCount - 1) * iconSize
+ return totalIconSize + totalSpace
+ }
}
// When this animator is running the bubble bar is expanded so it's safe to assume that we
// have at least 2 bubbles, but should update the logic to support optional overflow.
@@ -144,7 +173,7 @@
State.Idle -> 0f
is State.AddingBubble -> {
val tx =
- getExpandedBubbleTranslationXWhileScalingBubble(
+ getBubbleTranslationXWhileScalingBubble(
bubbleIndex = state.selectedBubbleIndex,
scalingBubbleIndex = 0,
bubbleScale = animator.animatedFraction
@@ -152,6 +181,17 @@
tx + iconSize / 2f
}
is State.RemovingBubble -> getArrowPositionWhenRemovingBubble(state)
+ is State.AddingAndRemoving -> {
+ // we never remove the selected bubble, so the arrow stays pointing to its center
+ val tx =
+ getBubbleTranslationXWhileAddingBubbleAtLimit(
+ bubbleIndex = state.selectedBubbleIndex,
+ removedBubbleIndex = state.removedBubbleIndex,
+ addedBubbleScale = animator.animatedFraction,
+ removedBubbleScale = 1 - animator.animatedFraction
+ )
+ tx + iconSize / 2f
+ }
}
}
@@ -160,7 +200,7 @@
// if we're not removing the selected bubble, the selected bubble doesn't change so just
// return the translation X of the selected bubble and add half icon
val tx =
- getExpandedBubbleTranslationXWhileScalingBubble(
+ getBubbleTranslationXWhileScalingBubble(
bubbleIndex = state.selectedBubbleIndex,
scalingBubbleIndex = state.bubbleIndex,
bubbleScale = 1 - animator.animatedFraction
@@ -208,7 +248,7 @@
* @param scalingBubbleIndex the index of the bubble that is animating
* @param bubbleScale the current scale of the animating bubble
*/
- private fun getExpandedBubbleTranslationXWhileScalingBubble(
+ private fun getBubbleTranslationXWhileScalingBubble(
bubbleIndex: Int,
scalingBubbleIndex: Int,
bubbleScale: Float
@@ -256,6 +296,68 @@
}
}
+ private fun getBubbleTranslationXWhileAddingBubbleAtLimit(
+ bubbleIndex: Int,
+ removedBubbleIndex: Int,
+ addedBubbleScale: Float,
+ removedBubbleScale: Float
+ ): Float {
+ val iconAndSpacing = iconSize + expandedBarIconSpacing
+ // the bubbles are scaling from the center, so we need to adjust their translation so
+ // that the distance to the adjacent bubble scales at the same rate.
+ val addedBubblePivotAdjustment = -(1 - addedBubbleScale) * iconSize / 2f
+ val removedBubblePivotAdjustment = -(1 - removedBubbleScale) * iconSize / 2f
+
+ return if (onLeft) {
+ // this is how many bubbles there are to the left of the current bubble.
+ // when the bubble bar is on the right the added bubble is the right-most bubble so it
+ // doesn't affect the translation of any other bubble.
+ // when the removed bubble is to the left of the current bubble, we need to subtract it
+ // from bubblesToLeft and use removedBubbleScale instead when calculating the
+ // translation.
+ val bubblesToLeft = bubbleCount - bubbleIndex - 1
+ when {
+ bubbleIndex == 0 ->
+ // this is the added bubble and it's the right-most bubble. account for all the
+ // other bubbles -- including the removed bubble -- and adjust for the added
+ // bubble pivot.
+ (bubblesToLeft - 1 + removedBubbleScale) * iconAndSpacing +
+ addedBubblePivotAdjustment
+ bubbleIndex < removedBubbleIndex ->
+ // the removed bubble is to the left so account for it
+ (bubblesToLeft - 1 + removedBubbleScale) * iconAndSpacing
+ bubbleIndex == removedBubbleIndex -> {
+ // this is the removed bubble. all the bubbles to the left are at full scale
+ // but we need to scale the spacing between the removed bubble and the bubble to
+ // its left because the removed bubble disappears towards the left side
+ val totalIconSize = bubblesToLeft * iconSize
+ val totalSpacing =
+ (bubblesToLeft - 1 + removedBubbleScale) * expandedBarIconSpacing
+ totalIconSize + totalSpacing + removedBubblePivotAdjustment
+ }
+ else ->
+ // both added and removed bubbles are to the right so they don't affect the tx
+ bubblesToLeft * iconAndSpacing
+ }
+ } else {
+ when {
+ bubbleIndex == 0 -> addedBubblePivotAdjustment // we always add bubbles at index 0
+ bubbleIndex < removedBubbleIndex ->
+ // the bar is on the right and the removed bubble is on the right. the current
+ // bubble is unaffected by the removed bubble. only need to factor in the added
+ // bubble's scale.
+ iconAndSpacing * (bubbleIndex - 1 + addedBubbleScale)
+ bubbleIndex == removedBubbleIndex ->
+ // the bar is on the right, and this is the animating bubble.
+ iconAndSpacing * (bubbleIndex - 1 + addedBubbleScale) +
+ removedBubblePivotAdjustment
+ else ->
+ // both the added and the removed bubbles are to the left of the current bubble
+ iconAndSpacing * (bubbleIndex - 2 + addedBubbleScale + removedBubbleScale)
+ }
+ }
+ }
+
val isRunning: Boolean
get() = state != State.Idle
@@ -277,6 +379,10 @@
/** Whether the bubble being removed is also the last bubble. */
val removingLastBubble: Boolean
) : State
+
+ /** A new bubble is being added and an old bubble is being removed from the bubble bar. */
+ data class AddingAndRemoving(val selectedBubbleIndex: Int, val removedBubbleIndex: Int) :
+ State
}
/** Callbacks for the animation. */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
index dc6365b..181cba0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -79,6 +79,7 @@
import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT
import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
import com.android.launcher3.util.PluginManagerWrapper
import com.android.launcher3.util.StartActivityParams
import com.android.launcher3.util.UserIconInfo
@@ -394,6 +395,7 @@
HOTSEAT_LONGPRESS_TIP_SEEN.sharedPrefKey
)
addOnboardPref("Taskbar Education", TASKBAR_EDU_TOOLTIP_STEP.sharedPrefKey)
+ addOnboardPref("Taskbar Search Education", TASKBAR_SEARCH_EDU_SEEN.sharedPrefKey)
addOnboardPref("All Apps Visited Count", ALL_APPS_VISITED_COUNT.sharedPrefKey)
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index fb2a982..b6d83d3 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -138,8 +138,8 @@
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -2445,16 +2445,15 @@
finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
return;
}
- Optional<RemoteAnimationTarget> taskTargetOptional =
- Arrays.stream(appearedTaskTargets)
- .filter(mGestureState.mLastStartedTaskIdPredicate)
- .findFirst();
- if (!taskTargetOptional.isPresent()) {
+ RemoteAnimationTarget[] taskTargets = Arrays.stream(appearedTaskTargets)
+ .filter(mGestureState.mLastStartedTaskIdPredicate)
+ .toArray(RemoteAnimationTarget[]::new);
+ if (taskTargets.length == 0) {
ActiveGestureLog.INSTANCE.addLog("No appeared task matching started task id");
finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
return;
}
- RemoteAnimationTarget taskTarget = taskTargetOptional.get();
+ RemoteAnimationTarget taskTarget = taskTargets[0];
TaskView taskView = mRecentsView == null
? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId);
if (taskView == null
@@ -2468,13 +2467,13 @@
finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
return;
}
- animateSplashScreenExit(mContainer, appearedTaskTargets, taskTarget.leash);
+ animateSplashScreenExit(mContainer, appearedTaskTargets, taskTargets);
}
private void animateSplashScreenExit(
@NonNull T activity,
@NonNull RemoteAnimationTarget[] appearedTaskTargets,
- @NonNull SurfaceControl leash) {
+ @NonNull RemoteAnimationTarget[] animatingTargets) {
ViewGroup splashView = activity.getDragLayer();
final QuickstepLauncher quickstepLauncher = activity instanceof QuickstepLauncher
? (QuickstepLauncher) activity : null;
@@ -2492,26 +2491,28 @@
}
surfaceApplier.scheduleApply(transaction);
- SplashScreenExitAnimationUtils.startAnimations(splashView, leash,
- mSplashMainWindowShiftLength, new TransactionPool(), new Rect(),
- SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION,
- /* iconStartAlpha= */ 0, /* brandingStartAlpha= */ 0,
- SPLASH_APP_REVEAL_DELAY, SPLASH_APP_REVEAL_DURATION,
- new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Hiding launcher which shows the app surface behind, then
- // finishing recents to the app. After transition finish, showing
- // the views on launcher again, so it can be visible when next
- // animation starts.
- splashView.setAlpha(0);
- if (quickstepLauncher != null) {
- quickstepLauncher.getDepthController()
- .pauseBlursOnWindows(false);
+ for (RemoteAnimationTarget target : animatingTargets) {
+ SplashScreenExitAnimationUtils.startAnimations(splashView, target.leash,
+ mSplashMainWindowShiftLength, new TransactionPool(), target.screenSpaceBounds,
+ SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION,
+ /* iconStartAlpha= */ 0, /* brandingStartAlpha= */ 0,
+ SPLASH_APP_REVEAL_DELAY, SPLASH_APP_REVEAL_DURATION,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Hiding launcher which shows the app surface behind, then
+ // finishing recents to the app. After transition finish, showing
+ // the views on launcher again, so it can be visible when next
+ // animation starts.
+ splashView.setAlpha(0);
+ if (quickstepLauncher != null) {
+ quickstepLauncher.getDepthController()
+ .pauseBlursOnWindows(false);
+ }
+ finishRecentsAnimationOnTasksAppeared(() -> splashView.setAlpha(1));
}
- finishRecentsAnimationOnTasksAppeared(() -> splashView.setAlpha(1));
- }
- });
+ });
+ }
}
private void finishRecentsAnimationOnTasksAppeared(Runnable onFinishComplete) {
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 9c188f3..45e5554 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -23,7 +23,7 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
-import com.android.quickstep.views.TaskView.TaskContainer
+import com.android.quickstep.views.TaskContainer
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.DesktopModeStatus
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 7adce74..a7d3890 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,6 +33,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -412,7 +413,8 @@
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED
| SYSUI_STATE_MAGNIFICATION_OVERLAP
| SYSUI_STATE_DEVICE_DREAMING
- | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
+ | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
+ | SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 5d0d074..b7f3f65 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -44,8 +44,8 @@
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index b4862fd..77124bf 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -56,8 +56,8 @@
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index bfdc3df..ee93cd6 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -70,6 +70,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.util.ArraySet;
@@ -126,6 +127,7 @@
import com.android.quickstep.views.RecentsViewContainer;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputConsumerController;
@@ -330,6 +332,49 @@
});
}
+ @BinderThread
+ @Override
+ public void updateWallpaperVisibility(int displayId, boolean visible) {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(
+ taskbarManager -> taskbarManager.setWallpaperVisible(visible))
+ ));
+ }
+
+ @BinderThread
+ @Override
+ public void checkNavBarModes() {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(TaskbarManager::checkNavBarModes)
+ ));
+ }
+
+ @BinderThread
+ @Override
+ public void finishBarAnimations() {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(TaskbarManager::finishBarAnimations)
+ ));
+ }
+
+ @BinderThread
+ @Override
+ public void touchAutoDim(boolean reset) {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(taskbarManager -> taskbarManager.touchAutoDim(reset))
+ ));
+ }
+
+ @BinderThread
+ @Override
+ public void transitionTo(@BarTransitions.TransitionMode int barMode,
+ boolean animate) {
+ MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
+ executeForTaskbarManager(
+ taskbarManager -> taskbarManager.transitionTo(barMode, animate))
+ ));
+ }
+
/**
* Preloads the Overview activity.
* <p>
@@ -359,6 +404,12 @@
}
@Override
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ executeForTaskbarManager(taskbarManager ->
+ taskbarManager.onTransitionModeUpdated(barMode, checkBarModes));
+ }
+
+ @Override
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
executeForTaskbarManager(taskbarManager ->
taskbarManager.onNavButtonsDarkIntensityChanged(darkIntensity));
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 6f9cbfd..c3d74bb 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -22,7 +22,6 @@
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_LAUNCH;
import static com.android.launcher3.model.data.AppInfo.PACKAGE_KEY_COMPARATOR;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SUPPORTS_MULTI_INSTANCE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -45,8 +44,6 @@
import com.android.internal.jank.Cuj;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.apppairs.AppPairIcon;
@@ -69,6 +66,7 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.views.GroupedTaskView;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -135,7 +133,7 @@
}
GroupedTaskView gtv = (GroupedTaskView) taskView;
- List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+ List<TaskContainer> containers = gtv.getTaskContainers();
ComponentKey taskKey1 = TaskUtils.getLaunchComponentKeyForTask(
containers.get(0).getTask().key);
ComponentKey taskKey2 = TaskUtils.getLaunchComponentKeyForTask(
@@ -172,7 +170,7 @@
*/
public void saveAppPair(GroupedTaskView gtv) {
InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
- List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
+ List<TaskContainer> containers = gtv.getTaskContainers();
WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo();
WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo();
WorkspaceItemInfo app1 = resolveAppPairWorkspaceInfo(recentsInfo1);
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index 8d99069..307b2fa 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -22,6 +22,7 @@
import com.android.systemui.shared.recents.model.Task;
import java.util.List;
+import java.util.Objects;
/**
* A {@link Task} container that can contain N number of tasks that are part of the desktop in
@@ -68,4 +69,16 @@
return "type=" + taskViewType + " tasks=" + tasks;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DesktopTask that)) return false;
+ if (!super.equals(o)) return false;
+ return Objects.equals(tasks, that.tasks);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), tasks);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index 945ffe3..e8b611c 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -26,6 +26,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* A {@link Task} container that can contain one or two tasks, depending on if the two tasks
@@ -91,4 +92,17 @@
return "type=" + taskViewType + " task1=" + task1 + " task2=" + task2;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GroupTask that)) return false;
+ return taskViewType == that.taskViewType && Objects.equals(task1,
+ that.task1) && Objects.equals(task2, that.task2)
+ && Objects.equals(mSplitBounds, that.mSplitBounds);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(task1, task2, mSplitBounds, taskViewType);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 876a4ea..49e1c88 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -68,9 +68,9 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.SplitInstructionsView
+import com.android.quickstep.views.TaskContainer
import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskContainer
import com.android.quickstep.views.TaskViewIcon
import com.android.wm.shell.shared.TransitionUtil
import java.util.Optional
@@ -486,7 +486,8 @@
depthController: DepthController?,
info: TransitionInfo?,
t: Transaction?,
- finishCallback: Runnable
+ finishCallback: Runnable,
+ cornerRadius: Float
) {
if (info == null && t == null) {
// (Legacy animation) Tapping a split tile in Overview
@@ -550,7 +551,8 @@
"unexpected null"
}
- composeFadeInSplitLaunchAnimator(initialTaskId, secondTaskId, info, t, finishCallback)
+ composeFadeInSplitLaunchAnimator(initialTaskId, secondTaskId, info, t, finishCallback,
+ cornerRadius)
}
}
@@ -1024,11 +1026,12 @@
*/
@VisibleForTesting
fun composeFadeInSplitLaunchAnimator(
- initialTaskId: Int,
- secondTaskId: Int,
- transitionInfo: TransitionInfo,
- t: Transaction,
- finishCallback: Runnable
+ initialTaskId: Int,
+ secondTaskId: Int,
+ transitionInfo: TransitionInfo,
+ t: Transaction,
+ finishCallback: Runnable,
+ cornerRadius: Float
) {
var splitRoot1: Change? = null
var splitRoot2: Change? = null
@@ -1106,6 +1109,7 @@
override fun onAnimationStart(animation: Animator) {
for (leash in openingTargets) {
animTransaction.show(leash).setAlpha(leash, 0.0f)
+ animTransaction.setCornerRadius(leash, cornerRadius);
}
animTransaction.apply()
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 7e7c794..d906bb3 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -104,6 +104,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
@@ -778,7 +779,8 @@
info, t, () -> {
finishAdapter.run();
cleanup(true /*success*/);
- });
+ },
+ QuickStepContract.getWindowCornerRadius(mContainer.asContext()));
});
}
@@ -826,7 +828,8 @@
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
Runnable finishedCallback) {
postAsyncCallback(mHandler,
- () -> mSplitAnimationController.playSplitLaunchAnimation(mLaunchingTaskView,
+ () -> mSplitAnimationController
+ .playSplitLaunchAnimation(mLaunchingTaskView,
mLaunchingIconView, mInitialTaskId, mSecondTaskId, apps, wallpapers,
nonApps, mStateManager, mDepthController, null /* info */, null /* t */,
() -> {
@@ -835,7 +838,8 @@
mSuccessCallback.accept(true);
}
resetState();
- }));
+ },
+ QuickStepContract.getWindowCornerRadius(mContainer.asContext())));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 88c3a08..48ed67b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -453,8 +453,9 @@
}
// adjust the mSourceRectHint / mAppBounds by display cutout if applicable.
if (mSourceRectHint != null && mDisplayCutoutInsets != null) {
- if (mFromRotation == Surface.ROTATION_0 && mDisplayCutoutInsets.top >= 0) {
- // TODO: this is to special case the issues on Pixel Foldable device(s).
+ if (mFromRotation == Surface.ROTATION_0) {
+ // TODO: this is to special case the issues on Foldable device
+ // with display cutout.
mSourceRectHint.offset(mDisplayCutoutInsets.left, mDisplayCutoutInsets.top);
} else if (mFromRotation == Surface.ROTATION_90) {
mSourceRectHint.offset(mDisplayCutoutInsets.left, mDisplayCutoutInsets.top);
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 46ed2ee..55bbd50 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -193,6 +193,7 @@
}
val taskContainer =
TaskContainer(
+ this,
task,
// TODO(b/338360089): Support new TTV for DesktopTaskView
thumbnailView = null,
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index c1e112a..8553635 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -212,7 +212,6 @@
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.VibrationConstants;
-import com.android.quickstep.views.TaskView.TaskContainer;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
new file mode 100644
index 0000000..cfdee6c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.views
+
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Insets
+import android.view.View
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.model.data.ItemInfoWithIcon
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.TransformingTouchDelegate
+import com.android.quickstep.TaskOverlayFactory
+import com.android.quickstep.TaskUtils
+import com.android.quickstep.task.thumbnail.TaskThumbnail
+import com.android.quickstep.task.thumbnail.TaskThumbnailView
+import com.android.quickstep.task.viewmodel.TaskContainerData
+import com.android.systemui.shared.recents.model.Task
+
+/** Holder for all Task dependent information. */
+class TaskContainer(
+ val taskView: TaskView,
+ val task: Task,
+ val thumbnailView: TaskThumbnailView?,
+ val thumbnailViewDeprecated: TaskThumbnailViewDeprecated,
+ val iconView: TaskViewIcon,
+ /**
+ * This technically can be a vanilla [android.view.TouchDelegate] class, however that class
+ * requires setting the touch bounds at construction, so we'd repeatedly be created many
+ * instances unnecessarily as scrolling occurs, whereas [TransformingTouchDelegate] allows touch
+ * delegated bounds only to be updated.
+ */
+ val iconTouchDelegate: TransformingTouchDelegate,
+ /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
+ @SplitConfigurationOptions.StagePosition val stagePosition: Int,
+ val digitalWellBeingToast: DigitalWellBeingToast?,
+ val showWindowsView: View?,
+ taskOverlayFactory: TaskOverlayFactory
+) {
+ val overlay: TaskOverlayFactory.TaskOverlay<*> = taskOverlayFactory.createOverlay(this)
+ val taskContainerData = TaskContainerData()
+
+ val snapshotView: View
+ get() = thumbnailView ?: thumbnailViewDeprecated
+
+ // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+ val thumbnail: Bitmap?
+ get() = thumbnailViewDeprecated.thumbnail
+
+ // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+ val isRealSnapshot: Boolean
+ get() = thumbnailViewDeprecated.isRealSnapshot()
+
+ // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
+ val scaledInsets: Insets
+ get() = thumbnailViewDeprecated.scaledInsets
+
+ /** Builds proto for logging */
+ val itemInfo: WorkspaceItemInfo
+ get() =
+ WorkspaceItemInfo().apply {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK
+ container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER
+ val componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key)
+ user = componentKey.user
+ intent = Intent().setComponent(componentKey.componentName)
+ title = task.title
+ taskView.recentsView?.let { screenId = it.indexOfChild(taskView) }
+ if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+ if (
+ UserCache.getInstance(taskView.context)
+ .getUserInfo(componentKey.user)
+ .isPrivate
+ ) {
+ runtimeStatusFlags =
+ runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE
+ }
+ }
+ }
+
+ fun destroy() {
+ digitalWellBeingToast?.destroy()
+ thumbnailView?.let { taskView.removeView(it) }
+ }
+
+ fun bind() {
+ if (Flags.enableRefactorTaskThumbnail() && thumbnailView != null) {
+ thumbnailViewDeprecated.setTaskOverlay(overlay)
+ bindThumbnailView()
+ } else {
+ thumbnailViewDeprecated.bind(task, overlay)
+ }
+ }
+
+ // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
+ // so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
+ fun bindThumbnailView() {
+ // TODO(b/343364498): Existing view has shouldShowScreenshot as an override as well but
+ // this should be decided inside TaskThumbnailViewModel.
+ thumbnailView?.viewModel?.bind(TaskThumbnail(task.key.id, taskView.isRunningTask))
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 8d5ba77..63bc509 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -55,7 +55,6 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.TaskCornerRadius;
-import com.android.quickstep.views.TaskView.TaskContainer;
/**
* Contains options for a recent task when long-pressing its icon.
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 659cc0c..e10d38c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -37,7 +37,6 @@
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.util.Themes
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.views.TaskView.TaskContainer
class TaskMenuViewWithArrow<T> : ArrowPopup<T> where T : RecentsViewContainer, T : Context {
companion object {
@@ -58,7 +57,9 @@
}
constructor(context: Context) : super(context)
+
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+
constructor(
context: Context,
attrs: AttributeSet,
@@ -80,6 +81,7 @@
private var alignedOptionIndex: Int = 0
private val extraSpaceForRowAlignment: Int
get() = optionMeasuredHeight * alignedOptionIndex
+
private val menuPaddingEnd = context.resources.getDimensionPixelSize(R.dimen.task_card_margin)
private lateinit var taskView: TaskView
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index d4b0040..b922df4 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -22,10 +22,7 @@
import android.annotation.IdRes
import android.app.ActivityOptions
import android.content.Context
-import android.content.Intent
-import android.graphics.Bitmap
import android.graphics.Canvas
-import android.graphics.Insets
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.drawable.Drawable
@@ -52,16 +49,11 @@
import com.android.launcher3.Flags.enableGridOnlyOverview
import com.android.launcher3.Flags.enableOverviewIconMenu
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
-import com.android.launcher3.Flags.privateSpaceRestrictAccessibilityDrag
-import com.android.launcher3.LauncherSettings
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.ItemInfo
-import com.android.launcher3.model.data.ItemInfoWithIcon
-import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.pm.UserCache
import com.android.launcher3.testing.TestLogging
import com.android.launcher3.testing.shared.TestProtocol
import com.android.launcher3.util.CancellableTask
@@ -84,13 +76,9 @@
import com.android.quickstep.RemoteAnimationTargets
import com.android.quickstep.TaskAnimationManager
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.TaskOverlayFactory.TaskOverlay
-import com.android.quickstep.TaskUtils
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
-import com.android.quickstep.task.thumbnail.TaskThumbnail
import com.android.quickstep.task.thumbnail.TaskThumbnailView
-import com.android.quickstep.task.viewmodel.TaskContainerData
import com.android.quickstep.task.viewmodel.TaskViewData
import com.android.quickstep.util.ActiveGestureErrorDetector
import com.android.quickstep.util.ActiveGestureLog
@@ -702,6 +690,7 @@
}
val iconView = getOrInflateIconView(iconViewId)
return TaskContainer(
+ this,
task,
thumbnailView,
thumbnailViewDeprecated,
@@ -1606,90 +1595,6 @@
override fun close() {}
}
- /** Holder for all Task dependent information. */
- inner class TaskContainer(
- val task: Task,
- val thumbnailView: TaskThumbnailView?,
- val thumbnailViewDeprecated: TaskThumbnailViewDeprecated,
- val iconView: TaskViewIcon,
- /**
- * This technically can be a vanilla [android.view.TouchDelegate] class, however that class
- * requires setting the touch bounds at construction, so we'd repeatedly be created many
- * instances unnecessarily as scrolling occurs, whereas [TransformingTouchDelegate] allows
- * touch delegated bounds only to be updated.
- */
- val iconTouchDelegate: TransformingTouchDelegate,
- /** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
- @StagePosition val stagePosition: Int,
- val digitalWellBeingToast: DigitalWellBeingToast?,
- val showWindowsView: View?,
- taskOverlayFactory: TaskOverlayFactory
- ) {
- val overlay: TaskOverlay<*> = taskOverlayFactory.createOverlay(this)
- val taskContainerData = TaskContainerData()
-
- val snapshotView: View
- get() = thumbnailView ?: thumbnailViewDeprecated
-
- // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
- val thumbnail: Bitmap?
- get() = thumbnailViewDeprecated.thumbnail
-
- // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
- val isRealSnapshot: Boolean
- get() = thumbnailViewDeprecated.isRealSnapshot()
-
- // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
- val scaledInsets: Insets
- get() = thumbnailViewDeprecated.scaledInsets
-
- /** Builds proto for logging */
- val itemInfo: WorkspaceItemInfo
- get() =
- WorkspaceItemInfo().apply {
- itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK
- container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER
- val componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key)
- user = componentKey.user
- intent = Intent().setComponent(componentKey.componentName)
- title = task.title
- recentsView?.let { screenId = it.indexOfChild(this@TaskView) }
- if (privateSpaceRestrictAccessibilityDrag()) {
- if (
- UserCache.getInstance(context).getUserInfo(componentKey.user).isPrivate
- ) {
- runtimeStatusFlags =
- runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE
- }
- }
- }
-
- val taskView: TaskView
- get() = this@TaskView
-
- fun destroy() {
- digitalWellBeingToast?.destroy()
- thumbnailView?.let { taskView.removeView(it) }
- }
-
- fun bind() {
- if (enableRefactorTaskThumbnail() && thumbnailView != null) {
- thumbnailViewDeprecated.setTaskOverlay(overlay)
- bindThumbnailView()
- } else {
- thumbnailViewDeprecated.bind(task, overlay)
- }
- }
-
- // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
- // so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
- fun bindThumbnailView() {
- // TODO(b/343364498): Existing view has shouldShowScreenshot as an override as well but
- // this should be decided inside TaskThumbnailViewModel.
- thumbnailView?.viewModel?.bind(TaskThumbnail(task.key.id, isRunningTask))
- }
- }
-
companion object {
private const val TAG = "TaskView"
const val FLAG_UPDATE_ICON = 1
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
index 20bd617..d5a76a2 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleAnimatorTest.kt
@@ -80,6 +80,31 @@
assertThat(bubbleAnimator.isRunning).isFalse()
}
+ @Test
+ fun animateNewAndRemoveOld_isRunning() {
+ bubbleAnimator =
+ BubbleAnimator(
+ iconSize = 40f,
+ expandedBarIconSpacing = 10f,
+ bubbleCount = 5,
+ onLeft = false
+ )
+ val listener = TestBubbleAnimatorListener()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ bubbleAnimator.animateNewAndRemoveOld(
+ selectedBubbleIndex = 3,
+ removedBubbleIndex = 2,
+ listener
+ )
+ }
+
+ assertThat(bubbleAnimator.isRunning).isTrue()
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(250)
+ }
+ assertThat(bubbleAnimator.isRunning).isFalse()
+ }
+
private class TestBubbleAnimatorListener : BubbleAnimator.Listener {
override fun onAnimationUpdate(animatedFraction: Float) {}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt
new file mode 100644
index 0000000..7aed579
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/DesktopTaskTest.kt
@@ -0,0 +1,67 @@
+/*
+ * 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 android.content.ComponentName
+import android.content.Intent
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+class DesktopTaskTest {
+
+ @Test
+ fun testDesktopTask_sameInstance_isEqual() {
+ val task = DesktopTask(createTasks(1))
+ assertThat(task).isEqualTo(task)
+ }
+
+ @Test
+ fun testDesktopTask_identicalConstructor_isEqual() {
+ val task1 = DesktopTask(createTasks(1))
+ val task2 = DesktopTask(createTasks(1))
+ assertThat(task1).isEqualTo(task2)
+ }
+
+ @Test
+ fun testDesktopTask_copy_isEqual() {
+ val task1 = DesktopTask(createTasks(1))
+ val task2 = task1.copy()
+ assertThat(task1).isEqualTo(task2)
+ }
+
+ @Test
+ fun testDesktopTask_differentId_isNotEqual() {
+ val task1 = DesktopTask(createTasks(1))
+ val task2 = DesktopTask(createTasks(2))
+ assertThat(task1).isNotEqualTo(task2)
+ }
+
+ @Test
+ fun testDesktopTask_differentLength_isNotEqual() {
+ val task1 = DesktopTask(createTasks(1))
+ val task2 = DesktopTask(createTasks(1, 2))
+ assertThat(task1).isNotEqualTo(task2)
+ }
+
+ private fun createTasks(vararg ids: Int): List<Task> {
+ return ids.map { Task(Task.TaskKey(it, 0, Intent(), ComponentName("", ""), 0, 0)) }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
new file mode 100644
index 0000000..a6d3887
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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 android.content.ComponentName
+import android.content.Intent
+import android.graphics.Rect
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.recents.model.Task
+import com.android.wm.shell.common.split.SplitScreenConstants
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+class GroupTaskTest {
+
+ @Test
+ fun testGroupTask_sameInstance_isEqual() {
+ val task = GroupTask(createTask(1))
+ assertThat(task).isEqualTo(task)
+ }
+
+ @Test
+ fun testGroupTask_identicalConstructor_isEqual() {
+ val task1 = GroupTask(createTask(1))
+ val task2 = GroupTask(createTask(1))
+ assertThat(task1).isEqualTo(task2)
+ }
+
+ @Test
+ fun testGroupTask_copy_isEqual() {
+ val task1 = GroupTask(createTask(1))
+ val task2 = task1.copy()
+ assertThat(task1).isEqualTo(task2)
+ }
+
+ @Test
+ fun testGroupTask_differentId_isNotEqual() {
+ val task1 = GroupTask(createTask(1))
+ val task2 = GroupTask(createTask(2))
+ assertThat(task1).isNotEqualTo(task2)
+ }
+
+ @Test
+ fun testGroupTask_equalSplitTasks_isEqual() {
+ val splitBounds =
+ SplitConfigurationOptions.SplitBounds(
+ Rect(),
+ Rect(),
+ 1,
+ 2,
+ SplitScreenConstants.SNAP_TO_50_50
+ )
+ val task1 = GroupTask(createTask(1), createTask(2), splitBounds, TaskView.Type.GROUPED)
+ val task2 = GroupTask(createTask(1), createTask(2), splitBounds, TaskView.Type.GROUPED)
+ assertThat(task1).isEqualTo(task2)
+ }
+
+ @Test
+ fun testGroupTask_differentSplitTasks_isNotEqual() {
+ val splitBounds1 =
+ SplitConfigurationOptions.SplitBounds(
+ Rect(),
+ Rect(),
+ 1,
+ 2,
+ SplitScreenConstants.SNAP_TO_50_50
+ )
+ val splitBounds2 =
+ SplitConfigurationOptions.SplitBounds(
+ Rect(),
+ Rect(),
+ 1,
+ 2,
+ SplitScreenConstants.SNAP_TO_30_70
+ )
+ val task1 = GroupTask(createTask(1), createTask(2), splitBounds1, TaskView.Type.GROUPED)
+ val task2 = GroupTask(createTask(1), createTask(2), splitBounds2, TaskView.Type.GROUPED)
+ assertThat(task1).isNotEqualTo(task2)
+ }
+
+ @Test
+ fun testGroupTask_differentType_isNotEqual() {
+ val task1 = GroupTask(createTask(1), null, null, TaskView.Type.SINGLE)
+ val task2 = GroupTask(createTask(1), null, null, TaskView.Type.DESKTOP)
+ assertThat(task1).isNotEqualTo(task2)
+ }
+
+ private fun createTask(id: Int): Task {
+ return Task(Task.TaskKey(id, 0, Intent(), ComponentName("", ""), 0, 0))
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index c8893ad..fd7ecb0 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -33,8 +33,8 @@
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.views.GroupedTaskView
import com.android.quickstep.views.IconView
+import com.android.quickstep.views.TaskContainer
import com.android.quickstep.views.TaskView
-import com.android.quickstep.views.TaskView.TaskContainer
import com.android.systemui.shared.recents.model.Task
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -225,7 +225,8 @@
depthController,
null /* info */,
null /* t */,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -261,7 +262,8 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -289,7 +291,8 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -317,7 +320,8 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -344,7 +348,8 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -371,7 +376,8 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
@@ -383,7 +389,7 @@
val spySplitAnimationController = spy(splitAnimationController)
doNothing()
.whenever(spySplitAnimationController)
- .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+ .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
spySplitAnimationController.playSplitLaunchAnimation(
null /* launchingTaskView */,
@@ -397,10 +403,11 @@
depthController,
transitionInfo,
transaction,
- {} /* finishCallback */
+ {} /* finishCallback */,
+ 1f /* cornerRadius */
)
verify(spySplitAnimationController)
- .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+ .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
}
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 486dc68..13c4f72 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -44,6 +44,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -56,7 +57,6 @@
@Mock private lateinit var mockRecentsModel: RecentsModel
@Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
- private var nextTaskId: Int = 500
private var taskListChangeId: Int = 1
private lateinit var recentAppsController: TaskbarRecentAppsController
@@ -478,6 +478,82 @@
assertThat(shownPackages).containsExactlyElementsIn(expectedPackages)
}
+ @Test
+ fun onRecentTasksChanged_notInDesktopMode_noActualChangeToRecents_commitRunningAppsToUI_notCalled() {
+ setInDesktopMode(false)
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = emptyList(),
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op.
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = emptyList(),
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ }
+
+ @Test
+ fun onRecentTasksChanged_inDesktopMode_noActualChangeToRunning_commitRunningAppsToUI_notCalled() {
+ setInDesktopMode(true)
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op.
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ }
+
+ @Test
+ fun onRecentTasksChanged_onlyMinimizedChanges_commitRunningAppsToUI_isCalled() {
+ setInDesktopMode(true)
+ val runningTasks = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = runningTasks,
+ minimizedTaskIndices = setOf(0),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ // Call onRecentTasksChanged() again with a new minimized app, verify we update UI.
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = emptyList(),
+ runningTaskPackages = runningTasks,
+ minimizedTaskIndices = setOf(0, 1),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(2)).commitRunningAppsToUI()
+ }
+
+ @Test
+ fun onRecentTasksChanged_hotseatAppStartsRunning_commitRunningAppsToUI_isCalled() {
+ setInDesktopMode(true)
+ val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = hotseatPackages,
+ runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(1)).commitRunningAppsToUI()
+ // Call onRecentTasksChanged() again with a new running app, verify we update UI.
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = hotseatPackages,
+ runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, HOTSEAT_PACKAGE_1),
+ recentTaskPackages = emptyList()
+ )
+ verify(taskbarViewController, times(2)).commitRunningAppsToUI()
+ }
+
private fun prepareHotseatAndRunningAndRecentApps(
hotseatPackages: List<String>,
runningTaskPackages: List<String>,
@@ -556,9 +632,11 @@
}
private fun createTask(packageName: String, isVisible: Boolean = true): Task {
+ // Use the number at the end of the test packageName as the id.
+ val id = packageName[packageName.length - 1].code
return Task(
Task.TaskKey(
- nextTaskId++,
+ id,
WINDOWING_MODE_FREEFORM,
Intent().apply { `package` = packageName },
ComponentName(packageName, "TestActivity"),
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 50b5df1..f160ce2 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -32,6 +32,7 @@
import com.android.launcher3.util.TransformingTouchDelegate
import com.android.quickstep.TaskOverlayFactory.TaskOverlay
import com.android.quickstep.views.LauncherRecentsView
+import com.android.quickstep.views.TaskContainer
import com.android.quickstep.views.TaskThumbnailViewDeprecated
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskViewIcon
@@ -186,8 +187,9 @@
}
}
- private fun createTaskContainer(task: Task): TaskView.TaskContainer {
- return taskView.TaskContainer(
+ private fun createTaskContainer(task: Task): TaskContainer {
+ return TaskContainer(
+ taskView,
task,
thumbnailView = null,
thumbnailViewDeprecated,
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 07d8f61..6e25b10 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -31,6 +31,7 @@
import com.android.launcher3.Launcher;
import com.android.quickstep.views.DigitalWellBeingToast;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
import org.junit.Test;
@@ -86,7 +87,7 @@
final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
- TaskView.TaskContainer taskContainer = task.getTaskContainers().get(0);
+ TaskContainer taskContainer = task.getTaskContainers().get(0);
assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(
taskContainer.getTask().getTopComponent().getPackageName()));
return taskContainer.getDigitalWellBeingToast();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index b7fd8be..2087016 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -69,7 +69,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/288939273
public void testSplitTaskTapBothIconMenus() {
createAndLaunchASplitPair();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 8adf793..733ea4e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -72,7 +72,6 @@
}
@Test
- @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
assumeTrue(mLauncher.isTablet());
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 6f021ea..0f4204f 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -48,6 +48,7 @@
import android.content.Intent;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -89,6 +90,8 @@
* logic in the Personal tab.
*/
public class PrivateProfileManager extends UserProfileManager {
+
+ private static final String TAG = "PrivateProfileManager";
private static final int EXPAND_COLLAPSE_DURATION = 800;
private static final int SETTINGS_OPACITY_DURATION = 400;
private static final int TEXT_UNLOCK_OPACITY_DURATION = 300;
@@ -362,6 +365,7 @@
} else {
// Ensure any unwanted animations to not happen.
settingAndLockGroup.setLayoutTransition(null);
+ Log.d(TAG, "bindPrivateSpaceHeaderViewElements: removing transitions ");
}
updateView();
}
@@ -597,6 +601,9 @@
}
attachFloatingMaskView(expand);
ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
+ TextView lockText = mPSHeader.findViewById(R.id.lock_text);
+ PrivateSpaceSettingsButton privateSpaceSettingsButton =
+ mPSHeader.findViewById(R.id.ps_settings_button);
if (settingsAndLockGroup.getLayoutTransition() == null) {
// Set a new transition if the current ViewGroup does not already contain one as each
// transition should only happen once when applied.
@@ -612,13 +619,15 @@
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
+ Log.d(TAG, "updatePrivateStateAnimator: Private space animation expanding: "
+ + expand);
mStatsLogManager.logger().sendToInteractionJankMonitor(
expand
? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN
: LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN,
mAllApps.getActiveRecyclerView());
// Animate the collapsing of the text at the same time while updating lock button.
- mPSHeader.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+ lockText.setVisibility(expand ? VISIBLE : GONE);
setAnimationRunning(true);
}
@@ -636,6 +645,11 @@
? LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END
: LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END,
mAllApps.getActiveRecyclerView());
+ Log.d(TAG, "updatePrivateStateAnimator: lockText visibility: "
+ + lockText.getVisibility() + " lockTextAlpha: " + lockText.getAlpha());
+ Log.d(TAG, "updatePrivateStateAnimator: settingsCog visibility: "
+ + privateSpaceSettingsButton.getVisibility()
+ + " settingsCogAlpha: " + privateSpaceSettingsButton.getAlpha());
if (!expand) {
mAllApps.mAH.get(MAIN).mRecyclerView.removeItemDecoration(
mPrivateAppsSectionDecorator);
@@ -717,15 +731,19 @@
@Override
public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
View view, int i) {
+ Log.d(TAG, "updatePrivateStateAnimator: transition started: " + transition);
}
@Override
public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
View view, int i) {
settingsAndLockGroup.setLayoutTransition(null);
mReadyToAnimate = false;
+ Log.d(TAG, "updatePrivateStateAnimator: transition finished: " + transition);
}
});
settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
+ Log.d(TAG, "updatePrivateStateAnimator: setting transition: "
+ + settingsAndLockTransition);
}
/** Change the settings gear alpha when expanded or collapsed. */
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9824992..37a8d9b 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -60,6 +60,7 @@
*/
public class FolderAnimationManager {
+ private static final float EXTRA_FOLDER_REVEAL_RADIUS_PERCENTAGE = 0.125F;
private static final int FOLDER_NAME_ALPHA_DURATION = 32;
private static final int LARGE_FOLDER_FOOTER_DURATION = 128;
@@ -158,12 +159,9 @@
mFolder.mFooter.setPivotX(0);
mFolder.mFooter.setPivotY(0);
- // We want to create a small X offset for the preview items, so that they follow their
- // expected path to their final locations. ie. an icon should not move right, if it's final
- // location is to its left. This value is arbitrarily defined.
- int previewItemOffsetX = (int) (previewSize / 2);
+ int previewItemOffsetX = 0;
if (Utilities.isRtl(mContext.getResources())) {
- previewItemOffsetX = (int) (lp.width * initialScale - initialSize - previewItemOffsetX);
+ previewItemOffsetX = (int) (lp.width * initialScale - initialSize);
}
final int paddingOffsetX = (int) (mContent.getPaddingLeft() * initialScale);
@@ -239,29 +237,19 @@
play(a, shapeDelegate.createRevealAnimator(
mFolder, startRect, endRect, finalRadius, !mIsOpening));
- // 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;
+ int left = page * lp.width;
+
+ int extraRadius = (int) ((mDeviceProfile.folderIconSizePx / initialScale)
+ * EXTRA_FOLDER_REVEAL_RADIUS_PERCENTAGE);
Rect contentStart = new Rect(
- left + rtlExtraWidth,
- 0,
- left + width + mContent.getPaddingRight() + rtlExtraWidth,
- height);
+ (int) (left + (startRect.left / initialScale)) - extraRadius,
+ (int) (startRect.top / initialScale) - extraRadius,
+ (int) (left + (startRect.right / initialScale)) + extraRadius,
+ (int) (startRect.bottom / initialScale) + extraRadius);
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/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index f46dcd3..78709b8 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -46,7 +46,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -67,10 +66,7 @@
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.views.FloatingIconView;
-import com.android.launcher3.views.Snackbar;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.PendingAddShortcutInfo;
-import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.PendingAppWidgetHostView;
import com.android.launcher3.widget.WidgetAddFlowHandler;
import com.android.launcher3.widget.WidgetManagerHelper;
@@ -127,20 +123,6 @@
}
} else if (tag instanceof ItemClickProxy) {
((ItemClickProxy) tag).onItemClicked(v);
- } else if (tag instanceof PendingAddShortcutInfo) {
- CharSequence msg = Utilities.wrapForTts(
- launcher.getText(R.string.long_press_shortcut_to_add),
- launcher.getString(R.string.long_accessible_way_to_add_shortcut));
- Snackbar.show(launcher, msg, null);
- } else if (tag instanceof PendingAddWidgetInfo) {
- if (DEBUG) {
- String targetPackage = ((PendingAddWidgetInfo) tag).getTargetPackage();
- Log.d(TAG, "onClick: PendingAddWidgetInfo clicked for package=" + targetPackage);
- }
- CharSequence msg = Utilities.wrapForTts(
- launcher.getText(R.string.long_press_widget_to_add),
- launcher.getString(R.string.long_accessible_way_to_add));
- Snackbar.show(launcher, msg, null);
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
index 28d1faa..d40d3bc 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
@@ -23,8 +23,6 @@
import static com.android.launcher3.provider.LauncherDbUtils.itemIdMatch;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -56,7 +54,6 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.util.rule.TestStabilityRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
@@ -143,7 +140,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/310242894
public void testPendingWidget_withConfigScreen() {
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
// Do not bind the widget
@@ -193,7 +189,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/310242894
public void testPendingWidget_notRestored_brokenInstall() {
// A widget which is was being installed once, even if its not being
// installed at the moment is not removed.
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index e92d641..bc26c00 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -247,7 +247,6 @@
}
@ScreenRecordRule.ScreenRecord // b/329935119
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/329935119
@Test
@PortraitLandscape
public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
@@ -353,8 +352,11 @@
}
private void assertPagesExist(Launcher launcher, int... pageIds) {
+ waitForLauncherCondition("Existing page count does NOT match. "
+ + "Expected: " + pageIds.length
+ + ". Actual: " + launcher.getWorkspace().getPageCount(),
+ l -> pageIds.length == l.getWorkspace().getPageCount());
int pageCount = launcher.getWorkspace().getPageCount();
- assertEquals("Existing page count does NOT match.", pageIds.length, pageCount);
for (int i = 0; i < pageCount; i++) {
CellLayout page = (CellLayout) launcher.getWorkspace().getPageAt(i);
int pageId = launcher.getWorkspace().getCellLayoutId(page);