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

Commit 21f495f0 authored by Jiaquan He's avatar Jiaquan He
Browse files

Add keyboard support to Grid-based Recents.

Test: Checked that pressing tab, shift + tab, alt + tab, alt + shift +
tab work for task navigation in Recents on local sw600dp device. Also
checked that Recents on phones work properly.
Bug: 32101881
Change-Id: I3e4cd212d2900523ece30a85cae7fb73a9594efb
parent 70c0f5c2
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
  <solid android:color="#61FFFFFF" />
  <corners android:radius="8dp"/>
</shape>
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -21,5 +21,6 @@
  <dimen name="recents_grid_padding_task_view">20dp</dimen>
  <dimen name="recents_grid_task_view_header_height">44dp</dimen>
  <dimen name="recents_grid_task_view_header_button_padding">8dp</dimen>
  <dimen name="recents_grid_task_view_focused_frame_thickness">8dp</dimen>
</resources>
+6 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ public class RecentsActivityLaunchState {
    /**
     * Returns the task to focus given the current launch state.
     */
    public int getInitialFocusTaskIndex(int numTasks) {
    public int getInitialFocusTaskIndex(int numTasks, boolean useGridLayout) {
        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
        if (launchedFromApp) {
@@ -66,6 +66,11 @@ public class RecentsActivityLaunchState {
                return numTasks - 1;
            }

            if (useGridLayout) {
                // If coming from another app to the grid layout, focus the front most task
                return numTasks - 1;
            }

            // If coming from another app, focus the next task
            return Math.max(0, numTasks - 2);
        } else {
+84 −21
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
@@ -93,6 +94,7 @@ import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;

import com.android.systemui.recents.views.grid.GridTaskView;
import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -206,6 +208,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    private int mLastWidth;
    private int mLastHeight;

    // We keep track of the task view focused by user interaction and draw a frame around it in the
    // grid layout.
    private TaskViewFocusFrame mTaskViewFocusFrame;

    // A convenience update listener to request updating clipping of tasks
    private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
            new ValueAnimator.AnimatorUpdateListener() {
@@ -265,6 +271,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
        mDisplayRect = ssp.getDisplayRect();

        // Create a frame to draw around the focused task view
        if (Recents.getConfiguration().isGridEnabled) {
            mTaskViewFocusFrame = new TaskViewFocusFrame(mContext, this,
                mLayoutAlgorithm.mTaskGridLayoutAlgorithm);
            addView(mTaskViewFocusFrame);
            getViewTreeObserver().addOnGlobalFocusChangeListener(mTaskViewFocusFrame);
        }

        int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                R.integer.recents_task_bar_dismiss_delay_seconds);
        mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
@@ -878,7 +892,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     *
     * @return whether or not the stack will scroll as a part of this focus change
     */
    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
    public boolean setFocusedTask(int taskIndex, boolean scrollToTask,
            final boolean requestViewFocus) {
        return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, 0);
    }
@@ -888,7 +902,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     *
     * @return whether or not the stack will scroll as a part of this focus change
     */
    private boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
    public boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
            boolean requestViewFocus, int timerIndicatorDuration) {
        // Find the next task to focus
        int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
@@ -940,6 +954,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                    newFocusedTaskView.setFocusedState(true, requestViewFocus);
                }
            }
            // Any time a task view gets the focus, we move the focus frame around it.
            if (mTaskViewFocusFrame != null) {
                mTaskViewFocusFrame.moveGridTaskViewFocus(getChildViewForTask(newFocusedTask));
            }
        }
        return willScroll;
    }
