From 1ca66992c18872ad1e22e3911908269b30f39f54 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Wed, 10 Jan 2024 14:04:12 -0500 Subject: [PATCH] Update KQS overview launch animation Updated the KQS overview launch animation to match the spec: open overview and scroll to the focused task in one fluid motion Flag: LEGACY ENABLE_KEYBOARD_QUICK_SWITCH ENABLED Fixes: 313608085 Test: Opened KQS from home and overview Change-Id: I2d617db29ff46e89fab50bb6f8aee900b6fe649f --- .../KeyboardQuickSwitchController.java | 4 +- .../android/quickstep/AbsSwipeUpHandler.java | 75 ++++++++++- .../quickstep/BaseActivityInterface.java | 4 +- .../quickstep/FallbackActivityInterface.java | 2 +- .../quickstep/LauncherActivityInterface.java | 5 +- .../quickstep/OverviewCommandHelper.java | 120 +++++++++++------- .../quickstep/util/TaskViewSimulator.java | 12 +- .../android/quickstep/views/RecentsView.java | 84 ++++++++++-- .../TaplTestsKeyboardQuickSwitch.java | 7 +- res/values-sw600dp/config.xml | 3 + res/values/config.xml | 3 + src/com/android/launcher3/PagedView.java | 21 ++- .../android/launcher3/tapl/BaseOverview.java | 31 +++++ 13 files changed, 289 insertions(+), 82 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java index 5caf0045cb..f15d12b12d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java @@ -22,6 +22,7 @@ import android.content.pm.ActivityInfo; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; import com.android.launcher3.statehandlers.DesktopVisibilityController; @@ -47,7 +48,8 @@ import java.util.stream.Collectors; public final class KeyboardQuickSwitchController implements TaskbarControllers.LoggableTaskbarController { - static final int MAX_TASKS = 6; + @VisibleForTesting + public static final int MAX_TASKS = 6; @NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks(); diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 60d0e2ba45..6698600f90 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -22,7 +22,9 @@ import static android.view.Surface.ROTATION_90; import static android.widget.Toast.LENGTH_SHORT; import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE; +import static com.android.app.animation.Interpolators.EMPHASIZED; import static com.android.app.animation.Interpolators.DECELERATE; +import static com.android.app.animation.Interpolators.LINEAR; import static com.android.app.animation.Interpolators.OVERSHOOT_1_2; import static com.android.launcher3.BaseActivity.EVENT_DESTROYED; import static com.android.launcher3.BaseActivity.EVENT_STARTED; @@ -134,6 +136,7 @@ import com.android.quickstep.util.SurfaceTransaction; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TaskViewSimulator; +import com.android.quickstep.util.TransformParams; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; @@ -167,6 +170,9 @@ public abstract class AbsSwipeUpHandler, private static final ArrayList STATE_NAMES = new ArrayList<>(); + // Fraction of the scroll and transform animation in which the current task fades out + private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f; + protected final BaseActivityInterface mActivityInterface; protected final InputConsumerProxy mInputConsumerProxy; protected final ActivityInitListener mActivityInitListener; @@ -900,7 +906,10 @@ public abstract class AbsSwipeUpHandler, return; } mLauncherTransitionController.setProgress( - Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor); + // Immediately finish the grid transition + isKeyboardTaskFocusPending() + ? 1f : Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), + mDragLengthFactor); } /** @@ -1349,7 +1358,9 @@ public abstract class AbsSwipeUpHandler, } Interpolator interpolator; S state = mActivityInterface.stateFromGestureEndTarget(endTarget); - if (state.displayOverviewTasksAsGrid(mDp)) { + if (isKeyboardTaskFocusPending()) { + interpolator = EMPHASIZED; + } else if (state.displayOverviewTasksAsGrid(mDp)) { interpolator = ACCELERATE_DECELERATE; } else if (endTarget == RECENTS) { interpolator = OVERSHOOT_1_2; @@ -1653,7 +1664,8 @@ public abstract class AbsSwipeUpHandler, animatorSet.play(windowAnim); if (mRecentsView != null) { mRecentsView.onPrepareGestureEndAnimation( - animatorSet, mGestureState.getEndTarget(), + mGestureState.isHandlingAtomicEvent() ? null : animatorSet, + mGestureState.getEndTarget(), getRemoteTaskViewSimulators()); } animatorSet.setDuration(duration).setInterpolator(interpolator); @@ -2225,6 +2237,14 @@ public abstract class AbsSwipeUpHandler, } } + private boolean shouldLinkRecentsViewScroll() { + return mRecentsViewScrollLinked && !isKeyboardTaskFocusPending(); + } + + private boolean isKeyboardTaskFocusPending() { + return mRecentsView != null && mRecentsView.isKeyboardTaskFocusPending(); + } + private void onRecentsViewScroll() { if (moveWindowWithRecentsScroll()) { onCurrentShiftUpdated(); @@ -2457,6 +2477,44 @@ public abstract class AbsSwipeUpHandler, mActivityInitListener.register(); } + private boolean shouldFadeOutTargetsForKeyboardQuickSwitch( + TransformParams transformParams, + TaskViewSimulator taskViewSimulator, + float progress) { + RemoteAnimationTargets targets = transformParams.getTargetSet(); + boolean fadeAppTargets = isKeyboardTaskFocusPending() + && targets != null + && targets.apps != null + && targets.apps.length > 0; + float fadeProgress = Utilities.mapBoundToRange( + progress, + /* lowerBound= */ 0f, + /* upperBound= */ KQS_TASK_FADE_ANIMATION_FRACTION, + /* toMin= */ 0f, + /* toMax= */ 1f, + LINEAR); + if (!fadeAppTargets || Float.compare(fadeProgress, 1f) == 0) { + return false; + } + SurfaceTransaction surfaceTransaction = + transformParams.createSurfaceParams(taskViewSimulator); + SurfaceControl.Transaction transaction = surfaceTransaction.getTransaction(); + + for (RemoteAnimationTarget app : targets.apps) { + transaction.setAlpha(app.leash, 1f - fadeProgress); + transaction.setPosition(app.leash, + /* x= */ app.startBounds.left + + (mActivity.getDeviceProfile().overviewPageSpacing + * (mRecentsView.isRtl() ? fadeProgress : -fadeProgress)), + /* y= */ 0f); + transaction.setScale(app.leash, 1f, 1f); + taskViewSimulator.taskPrimaryTranslation.value = + mRecentsView.getScrollOffsetForKeyboardTaskFocus(); + taskViewSimulator.apply(transformParams, surfaceTransaction); + } + return true; + } + /** * Applies the transform on the recents animation */ @@ -2466,7 +2524,7 @@ public abstract class AbsSwipeUpHandler, // swipe-to-icon animation is handled by RectFSpringAnim anim boolean notSwipingToHome = mRecentsAnimationTargets != null && mGestureState.getEndTarget() != HOME; - boolean setRecentsScroll = mRecentsViewScrollLinked && mRecentsView != null; + boolean setRecentsScroll = shouldLinkRecentsViewScroll() && mRecentsView != null; float progress = Math.max(mCurrentShift.value, getScaleProgressDueToScroll()); int scrollOffset = setRecentsScroll ? mRecentsView.getScrollOffset() : 0; if (!mStartMovingTasks && (progress > 0 || scrollOffset != 0)) { @@ -2485,7 +2543,12 @@ public abstract class AbsSwipeUpHandler, if (setRecentsScroll) { taskViewSimulator.setScroll(scrollOffset); } - taskViewSimulator.apply(remoteHandle.getTransformParams()); + TransformParams transformParams = remoteHandle.getTransformParams(); + if (shouldFadeOutTargetsForKeyboardQuickSwitch( + transformParams, taskViewSimulator, progress)) { + continue; + } + taskViewSimulator.apply(transformParams); } } } @@ -2493,7 +2556,7 @@ public abstract class AbsSwipeUpHandler, // Scaling of RecentsView during quick switch based on amount of recents scroll private float getScaleProgressDueToScroll() { if (mActivity == null || !mActivity.getDeviceProfile().isTablet || mRecentsView == null - || !mRecentsViewScrollLinked) { + || !shouldLinkRecentsViewScroll()) { return 0; } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index ca82a2d296..b89d20ca97 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -178,7 +178,7 @@ public abstract class BaseActivityInterface T getVisibleRecentsView(); @UiThread - public abstract boolean switchToRecentsIfVisible(Runnable onCompleteCallback); + public abstract boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener); public abstract Rect getOverviewWindowBounds( Rect homeBounds, RemoteAnimationTarget target); @@ -520,7 +520,7 @@ public abstract class BaseActivityInterface mActivity.getStateManager().goToState( controller.getInterpolatedProgress() > 0.5 ? mTargetState : mBackgroundState, - false)); + /* animated= */ false)); RecentsView recentsView = mActivity.getOverviewPanel(); AnimatorControllerWithResistance controllerWithResistance = diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index 693d6ae4bd..27e8726975 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -122,7 +122,7 @@ public final class FallbackActivityInterface extends } @Override - public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) { + public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) { return false; } diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 70b9183207..97c48e6327 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; @@ -212,7 +211,7 @@ public final class LauncherActivityInterface extends } @Override - public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) { + public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) { Launcher launcher = getVisibleLauncher(); if (launcher == null) { return false; @@ -227,7 +226,7 @@ public final class LauncherActivityInterface extends closeOverlay(); launcher.getStateManager().goToState(OVERVIEW, launcher.getStateManager().shouldAnimateStateChange(), - onCompleteCallback == null ? null : forEndCallback(onCompleteCallback)); + animatorListener); return true; } diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 315316d56e..e448a14e1e 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -15,9 +15,12 @@ */ package com.android.quickstep; +import static com.android.launcher3.PagedView.INVALID_PAGE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.PointF; import android.os.SystemClock; @@ -25,7 +28,6 @@ import android.os.Trace; import android.view.View; import androidx.annotation.BinderThread; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -75,7 +77,7 @@ public class OverviewCommandHelper { * do not lose the focus across multiple calls of * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command */ - private int mTaskFocusIndexOverride = -1; + private int mKeyboardTaskFocusIndex = -1; /** * Whether we should incoming toggle commands while a previous toggle command is still ongoing. @@ -195,9 +197,11 @@ public class OverviewCommandHelper { } BaseActivityInterface activityInterface = mOverviewComponentObserver.getActivityInterface(); - RecentsView recents = activityInterface.getVisibleRecentsView(); - if (recents == null) { + RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView(); + RecentsView createdRecentsView; + if (visibleRecentsView == null) { T activity = activityInterface.getCreatedActivity(); + createdRecentsView = activity == null ? null : activity.getOverviewPanel(); DeviceProfile dp = activity == null ? null : activity.getDeviceProfile(); TaskbarUIController uiController = activityInterface.getTaskbarController(); boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() @@ -209,8 +213,8 @@ public class OverviewCommandHelper { if (!allowQuickSwitch) { return true; } - mTaskFocusIndexOverride = uiController.launchFocusedTask(); - if (mTaskFocusIndexOverride == -1) { + mKeyboardTaskFocusIndex = uiController.launchFocusedTask(); + if (mKeyboardTaskFocusIndex == -1) { return true; } } @@ -224,34 +228,47 @@ public class OverviewCommandHelper { return true; } } else { + createdRecentsView = visibleRecentsView; switch (cmd.type) { case TYPE_SHOW: // already visible return true; case TYPE_HIDE: { - mTaskFocusIndexOverride = -1; - int currentPage = recents.getNextPage(); - TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount()) - ? (TaskView) recents.getPageAt(currentPage) + mKeyboardTaskFocusIndex = INVALID_PAGE; + int currentPage = visibleRecentsView.getNextPage(); + TaskView tv = (currentPage >= 0 + && currentPage < visibleRecentsView.getTaskViewCount()) + ? (TaskView) visibleRecentsView.getPageAt(currentPage) : null; - return launchTask(recents, tv, cmd); + return launchTask(visibleRecentsView, tv, cmd); } case TYPE_TOGGLE: - return launchTask(recents, getNextTask(recents), cmd); + return launchTask(visibleRecentsView, getNextTask(visibleRecentsView), cmd); case TYPE_HOME: - recents.startHome(); + visibleRecentsView.startHome(); return true; } } - final Runnable completeCallback = () -> { - RecentsView rv = activityInterface.getVisibleRecentsView(); - if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) { - updateRecentsViewFocus(rv); + if (createdRecentsView != null) { + createdRecentsView.setKeyboardTaskFocusIndex(mKeyboardTaskFocusIndex); + } + // Handle recents view focus when launching from home + Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + updateRecentsViewFocus(cmd); + } + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + onRecentsViewFocusUpdated(cmd); + scheduleNextTask(cmd); } - scheduleNextTask(cmd); }; - if (activityInterface.switchToRecentsIfVisible(completeCallback)) { + if (activityInterface.switchToRecentsIfVisible(animatorListener)) { // If successfully switched, wait until animation finishes return false; } @@ -276,6 +293,7 @@ public class OverviewCommandHelper { @Override public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { + updateRecentsViewFocus(cmd); activityInterface.runOnInitBackgroundStateUI(() -> interactionHandler.onGestureEnded(0, new PointF())); cmd.removeListener(this); @@ -290,14 +308,12 @@ public class OverviewCommandHelper { if (createdActivity == null) { return; } - RecentsView createdRecents = createdActivity.getOverviewPanel(); - if (createdRecents != null) { - createdRecents.onRecentsAnimationComplete(); + if (createdRecentsView != null) { + createdRecentsView.onRecentsAnimationComplete(); } } }; - RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView(); if (visibleRecentsView != null) { visibleRecentsView.moveRunningTaskToFront(); } @@ -317,7 +333,6 @@ public class OverviewCommandHelper { interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/); cmd.mActiveCallbacks.addListener(recentAnimListener); } - Trace.beginAsyncSection(TRANSITION_NAME, 0); return false; } @@ -325,47 +340,58 @@ public class OverviewCommandHelper { private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) { cmd.removeListener(handler); Trace.endAsyncSection(TRANSITION_NAME, 0); - - RecentsView rv = - mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView(); - if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) { - updateRecentsViewFocus(rv); - } + onRecentsViewFocusUpdated(cmd); scheduleNextTask(cmd); } - private void updateRecentsViewFocus(@NonNull RecentsView rv) { + private void updateRecentsViewFocus(CommandInfo cmd) { + RecentsView recentsView = + mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView(); + if (recentsView == null || (cmd.type != TYPE_KEYBOARD_INPUT && cmd.type != TYPE_HIDE)) { + return; + } // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT), // the touch mode somehow is not change to false by the Android framework. // The subsequent tab to go through tasks in overview can only be dispatched to // focuses views, while focus can only be requested in // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note, // here we launch overview with live tile. - rv.getViewRootImpl().touchModeChanged(false); + recentsView.getViewRootImpl().touchModeChanged(false); // Ensure that recents view has focus so that it receives the followup key inputs - TaskView taskView = rv.getTaskViewAt(mTaskFocusIndexOverride); - if (taskView != null) { - requestFocus(taskView); + if (requestFocus(recentsView.getTaskViewAt(mKeyboardTaskFocusIndex))) { return; } - taskView = rv.getNextTaskView(); - if (taskView != null) { - requestFocus(taskView); + if (requestFocus(recentsView.getNextTaskView())) { return; } - taskView = rv.getTaskViewAt(0); - if (taskView != null) { - requestFocus(taskView); + if (requestFocus(recentsView.getTaskViewAt(0))) { return; } - requestFocus(rv); + requestFocus(recentsView); } - private void requestFocus(@NonNull View view) { - view.post(() -> { - view.requestFocus(); - view.requestAccessibilityFocus(); + private void onRecentsViewFocusUpdated(CommandInfo cmd) { + RecentsView recentsView = + mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView(); + if (recentsView == null + || cmd.type != TYPE_HIDE + || mKeyboardTaskFocusIndex == INVALID_PAGE) { + return; + } + recentsView.setKeyboardTaskFocusIndex(INVALID_PAGE); + recentsView.setCurrentPage(mKeyboardTaskFocusIndex); + mKeyboardTaskFocusIndex = INVALID_PAGE; + } + + private boolean requestFocus(@Nullable View taskView) { + if (taskView == null) { + return false; + } + taskView.post(() -> { + taskView.requestFocus(); + taskView.requestAccessibilityFocus(); }); + return true; } public void dump(PrintWriter pw) { @@ -374,7 +400,7 @@ public class OverviewCommandHelper { if (!mPendingCommands.isEmpty()) { pw.println(" pendingCommandType=" + mPendingCommands.get(0).type); } - pw.println(" mTaskFocusIndexOverride=" + mTaskFocusIndexOverride); + pw.println(" mKeyboardTaskFocusIndex=" + mKeyboardTaskFocusIndex); pw.println(" mWaitForToggleCommandComplete=" + mWaitForToggleCommandComplete); } diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 065a9c5964..0bb6b23dca 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -40,6 +40,7 @@ import android.util.Log; import android.view.RemoteAnimationTarget; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; @@ -344,6 +345,14 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { * Applies the target to the previously set parameters */ public void apply(TransformParams params) { + apply(params, null); + } + + /** + * Applies the target to the previously set parameters, optionally with an overridden + * surface transaction + */ + public void apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction) { if (mDp == null || mThumbnailPosition.isEmpty()) { return; } @@ -404,7 +413,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mTempRectF.roundOut(mTmpCropRect); params.setProgress(1f - fullScreenProgress); - params.applySurfaceParams(params.createSurfaceParams(this)); + params.applySurfaceParams(surfaceTransaction == null + ? params.createSurfaceParams(this) : surfaceTransaction); if (!DEBUG) { return; diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 66d651e944..d10541a832 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -542,6 +542,9 @@ public abstract class RecentsView 0) { - // Don't dampen the scroll (due to overscroll) if the adjacent tasks are offscreen, so - // that the page can move freely given there's no visual indication why it shouldn't. - overScrollShift = (int) Utilities.mapRange(mAdjacentPageHorizontalOffset, - overScrollShift, getUndampedOverScrollShift()); - } + // Don't dampen the scroll (due to overscroll) if the adjacent tasks are offscreen, so that + // the page can move freely given there's no visual indication why it shouldn't. + int overScrollShift = mAdjacentPageHorizontalOffset > 0 + ? (int) Utilities.mapRange( + mAdjacentPageHorizontalOffset, + getOverScrollShift(), + getUndampedOverScrollShift()) + : getOverScrollShift(); return getScrollForPage(pageIndex) - getPagedOrientationHandler().getPrimaryScroll(this) + overScrollShift + getOffsetFromScrollPosition(pageIndex); } @@ -6025,11 +6044,50 @@ public abstract class RecentsView 550 + + 400 + 500 500 diff --git a/res/values/config.xml b/res/values/config.xml index 29c4e663fb..1b74238353 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -43,6 +43,9 @@ 750 + + 750 + diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 43dca5cede..ca83245d42 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -637,6 +637,11 @@ public abstract class PagedView extends ViewGrou mMinFlingVelocity = res.getDimensionPixelSize(R.dimen.min_fling_velocity); mMinSnapVelocity = res.getDimensionPixelSize(R.dimen.min_page_snap_velocity); mPageSnapAnimationDuration = res.getInteger(R.integer.config_pageSnapAnimationDuration); + onVelocityValuesUpdated(); + } + + protected void onVelocityValuesUpdated() { + // Overridden in RecentsView } @Override @@ -1582,7 +1587,7 @@ public abstract class PagedView extends ViewGrou @Override public void requestChildFocus(View child, View focused) { super.requestChildFocus(child, focused); - if (!shouldHandleRequestChildFocus()) { + if (!shouldHandleRequestChildFocus(child)) { return; } // In case the device is controlled by a controller, mCurrentPage isn't updated properly @@ -1598,7 +1603,7 @@ public abstract class PagedView extends ViewGrou } } - protected boolean shouldHandleRequestChildFocus() { + protected boolean shouldHandleRequestChildFocus(View child) { return true; } @@ -1652,7 +1657,7 @@ public abstract class PagedView extends ViewGrou } protected void snapToDestination() { - snapToPage(getDestinationPage(), mPageSnapAnimationDuration); + snapToPage(getDestinationPage(), getSnapAnimationDuration()); } // We want the duration of the page snap animation to be influenced by the distance that @@ -1676,7 +1681,7 @@ public abstract class PagedView extends ViewGrou if (Math.abs(velocity) < mMinFlingVelocity) { // If the velocity is low enough, then treat this more as an automatic page advance // as opposed to an apparent physical response to flinging - return snapToPage(whichPage, mPageSnapAnimationDuration); + return snapToPage(whichPage, getSnapAnimationDuration()); } // Here we compute a "distance" that will be used in the computation of the overall @@ -1698,12 +1703,16 @@ public abstract class PagedView extends ViewGrou return snapToPage(whichPage, delta, duration); } + protected int getSnapAnimationDuration() { + return mPageSnapAnimationDuration; + } + public boolean snapToPage(int whichPage) { - return snapToPage(whichPage, mPageSnapAnimationDuration); + return snapToPage(whichPage, getSnapAnimationDuration()); } public boolean snapToPageImmediately(int whichPage) { - return snapToPage(whichPage, mPageSnapAnimationDuration, true); + return snapToPage(whichPage, getSnapAnimationDuration(), true); } public boolean snapToPage(int whichPage, int duration) { diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/BaseOverview.java index 1bc489c405..d337b91c86 100644 --- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -19,9 +19,11 @@ package com.android.launcher3.tapl; import static android.view.KeyEvent.KEYCODE_ESCAPE; import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID; +import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; import android.graphics.Rect; +import android.view.KeyEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -47,6 +49,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ESCAPE.*?metaState=0"); private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile( "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0"); + private static final Pattern EVENT_ENTER_DOWN = Pattern.compile( + "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ENTER"); + private static final Pattern EVENT_ENTER_UP = Pattern.compile( + "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ENTER"); private static final int FLINGS_FOR_DISMISS_LIMIT = 40; @@ -414,6 +420,31 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { } } + /** + * Presses the enter key to launch the focused task + *

+ * If no task is focused, this will fail. + */ + public LaunchedAppState launchFocusedTaskByEnterKey(@NonNull String expectedPackageName) { + try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { + mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ENTER_DOWN); + mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ENTER_UP); + mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT); + + mLauncher.executeAndWaitForLauncherStop( + () -> mLauncher.assertTrue( + "Failed to press enter", + mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_ENTER)), + "pressing enter"); + mLauncher.assertAppLaunched(expectedPackageName); + + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "pressed enter")) { + return new LaunchedAppState(mLauncher); + } + } + } + private void verifyActionsViewVisibility() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to assert overview actions view visibility")) {