diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 70642edde3ef4..6e4a69bc1188c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -74,6 +74,8 @@ import com.android.systemui.recents.events.ui.UserInteractionEvent; import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; @@ -590,13 +592,12 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD } return true; } - case KeyEvent.KEYCODE_DPAD_UP: { - EventBus.getDefault().send( - new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */)); - return true; - } - case KeyEvent.KEYCODE_DPAD_DOWN: { - EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_DPAD_RIGHT: { + final Direction direction = NavigateTaskViewEvent.getDirectionFromKeyCode(keyCode); + EventBus.getDefault().send(new NavigateTaskViewEvent(direction)); return true; } case KeyEvent.KEYCODE_DEL: diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java new file mode 100644 index 0000000000000..5508d269f03f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package com.android.systemui.recents.events.ui.focus; + +import android.view.KeyEvent; +import com.android.systemui.recents.events.EventBus; + +/** + * Navigates the task view by arrow keys. + */ +public class NavigateTaskViewEvent extends EventBus.Event { + public enum Direction { + UNDEFINED, UP, DOWN, LEFT, RIGHT; + } + + public Direction direction; + public NavigateTaskViewEvent(Direction direction) { + this.direction = direction; + } + + public static Direction getDirectionFromKeyCode(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_UP: + return Direction.UP; + case KeyEvent.KEYCODE_DPAD_DOWN: + return Direction.DOWN; + case KeyEvent.KEYCODE_DPAD_LEFT: + return Direction.LEFT; + case KeyEvent.KEYCODE_DPAD_RIGHT: + return Direction.RIGHT; + default: + return Direction.UNDEFINED; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index bc2c4249dd84a..3cd681c27a93e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -87,6 +87,7 @@ import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropT import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; @@ -1869,6 +1870,26 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */); } + public final void onBusEvent(NavigateTaskViewEvent event) { + if (useGridLayout()) { + final int taskCount = mStack.getTaskCount(); + final int currentIndex = mStack.indexOfStackTask(getFocusedTask()); + final int nextIndex = mLayoutAlgorithm.mTaskGridLayoutAlgorithm.navigateFocus(taskCount, + currentIndex, event.direction); + setFocusedTask(nextIndex, false, true); + } else { + switch (event.direction) { + case UP: + EventBus.getDefault().send(new FocusPreviousTaskViewEvent()); + break; + case DOWN: + EventBus.getDefault().send( + new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */)); + break; + } + } + } + public final void onBusEvent(UserInteractionEvent event) { // Poke the doze trigger on user interaction mUIDozeTrigger.poke(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java index 70536b1bdce2f..78c26dd64986a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java @@ -23,6 +23,8 @@ import android.graphics.Rect; import android.view.WindowManager; import com.android.systemui.R; +import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; +import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; import com.android.systemui.recents.views.TaskViewTransform; @@ -63,6 +65,8 @@ public class TaskGridLayoutAlgorithm { Rect size; int[] xOffsets; int[] yOffsets; + int tasksPerLine; + int lines; TaskGridRectInfo(int taskCount) { size = new Rect(); @@ -71,10 +75,10 @@ public class TaskGridLayoutAlgorithm { int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount); - int tasksPerLine = layoutTaskCount < 2 ? 1 : ( + tasksPerLine = layoutTaskCount < 2 ? 1 : ( layoutTaskCount < 5 ? 2 : ( layoutTaskCount < 7 ? 3 : 4)); - int lines = layoutTaskCount < 3 ? 1 : 2; + lines = layoutTaskCount < 3 ? 1 : 2; // A couple of special cases. boolean landscapeWindow = mWindowRect.width() > mWindowRect.height(); @@ -200,6 +204,48 @@ public class TaskGridLayoutAlgorithm { return transformOut; } + /** + * Return the proper task index to focus for arrow key navigation. + * @param taskCount The amount of tasks. + * @param currentFocusedIndex The index of the currently focused task. + * @param direction The direction we're navigating. + * @return The index of the task that should get the focus. + */ + public int navigateFocus(int taskCount, int currentFocusedIndex, Direction direction) { + if (taskCount < 1 || taskCount > MAX_LAYOUT_TASK_COUNT) { + return -1; + } + if (currentFocusedIndex == -1) { + return 0; + } + int newIndex = currentFocusedIndex; + final TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; + final int currentLine = (taskCount - 1 - currentFocusedIndex) / gridInfo.tasksPerLine; + switch (direction) { + case UP: + newIndex += gridInfo.tasksPerLine; + newIndex = newIndex >= taskCount ? currentFocusedIndex : newIndex; + break; + case DOWN: + newIndex -= gridInfo.tasksPerLine; + newIndex = newIndex < 0 ? currentFocusedIndex : newIndex; + break; + case LEFT: + newIndex++; + final int leftMostIndex = (taskCount - 1) - currentLine * gridInfo.tasksPerLine; + newIndex = newIndex > leftMostIndex ? currentFocusedIndex : newIndex; + break; + case RIGHT: + newIndex--; + int rightMostIndex = + (taskCount - 1) - (currentLine + 1) * gridInfo.tasksPerLine + 1; + rightMostIndex = rightMostIndex < 0 ? 0 : rightMostIndex; + newIndex = newIndex < rightMostIndex ? currentFocusedIndex : newIndex; + break; + } + return newIndex; + } + public void initialize(Rect windowRect) { mWindowRect = windowRect; // Define paddings in terms of percentage of the total area.