diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml index 16abdeefcf..5af8d5165f 100644 --- a/quickstep/res/layout/keyboard_quick_switch_view.xml +++ b/quickstep/res/layout/keyboard_quick_switch_view.xml @@ -17,6 +17,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/keyboard_quick_switch_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/keyboard_quick_switch_margin_top" diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java index 4e9e3019a9..42c423ce83 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java @@ -46,6 +46,8 @@ import com.android.app.animation.Interpolators; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.testing.TestLogging; +import com.android.launcher3.testing.shared.TestProtocol; import com.android.quickstep.util.GroupTask; import java.util.HashMap; @@ -360,11 +362,8 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { OPEN_OUTLINE_INTERPOLATOR)); } }); - if (currentFocusIndexOverride == -1) { - initializeScroll(/* index= */ 0, /* shouldTruncateTarget= */ false); - } else { - animateFocusMove(-1, currentFocusIndexOverride); - } + animateFocusMove(-1, currentFocusIndexOverride == -1 + ? Math.min(mContent.getChildCount(), 1) : currentFocusIndexOverride); displayedContent.setVisibility(VISIBLE); setVisibility(VISIBLE); requestFocus(); @@ -413,7 +412,8 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { // there are more tasks initializeScroll( firstVisibleTaskIndex, - /* shouldTruncateTarget= */ firstVisibleTaskIndex != toIndex); + /* shouldTruncateTarget= */ firstVisibleTaskIndex != 0 + && firstVisibleTaskIndex != toIndex); } else if (toIndex > fromIndex || toIndex == 0) { // Scrolling to next task view if (mIsRtl) { @@ -438,6 +438,13 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { focusAnimation.start(); } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + TestLogging.recordKeyEvent( + TestProtocol.SEQUENCE_MAIN, "KeyboardQuickSwitchView key event", event); + return super.dispatchKeyEvent(event); + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return (mViewCallbacks != null @@ -454,56 +461,80 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { return; } if (mIsRtl) { - scrollRightTo( - task, shouldTruncateTarget, /* smoothScroll= */ false); - } else { scrollLeftTo( - task, shouldTruncateTarget, /* smoothScroll= */ false); + task, + shouldTruncateTarget, + /* smoothScroll= */ false, + /* waitForLayout= */ true); + } else { + scrollRightTo( + task, + shouldTruncateTarget, + /* smoothScroll= */ false, + /* waitForLayout= */ true); } } private void scrollRightTo(@NonNull View targetTask) { - scrollRightTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true); + scrollRightTo( + targetTask, + /* shouldTruncateTarget= */ false, + /* smoothScroll= */ true, + /* waitForLayout= */ false); } private void scrollRightTo( - @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) { + @NonNull View targetTask, + boolean shouldTruncateTarget, + boolean smoothScroll, + boolean waitForLayout) { if (!mDisplayingRecentTasks) { return; } if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) { return; } - int scrollTo = targetTask.getLeft() - mSpacing - + (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0); - // Scroll so that the focused task is to the left of the list - if (smoothScroll) { - mScrollView.smoothScrollTo(scrollTo, 0); - } else { - mScrollView.scrollTo(scrollTo, 0); - } + runScrollCommand(waitForLayout, () -> { + int scrollTo = targetTask.getLeft() - mSpacing + + (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0); + // Scroll so that the focused task is to the left of the list + if (smoothScroll) { + mScrollView.smoothScrollTo(scrollTo, 0); + } else { + mScrollView.scrollTo(scrollTo, 0); + } + }); } private void scrollLeftTo(@NonNull View targetTask) { - scrollLeftTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true); + scrollLeftTo( + targetTask, + /* shouldTruncateTarget= */ false, + /* smoothScroll= */ true, + /* waitForLayout= */ false); } private void scrollLeftTo( - @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) { + @NonNull View targetTask, + boolean shouldTruncateTarget, + boolean smoothScroll, + boolean waitForLayout) { if (!mDisplayingRecentTasks) { return; } if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) { return; } - int scrollTo = targetTask.getRight() + mSpacing - mScrollView.getWidth() - - (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0); - // Scroll so that the focused task is to the right of the list - if (smoothScroll) { - mScrollView.smoothScrollTo(scrollTo, 0); - } else { - mScrollView.scrollTo(scrollTo, 0); - } + runScrollCommand(waitForLayout, () -> { + int scrollTo = targetTask.getRight() + mSpacing - mScrollView.getWidth() + - (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0); + // Scroll so that the focused task is to the right of the list + if (smoothScroll) { + mScrollView.smoothScrollTo(scrollTo, 0); + } else { + mScrollView.scrollTo(scrollTo, 0); + } + }); } private boolean shouldScroll(@NonNull View targetTask, boolean shouldTruncateTarget) { @@ -514,6 +545,21 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { return isTargetTruncated && !shouldTruncateTarget; } + private void runScrollCommand(boolean waitForLayout, @NonNull Runnable scrollCommand) { + if (!waitForLayout) { + scrollCommand.run(); + return; + } + mScrollView.getViewTreeObserver().addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + scrollCommand.run(); + mScrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } + @Nullable protected KeyboardQuickSwitchTaskView getTaskAt(int index) { return !mDisplayingRecentTasks || index < 0 || index >= mContent.getChildCount() diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java index a293f748b9..cbb991da82 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java @@ -24,7 +24,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.anim.AnimationSuccessListener; +import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer; import com.android.quickstep.SystemUiProxy; @@ -92,27 +92,19 @@ public class KeyboardQuickSwitchViewController { protected void closeQuickSwitchView(boolean animate) { if (mCloseAnimation != null) { - if (animate) { - // Let currently-running animation finish. - return; - } else { - mCloseAnimation.cancel(); + // Let currently-running animation finish. + if (!animate) { + mCloseAnimation.end(); } + return; } if (!animate) { - mCloseAnimation = null; onCloseComplete(); return; } mCloseAnimation = mKeyboardQuickSwitchView.getCloseAnimation(); - mCloseAnimation.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - mCloseAnimation = null; - onCloseComplete(); - } - }); + mCloseAnimation.addListener(AnimatorListeners.forEndCallback(this::onCloseComplete)); mCloseAnimation.start(); } @@ -160,6 +152,7 @@ public class KeyboardQuickSwitchViewController { } private void onCloseComplete() { + mCloseAnimation = null; mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView); mControllerCallbacks.onCloseComplete(); }