Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf6905c0 authored by Pat Manning's avatar Pat Manning Committed by Android (Google) Code Review
Browse files

Merge "Navigate grid overview via arrows and tab properly." into main

parents 063858b5 e683c4c5
Loading
Loading
Loading
Loading
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 static java.lang.annotation.RetentionPolicy.SOURCE;

import androidx.annotation.IntDef;

import com.android.launcher3.util.IntArray;

import java.lang.annotation.Retention;

/**
 * Helper class for navigating RecentsView grid tasks via arrow keys and tab.
 */
public class TaskGridNavHelper {
    public static final int CLEAR_ALL_PLACEHOLDER_ID = -1;
    public static final int INVALID_FOCUSED_TASK_ID = -1;

    public static final int DIRECTION_UP = 0;
    public static final int DIRECTION_DOWN = 1;
    public static final int DIRECTION_LEFT = 2;
    public static final int DIRECTION_RIGHT = 3;
    public static final int DIRECTION_TAB = 4;

    @Retention(SOURCE)
    @IntDef({DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_TAB})
    public @interface TASK_NAV_DIRECTION {}

    private final IntArray mOriginalTopRowIds;
    private IntArray mTopRowIds;
    private IntArray mBottomRowIds;
    private final int mFocusedTaskId;

    public TaskGridNavHelper(IntArray topIds, IntArray bottomIds, int focusedTaskId) {
        mFocusedTaskId = focusedTaskId;
        mOriginalTopRowIds = topIds.clone();
        generateTaskViewIdGrid(topIds, bottomIds);
    }

