diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt index 23dc81d4e6..c9f791c6ee 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.kt @@ -21,6 +21,7 @@ import com.android.app.animation.Interpolators.FINAL_FRAME import com.android.app.animation.Interpolators.INSTANT import com.android.app.animation.Interpolators.LINEAR import com.android.launcher3.Flags.enableDesktopExplodedView +import com.android.launcher3.Flags.enableGridOnlyOverview import com.android.launcher3.Flags.enableLargeDesktopWindowingTile import com.android.launcher3.LauncherState import com.android.launcher3.anim.AnimatedFloat @@ -143,7 +144,11 @@ class RecentsViewStateController(private val launcher: QuickstepLauncher) : recentsView, TASK_MODALNESS, toState.overviewModalness, - config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR), + config.getInterpolator( + ANIM_OVERVIEW_MODAL, + if (enableGridOnlyOverview() && !toState.isRecentsViewVisible) FINAL_FRAME + else LINEAR, + ), ) val fromState = launcher.stateManager.state diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java index 0c0b4fd203..ae82f82c01 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java @@ -15,11 +15,11 @@ */ package com.android.launcher3.uioverrides.states; +import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW; import android.graphics.Rect; -import com.android.launcher3.Flags; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.views.ActivityContext; @@ -50,6 +50,9 @@ public class OverviewModalTaskState extends OverviewState { @Override public float[] getOverviewScaleAndOffset(Launcher launcher) { + if (enableGridOnlyOverview()) { + return super.getOverviewScaleAndOffset(launcher); + } return getOverviewScaleAndOffsetForModalState(launcher.getOverviewPanel()); } @@ -65,7 +68,7 @@ public class OverviewModalTaskState extends OverviewState { @Override public boolean isTaskbarStashed(Launcher launcher) { - if (Flags.enableGridOnlyOverview()) { + if (enableGridOnlyOverview()) { return true; } return super.isTaskbarStashed(launcher); diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java index 554cea262f..7db1813a90 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java @@ -19,6 +19,7 @@ import static com.android.app.animation.Interpolators.FINAL_FRAME; import static com.android.app.animation.Interpolators.INSTANT; import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.Flags.enableDesktopExplodedView; +import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.launcher3.Flags.enableLargeDesktopWindowingTile; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE; @@ -118,7 +119,9 @@ public class FallbackRecentsStateController implements StateHandler { @Override public float[] getOverviewScaleAndOffset(RecentsViewContainer container) { + if (enableGridOnlyOverview()) { + return super.getOverviewScaleAndOffset(container); + } return getOverviewScaleAndOffsetForModalState(container.getOverviewPanel()); } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index 74de2aca7b..c1282b945a 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -18,6 +18,7 @@ package com.android.quickstep.views; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY; +import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON; import static com.android.launcher3.LauncherState.ADD_DESK_BUTTON; import static com.android.launcher3.LauncherState.NORMAL; @@ -151,7 +152,14 @@ public class LauncherRecentsView extends RecentsView> CONTENT_ALPHA = @@ -534,7 +534,6 @@ public abstract class RecentsView< protected final Rect mLastComputedTaskSize = new Rect(); protected final Rect mLastComputedGridSize = new Rect(); protected final Rect mLastComputedGridTaskSize = new Rect(); - private TaskView mSelectedTask = null; // How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot. @Nullable protected Float mLastComputedTaskStartPushOutDistance = null; @@ -2418,21 +2417,28 @@ public abstract class RecentsView< } /** - * Sets the last TaskView selected. + * Returns the currently selected TaskView in Select mode. + */ + @Nullable + public TaskView getSelectedTaskView() { + return mUtils.getSelectedTaskView(); + } + + /** + * Sets the selected TaskView in Select mode. */ public void setSelectedTask(int lastSelectedTaskId) { - mSelectedTask = getTaskViewByTaskId(lastSelectedTaskId); + mUtils.setSelectedTaskView(getTaskViewByTaskId(lastSelectedTaskId)); } /** * Returns the bounds of the task selected to enter modal state. */ public Rect getSelectedTaskBounds() { - if (mSelectedTask == null) { - return enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet - ? mLastComputedGridTaskSize : mLastComputedTaskSize; + if (getSelectedTaskView() == null) { + return mLastComputedTaskSize; } - return getTaskBounds(mSelectedTask); + return getTaskBounds(getSelectedTaskView()); } /** @@ -2448,7 +2454,7 @@ public abstract class RecentsView< return deviceProfile.overviewTaskThumbnailTopMarginPx / 2.0f; } - private Rect getTaskBounds(TaskView taskView) { + protected Rect getTaskBounds(TaskView taskView) { int selectedPage = indexOfChild(taskView); int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this); int selectedPageScroll = getScrollForPage(selectedPage); @@ -5011,15 +5017,8 @@ public abstract class RecentsView< } private void updatePivots() { - if (mOverviewSelectEnabled) { - if (enableGridOnlyOverview()) { - getModalTaskSize(mTempRect); - Rect selectedTaskPosition = getSelectedTaskBounds(); - Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition, - mTempPointF); - } else { - mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom); - } + if (mOverviewSelectEnabled && !enableGridOnlyOverview()) { + mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom); } else { mTempRect.set(mLastComputedTaskSize); getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect, @@ -5065,7 +5064,7 @@ public abstract class RecentsView< && (enableGridOnlyOverview() || enableLargeDesktopWindowingTile()) && mTaskModalness > 0; if (shouldCalculateOffsetForAllTasks) { - modalMidpoint = indexOfChild(mSelectedTask); + modalMidpoint = indexOfChild(getSelectedTaskView()); } float midpointOffsetSize = 0; @@ -5273,7 +5272,7 @@ public abstract class RecentsView< */ private float getVerticalOffsetSize(TaskView taskView, float offsetProgress) { if (offsetProgress == 0 || !(showAsGrid() && enableGridOnlyOverview()) - || mSelectedTask == null) { + || getSelectedTaskView() == null) { // Don't bother calculating everything below if we won't offset vertically. return 0; } @@ -5281,7 +5280,7 @@ public abstract class RecentsView< // First, get the position of the task relative to the top row. Rect taskPosition = getTaskBounds(taskView); - boolean isSelectedTaskTopRow = mTopRowIdSet.contains(mSelectedTask.getTaskViewId()); + boolean isSelectedTaskTopRow = mTopRowIdSet.contains(getSelectedTaskView().getTaskViewId()); boolean isChildTopRow = mTopRowIdSet.contains(taskView.getTaskViewId()); // Whether the task should be shifted to the top. boolean isTopShift = !isSelectedTaskTopRow && isChildTopRow; @@ -5335,8 +5334,8 @@ public abstract class RecentsView< * Resets the visuals when exit modal state. */ public void resetModalVisuals() { - if (mSelectedTask != null) { - mSelectedTask.taskContainers.forEach( + if (getSelectedTaskView() != null) { + getSelectedTaskView().taskContainers.forEach( taskContainer -> taskContainer.getOverlay().resetModalVisuals()); } } @@ -6717,8 +6716,14 @@ public abstract class RecentsView< private void setTaskModalness(float modalness) { mTaskModalness = modalness; updatePageOffsets(); - if (mSelectedTask != null) { - mSelectedTask.setModalness(modalness); + if (getSelectedTaskView() != null) { + if (enableGridOnlyOverview()) { + for (TaskView taskView : getTaskViews()) { + taskView.setModalness(modalness); + } + } else { + getSelectedTaskView().setModalness(modalness); + } } else if (getCurrentPageTaskView() != null) { getCurrentPageTaskView().setModalness(modalness); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt index 9c35913841..51a5d0f0d6 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt @@ -16,6 +16,7 @@ package com.android.quickstep.views +import android.graphics.PointF import android.graphics.Rect import android.util.FloatProperty import android.view.KeyEvent @@ -25,9 +26,11 @@ import android.view.View.LAYOUT_DIRECTION_RTL import androidx.core.view.children import com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU import com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType +import com.android.launcher3.Flags.enableGridOnlyOverview import com.android.launcher3.Flags.enableLargeDesktopWindowingTile import com.android.launcher3.Flags.enableOverviewIconMenu import com.android.launcher3.Flags.enableSeparateExternalDisplayTasks +import com.android.launcher3.Utilities.getPivotsForScalingRectToRect import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.statehandlers.DesktopVisibilityController.Companion.INACTIVE_DESK_ID import com.android.launcher3.util.IntArray @@ -38,6 +41,7 @@ import com.android.quickstep.util.isExternalDisplay import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA import com.android.systemui.shared.recents.model.ThumbnailData import java.util.function.BiConsumer +import kotlin.math.min import kotlin.reflect.KMutableProperty1 /** @@ -393,6 +397,47 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { taskViews.filterIsInstance().forEach { it.explodeProgress = field } } + var selectedTaskView: TaskView? = null + set(newValue) { + val oldValue = field + field = newValue + if (oldValue != newValue) { + onSelectedTaskViewUpdated(oldValue, newValue) + } + } + + private fun onSelectedTaskViewUpdated( + oldSelectedTaskView: TaskView?, + newSelectedTaskView: TaskView?, + ) { + if (!enableGridOnlyOverview()) return + with(recentsView) { + oldSelectedTaskView?.modalScale = 1f + oldSelectedTaskView?.modalPivot = null + + if (newSelectedTaskView == null) return + + val modalTaskBounds = mTempRect + getModalTaskSize(modalTaskBounds) + val selectedTaskBounds = getTaskBounds(newSelectedTaskView) + + // Map bounds to selectedTaskView's coordinate system. + modalTaskBounds.offset(-selectedTaskBounds.left, -selectedTaskBounds.top) + selectedTaskBounds.offset(-selectedTaskBounds.left, -selectedTaskBounds.top) + + val modalScale = + min( + (modalTaskBounds.height().toFloat() / selectedTaskBounds.height()), + (modalTaskBounds.width().toFloat() / selectedTaskBounds.width()), + ) + val modalPivot = PointF() + getPivotsForScalingRectToRect(modalTaskBounds, selectedTaskBounds, modalPivot) + + newSelectedTaskView.modalScale = modalScale + newSelectedTaskView.modalPivot = modalPivot + } + } + companion object { class RecentsViewFloatProperty( private val utilsProperty: KMutableProperty1 diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index 3d1643cefe..3835e48a9e 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -33,6 +33,7 @@ import android.util.Log import android.view.Display import android.view.MotionEvent import android.view.View +import android.view.View.OnClickListener import android.view.ViewGroup import android.view.ViewStub import android.view.accessibility.AccessibilityNodeInfo @@ -147,6 +148,9 @@ constructor( val isRunningTask: Boolean get() = this === recentsView?.runningTaskView + private val isSelectedTask: Boolean + get() = this === recentsView?.selectedTaskView + open val displayId: Int get() = taskContainers.firstOrNull()?.task.displayId @@ -337,6 +341,12 @@ constructor( onModalnessUpdated(field) } + var modalPivot: PointF? = null + set(value) { + field = value + updatePivots() + } + var splitSplashAlpha = 0f set(value) { field = value @@ -361,6 +371,12 @@ constructor( applyScale() } + var modalScale = 1f + set(value) { + field = value + applyScale() + } + private var dismissTranslationX = 0f set(value) { field = value @@ -446,9 +462,10 @@ constructor( } private val taskViewAlpha = MultiValueAlpha(this, Alpha.entries.size) - protected var stableAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.STABLE) - var attachAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.ATTACH) - var splitAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.SPLIT) + protected var stableAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.Stable) + var attachAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.Attach) + var splitAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.Split) + private var modalAlpha by MultiPropertyDelegate(taskViewAlpha, Alpha.Modal) protected var shouldShowScreenshot = false get() = !isRunningTask || field @@ -628,14 +645,7 @@ constructor( override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) - val thumbnailTopMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx - if (container.deviceProfile.isTablet) { - pivotX = (if (layoutDirection == LAYOUT_DIRECTION_RTL) 0 else right - left).toFloat() - pivotY = thumbnailTopMargin.toFloat() - } else { - pivotX = (right - left) * 0.5f - pivotY = thumbnailTopMargin + (height - thumbnailTopMargin) * 0.5f - } + updatePivots() systemGestureExclusionRects = SYSTEM_GESTURE_EXCLUSION_RECT.onEach { it.right = width @@ -646,6 +656,24 @@ constructor( } } + private fun updatePivots() { + val modalPivot = modalPivot + if (modalPivot != null) { + pivotX = modalPivot.x + pivotY = modalPivot.y + } else { + val thumbnailTopMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx + if (container.deviceProfile.isTablet) { + pivotX = + (if (layoutDirection == LAYOUT_DIRECTION_RTL) 0 else right - left).toFloat() + pivotY = thumbnailTopMargin.toFloat() + } else { + pivotX = (right - left) * 0.5f + pivotY = thumbnailTopMargin + (height - thumbnailTopMargin) * 0.5f + } + } + } + override fun onRecycle() { resetPersistentViewTransforms() @@ -653,6 +681,9 @@ constructor( attachAlpha = 1f splitAlpha = 1f splitSplashAlpha = 0f + modalAlpha = 1f + modalScale = 1f + modalPivot = null taskThumbnailSplashAlpha = 0f // Clear any references to the thumbnail (it will be re-read either from the cache or the // system on next bind) @@ -1286,7 +1317,7 @@ constructor( targets.apps, targets.wallpapers, targets.nonApps, - true /* launcherClosing */, + true, /* launcherClosing */ recentsView.stateManager, recentsView, recentsView.depthController, @@ -1722,7 +1753,7 @@ constructor( fun getSizeAdjustment(fullscreenEnabled: Boolean) = if (fullscreenEnabled) nonGridScale else 1f private fun applyScale() { - val scale = persistentScale * dismissScale + val scale = persistentScale * dismissScale * Utilities.mapRange(modalness, 1f, modalScale) scaleX = scale scaleY = scale updateFullscreenParams() @@ -1784,9 +1815,13 @@ constructor( private fun onModalnessUpdated(modalness: Float) { isClickable = modalness == 0f taskContainers.forEach { - it.iconView.setModalAlpha(1 - modalness) + it.iconView.setModalAlpha(1f - modalness) it.digitalWellBeingToast?.bannerOffsetPercentage = modalness } + if (enableGridOnlyOverview()) { + modalAlpha = if (isSelectedTask) 1f else (1f - modalness) + applyScale() + } } fun resetPersistentViewTransforms() { @@ -1842,9 +1877,10 @@ constructor( private const val TAG = "TaskView" private enum class Alpha { - STABLE, - ATTACH, - SPLIT, + Stable, + Attach, + Split, + Modal, } private enum class SettledProgress {