@@ -1005,6 +1023,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
            float stackScroll = mStackScroller.getStackScroll();
            ArrayList<Task> tasks = mStack.getStackTasks();
            int taskCount = tasks.size();
            if (useGridLayout()) {
                // For the grid layout, we directly set focus to the most recently used task
                // no matter we're moving forwards or backwards.
                newIndex = taskCount - 1;
            } else {
                // For the grid layout we pick a proper task to focus, according to the current
                // stack scroll.
                if (forward) {
                    // Walk backwards and focus the next task smaller than the current stack scroll
                    for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
@@ -1023,6 +1048,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                    }
                }
            }
        }
        if (newIndex != -1) {
            boolean willScroll = setFocusedTask(newIndex, true /* scrollToTask */,
                    true /* requestViewFocus */, timerIndicatorDuration);
@@ -1037,20 +1063,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    /**
     * Resets the focused task.
     */
    void resetFocusedTask(Task task) {
    public void resetFocusedTask(Task task) {
        if (task != null) {
            TaskView tv = getChildViewForTask(task);
            if (tv != null) {
                tv.setFocusedState(false, false /* requestViewFocus */);
            }
        }
        if (mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
        }
        mFocusedTask = null;
    }

    /**
     * Returns the focused task.
     */
    Task getFocusedTask() {
    public Task getFocusedTask() {
        return mFocusedTask;
    }

@@ -1253,6 +1282,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        for (int i = 0; i < taskViewCount; i++) {
            measureTaskView(mTmpTaskViews.get(i));
        }
        if (mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.measure();
        }

        setMeasuredDimension(width, height);
        mLastWidth = width;
@@ -1287,6 +1319,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        for (int i = 0; i < taskViewCount; i++) {
            layoutTaskView(changed, mTmpTaskViews.get(i));
        }
        if (mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.layout();
        }

        if (changed) {
            if (mStackScroller.isScrollOutOfBounds()) {
@@ -1339,11 +1374,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        // until after the enter-animation
        RecentsConfiguration config = Recents.getConfiguration();
        RecentsActivityLaunchState launchState = config.getLaunchState();
        int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount());

        // We set the initial focused task view iff the following conditions are satisfied:
        // 1. Recents is showing task views in stack layout.
        // 2. Recents is launched with ALT + TAB.
        boolean setFocusOnFirstLayout = !useGridLayout() ||
            Recents.getConfiguration().getLaunchState().launchedWithAltTab;
        if (setFocusOnFirstLayout) {
            int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount(),
                useGridLayout());
            if (focusedTaskIndex != -1) {
                setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
                        false /* requestViewFocus */);
            }
        }
        updateStackActionButtonVisibility();
    }

@@ -1443,6 +1487,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        // Remove the task from the ignored set
        removeIgnoreTask(removedTask);

        // Resize the grid layout task view focus frame
        if (mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.resize();
        }

        // If requested, relayout with the given animation
        if (animation != null) {
            updateLayoutAlgorithm(true /* boundScroll */);
@@ -1740,10 +1789,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
        animateFreeformWorkspaceBackgroundAlpha(0, new AnimationProps(taskViewExitToHomeDuration,
                Interpolators.FAST_OUT_SLOW_IN));

        // Dismiss the grid task view focus frame
        if (mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
        }
    }

    public final void onBusEvent(DismissFocusedTaskViewEvent event) {
        if (mFocusedTask != null) {
            if (mTaskViewFocusFrame != null) {
                mTaskViewFocusFrame.moveGridTaskViewFocus(null);
            }
            TaskView tv = getChildViewForTask(mFocusedTask);
            if (tv != null) {
                tv.dismissTask();
@@ -2073,6 +2130,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        mResetToInitialStateWhenResized = true;
    }

    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
        if (!event.visible && mTaskViewFocusFrame != null) {
            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
        }
    }

    public void reloadOnConfigurationChange() {
        mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
        mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+3 −2
Original line number Diff line number Diff line
@@ -342,8 +342,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
                        mSv.invalidate();
                    }

                    // Reset the focused task after the user has scrolled
                    if (!mSv.mTouchExplorationEnabled) {
                    // Reset the focused task after the user has scrolled, but we have no scrolling
                    // in grid layout and therefore we don't want to reset the focus there.
                    if (!mSv.mTouchExplorationEnabled && !mSv.useGridLayout()) {
                        mSv.resetFocusedTask(mSv.getFocusedTask());
                    }
                } else if (mActiveTaskView == null) {
Loading