    private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray) {
        boolean hasFocusedTask = mFocusedTaskId != INVALID_FOCUSED_TASK_ID;
        int maxSize =
                Math.max(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0);
        int minSize =
                Math.min(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0);

        // Add the focused task to the beginning of both arrays if it exists.
        if (hasFocusedTask) {
            topRowIdArray.add(0, mFocusedTaskId);
            bottomRowIdArray.add(0, mFocusedTaskId);
        }

        // Fill in the shorter array with the ids from the longer one.
        for (int i = minSize; i < maxSize; i++) {
            if (i >= topRowIdArray.size()) {
                topRowIdArray.add(bottomRowIdArray.get(i));
            } else {
                bottomRowIdArray.add(topRowIdArray.get(i));
            }
        }

        // Add the clear all button to the end of both arrays
        topRowIdArray.add(CLEAR_ALL_PLACEHOLDER_ID);
        bottomRowIdArray.add(CLEAR_ALL_PLACEHOLDER_ID);

        mTopRowIds = topRowIdArray;
        mBottomRowIds = bottomRowIdArray;
    }

    /**
     * Returns the id of the next page in the grid or -1 for the clear all button.
     */
    public int getNextGridPage(int currentPageTaskViewId, int delta,
            @TASK_NAV_DIRECTION int direction, boolean cycle) {
        boolean inTop = mTopRowIds.contains(currentPageTaskViewId);
        int index = inTop ? mTopRowIds.indexOf(currentPageTaskViewId)
                : mBottomRowIds.indexOf(currentPageTaskViewId);
        int maxSize = Math.max(mTopRowIds.size(), mBottomRowIds.size());
        int nextIndex = index + delta;

        switch (direction) {
            case DIRECTION_UP:
            case DIRECTION_DOWN: {
                return inTop ? mBottomRowIds.get(index) : mTopRowIds.get(index);
            }
            case DIRECTION_LEFT: {
                int boundedIndex = cycle ? nextIndex % maxSize : Math.min(nextIndex, maxSize - 1);
                return inTop ? mTopRowIds.get(boundedIndex)
                        : mBottomRowIds.get(boundedIndex);
            }
            case DIRECTION_RIGHT: {
                int boundedIndex =
                        cycle ? (nextIndex < 0 ? maxSize - 1 : nextIndex) : Math.max(
                                nextIndex, 0);
                boolean inOriginalTop = mOriginalTopRowIds.contains(currentPageTaskViewId);
                return inOriginalTop ? mTopRowIds.get(boundedIndex)
                        : mBottomRowIds.get(boundedIndex);
            }
            case DIRECTION_TAB: {
                int boundedIndex =
                        cycle ? nextIndex < 0 ? maxSize - 1 : nextIndex % maxSize : Math.min(
                                nextIndex, maxSize - 1);
                if (delta >= 0) {
                    return inTop && mTopRowIds.get(index) != mBottomRowIds.get(index)
                            ? mBottomRowIds.get(index)
                            : mTopRowIds.get(boundedIndex);
                } else {
                    if (mTopRowIds.contains(currentPageTaskViewId)) {
                        return mBottomRowIds.get(boundedIndex);
                    } else {
                        // Go up to top if there is task above
                        return mTopRowIds.get(index) != mBottomRowIds.get(index)
                                ? mTopRowIds.get(index)
                                : mBottomRowIds.get(boundedIndex);
                    }
                }
            }
            default:
                return currentPageTaskViewId;
        }
    }
}
+52 −7
Original line number Diff line number Diff line
@@ -55,6 +55,11 @@ import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VAL
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_LEFT;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_RIGHT;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_TAB;
import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP;
import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
@@ -196,6 +201,7 @@ import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SurfaceTransaction;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskGridNavHelper;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.quickstep.util.TransformParams;
@@ -4065,12 +4071,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        return anim;
    }

    private boolean snapToPageRelative(int pageCount, int delta, boolean cycle) {
    private boolean snapToPageRelative(int delta, boolean cycle,
            @TaskGridNavHelper.TASK_NAV_DIRECTION int direction) {
        // Ignore grid page snap events while scroll animations are running, otherwise the next
        // page gets set before the animation finishes and can cause jumps.
        if (!mScroller.isFinished()) {
            return true;
        }
        int pageCount = getPageCount();
        if (pageCount == 0) {
            return false;
        }
        final int newPageUnbound = getNextPage() + delta;
        if (!cycle && (newPageUnbound < 0 || newPageUnbound >= pageCount)) {
        final int newPageUnbound = getNextPageInternal(delta, direction, cycle);
        if (!cycle && (newPageUnbound < 0 || newPageUnbound > pageCount)) {
            return false;
        }
        snapToPage((newPageUnbound + pageCount) % pageCount);
@@ -4078,6 +4091,34 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        return true;
    }

    private int getNextPageInternal(int delta, @TaskGridNavHelper.TASK_NAV_DIRECTION int direction,
            boolean cycle) {
        if (!showAsGrid()) {
            return getNextPage() + delta;
        }

        // Init task grid nav helper with top/bottom id arrays.
        TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(),
                getBottomRowIdArray(), mFocusedTaskViewId);

        // Get current page's task view ID.
        TaskView currentPageTaskView = getCurrentPageTaskView();
        int currentPageTaskViewId;
        if (currentPageTaskView != null) {
            currentPageTaskViewId = currentPageTaskView.getTaskViewId();
        } else if (mCurrentPage == indexOfChild(mClearAllButton)) {
            currentPageTaskViewId = TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID;
        } else {
            return INVALID_PAGE;
        }

        int nextGridPage =
                taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle);
        return nextGridPage == TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID
                ? indexOfChild(mClearAllButton)
                : indexOfChild(getTaskViewFromTaskViewId(nextGridPage));
    }

    private void runDismissAnimation(PendingAnimation pendingAnim) {
        AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
        controller.dispatchOnStart();
@@ -4119,12 +4160,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_TAB:
                    return snapToPageRelative(getTaskViewCount(), event.isShiftPressed() ? -1 : 1,
                            event.isAltPressed() /* cycle */);
                    return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
                            DIRECTION_TAB);
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    return snapToPageRelative(getPageCount(), mIsRtl ? -1 : 1, false /* cycle */);
                    return snapToPageRelative(mIsRtl ? -1 : 1, true /* cycle */, DIRECTION_RIGHT);
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    return snapToPageRelative(getPageCount(), mIsRtl ? 1 : -1, false /* cycle */);
                    return snapToPageRelative(mIsRtl ? 1 : -1, true /* cycle */, DIRECTION_LEFT);
                case KeyEvent.KEYCODE_DPAD_UP:
                    return snapToPageRelative(1, false /* cycle */, DIRECTION_UP);
                case KeyEvent.KEYCODE_DPAD_DOWN:
                    return snapToPageRelative(1, false /* cycle */, DIRECTION_DOWN);
                case KeyEvent.KEYCODE_DEL:
                case KeyEvent.KEYCODE_FORWARD_DEL:
                    dismissCurrentTask();
+510 −0

File added.

Preview size limit exceeded, changes collapsed.