Update KeyboardQuickSwitch for TAPL testing

- Added a res id to KeyboardQuickSwitchView for TAPL testing
- Updated KeyboardQuickSwitch focus and scroll initialization
- Logging KeyEvents for TAPL testing
- Updated scrolling logic to wait for initial layout
- Fixed activity leak in KeyboardQuickSwitchViewController

Flag: ENABLE_KEYBOARD_QUICK_SWITCH
Bug: 267520665
Test: TaplTestsKeyboardQuickSwitch
Change-Id: I1d45d948c0e185504d994f7ef1d34f173c2243a9
This commit is contained in:
Schneider Victor-tulias
2023-09-21 10:14:40 -04:00
parent f5099749be
commit e95326dfdd
3 changed files with 84 additions and 44 deletions
@@ -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"
@@ -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()
@@ -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();
}