2011-04-13 11:27:36 -07:00
|
|
|
/*
|
2015-02-20 14:25:27 -08:00
|
|
|
* Copyright (C) 2015 The Android Open Source Project
|
2011-04-13 11:27:36 -07:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-06-05 22:57:57 -04:00
|
|
|
package com.android.launcher3;
|
2011-04-13 11:27:36 -07:00
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
import android.util.Log;
|
2011-04-13 11:27:36 -07:00
|
|
|
import android.view.KeyEvent;
|
2014-08-20 16:58:17 -07:00
|
|
|
import android.view.SoundEffectConstants;
|
2011-04-13 11:27:36 -07:00
|
|
|
import android.view.View;
|
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
import com.android.launcher3.util.FocusLogic;
|
2015-03-18 14:16:05 -07:00
|
|
|
import com.android.launcher3.util.Thunk;
|
2011-06-13 18:15:54 -07:00
|
|
|
|
2011-07-21 11:46:32 -07:00
|
|
|
/**
|
|
|
|
|
* A keyboard listener we set on all the workspace icons.
|
|
|
|
|
*/
|
2011-09-28 20:45:37 -07:00
|
|
|
class IconKeyEventListener implements View.OnKeyListener {
|
2015-02-20 14:25:27 -08:00
|
|
|
@Override
|
2011-07-21 11:46:32 -07:00
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
2011-09-28 20:45:37 -07:00
|
|
|
return FocusHelper.handleIconKeyEvent(v, keyCode, event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-09 11:56:34 -07:00
|
|
|
/**
|
2011-07-13 17:25:49 -07:00
|
|
|
* A keyboard listener we set on all the hotseat buttons.
|
2011-05-09 11:56:34 -07:00
|
|
|
*/
|
2011-09-28 20:45:37 -07:00
|
|
|
class HotseatIconKeyEventListener implements View.OnKeyListener {
|
2015-02-20 14:25:27 -08:00
|
|
|
@Override
|
2011-05-09 11:56:34 -07:00
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
2015-02-20 14:25:27 -08:00
|
|
|
return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event);
|
2011-05-09 11:56:34 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-13 11:27:36 -07:00
|
|
|
public class FocusHelper {
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
private static final String TAG = "FocusHelper";
|
|
|
|
|
private static final boolean DEBUG = false;
|
|
|
|
|
|
2015-03-05 11:33:33 -08:00
|
|
|
/**
|
2015-04-09 18:48:21 -07:00
|
|
|
* Handles key events in paged folder.
|
2015-03-05 11:33:33 -08:00
|
|
|
*/
|
2015-04-09 18:48:21 -07:00
|
|
|
public static class PagedFolderKeyEventListener implements View.OnKeyListener {
|
2015-03-05 11:33:33 -08:00
|
|
|
|
|
|
|
|
private final Folder mFolder;
|
|
|
|
|
|
|
|
|
|
public PagedFolderKeyEventListener(Folder folder) {
|
|
|
|
|
mFolder = folder;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 14:35:23 -07:00
|
|
|
@Override
|
|
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent e) {
|
|
|
|
|
boolean consume = FocusLogic.shouldConsume(keyCode);
|
|
|
|
|
if (e.getAction() == KeyEvent.ACTION_UP) {
|
|
|
|
|
return consume;
|
|
|
|
|
}
|
|
|
|
|
if (DEBUG) {
|
2015-04-09 18:48:21 -07:00
|
|
|
Log.v(TAG, String.format("Handle ALL Folders keyevent=[%s].",
|
2015-04-10 14:35:23 -07:00
|
|
|
KeyEvent.keyCodeToString(keyCode)));
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
|
2015-04-09 18:48:21 -07:00
|
|
|
|
|
|
|
|
if (!(v.getParent() instanceof ShortcutAndWidgetContainer)) {
|
2015-04-10 14:35:23 -07:00
|
|
|
if (LauncherAppState.isDogfoodBuild()) {
|
|
|
|
|
throw new IllegalStateException("Parent of the focused item is not supported.");
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-03-05 11:33:33 -08:00
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
|
2015-04-09 18:48:21 -07:00
|
|
|
// Initialize variables.
|
|
|
|
|
final ShortcutAndWidgetContainer itemContainer = (ShortcutAndWidgetContainer) v.getParent();
|
|
|
|
|
final CellLayout cellLayout = (CellLayout) itemContainer.getParent();
|
|
|
|
|
final int countX = cellLayout.getCountX();
|
|
|
|
|
final int countY = cellLayout.getCountY();
|
|
|
|
|
|
2015-04-10 14:35:23 -07:00
|
|
|
final int iconIndex = itemContainer.indexOfChild(v);
|
2015-04-09 18:48:21 -07:00
|
|
|
final FolderPagedView pagedView = (FolderPagedView) cellLayout.getParent();
|
2015-04-10 14:35:23 -07:00
|
|
|
|
2015-04-09 18:48:21 -07:00
|
|
|
final int pageIndex = pagedView.indexOfChild(cellLayout);
|
|
|
|
|
final int pageCount = pagedView.getPageCount();
|
2015-05-21 20:46:33 -07:00
|
|
|
final boolean isLayoutRtl = Utilities.isRtl(v.getResources());
|
2015-04-09 18:48:21 -07:00
|
|
|
|
|
|
|
|
int[][] matrix = FocusLogic.createSparseMatrix(cellLayout);
|
2015-04-10 14:35:23 -07:00
|
|
|
// Process focus.
|
2015-05-06 11:42:25 -07:00
|
|
|
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
|
2015-05-21 20:46:33 -07:00
|
|
|
countY, matrix, iconIndex, pageIndex, pageCount, isLayoutRtl);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newIconIndex == FocusLogic.NOOP) {
|
|
|
|
|
handleNoopKey(keyCode, v);
|
|
|
|
|
return consume;
|
|
|
|
|
}
|
2015-04-09 18:48:21 -07:00
|
|
|
ShortcutAndWidgetContainer newParent = null;
|
|
|
|
|
View child = null;
|
|
|
|
|
|
2015-04-10 14:35:23 -07:00
|
|
|
switch (newIconIndex) {
|
|
|
|
|
case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
|
2015-04-09 18:48:21 -07:00
|
|
|
case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
|
|
|
|
|
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newParent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
|
|
|
|
|
pagedView.snapToPage(pageIndex - 1);
|
|
|
|
|
child = newParent.getChildAt(
|
|
|
|
|
((newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN)
|
|
|
|
|
^ newParent.invertLayoutHorizontally()) ? 0 : countX - 1, row);
|
2015-04-10 14:35:23 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
|
2015-04-09 18:48:21 -07:00
|
|
|
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newParent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
pagedView.snapToPage(pageIndex - 1);
|
|
|
|
|
child = newParent.getChildAt(0, 0);
|
2015-04-10 14:35:23 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
|
2015-04-09 18:48:21 -07:00
|
|
|
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newParent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
pagedView.snapToPage(pageIndex - 1);
|
|
|
|
|
child = newParent.getChildAt(countX - 1, countY - 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
|
2015-04-09 18:48:21 -07:00
|
|
|
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newParent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
pagedView.snapToPage(pageIndex + 1);
|
|
|
|
|
child = newParent.getChildAt(0, 0);
|
2015-04-10 14:35:23 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
|
2015-04-09 18:48:21 -07:00
|
|
|
case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
|
|
|
|
|
newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
|
2015-04-10 14:35:23 -07:00
|
|
|
if (newParent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
pagedView.snapToPage(pageIndex + 1);
|
|
|
|
|
child = FocusLogic.getAdjacentChildInNextPage(newParent, v, newIconIndex);
|
2015-04-10 14:35:23 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
|
2015-04-09 18:48:21 -07:00
|
|
|
child = cellLayout.getChildAt(0, 0);
|
2015-04-10 14:35:23 -07:00
|
|
|
break;
|
|
|
|
|
case FocusLogic.CURRENT_PAGE_LAST_ITEM:
|
2015-04-09 18:48:21 -07:00
|
|
|
child = pagedView.getLastItem();
|
2015-04-10 14:35:23 -07:00
|
|
|
break;
|
|
|
|
|
default: // Go to some item on the current page.
|
|
|
|
|
child = itemContainer.getChildAt(newIconIndex);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (child != null) {
|
|
|
|
|
child.requestFocus();
|
|
|
|
|
playSoundEffect(keyCode, v);
|
|
|
|
|
} else {
|
|
|
|
|
handleNoopKey(keyCode, v);
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
return consume;
|
|
|
|
|
}
|
2011-04-13 11:27:36 -07:00
|
|
|
|
2015-04-09 18:48:21 -07:00
|
|
|
public void handleNoopKey(int keyCode, View v) {
|
|
|
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
|
|
|
|
|
mFolder.mFolderName.requestFocus();
|
|
|
|
|
playSoundEffect(keyCode, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-05 11:33:33 -08:00
|
|
|
}
|
|
|
|
|
|
2011-05-09 11:56:34 -07:00
|
|
|
/**
|
2015-02-20 14:25:27 -08:00
|
|
|
* Handles key events in the workspace hot seat (bottom of the screen).
|
|
|
|
|
* <p>Currently we don't special case for the phone UI in different orientations, even though
|
|
|
|
|
* the hotseat is on the side in landscape mode. This is to ensure that accessibility
|
|
|
|
|
* consistency is maintained across rotations.
|
2011-05-09 11:56:34 -07:00
|
|
|
*/
|
2015-02-20 14:25:27 -08:00
|
|
|
static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e) {
|
|
|
|
|
boolean consume = FocusLogic.shouldConsume(keyCode);
|
|
|
|
|
if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
|
|
|
|
|
return consume;
|
|
|
|
|
}
|
2011-05-09 11:56:34 -07:00
|
|
|
|
2015-05-06 11:42:25 -07:00
|
|
|
DeviceProfile profile = ((Launcher) v.getContext()).getDeviceProfile();
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
if (DEBUG) {
|
|
|
|
|
Log.v(TAG, String.format(
|
2015-03-17 11:32:21 -07:00
|
|
|
"Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s",
|
|
|
|
|
KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
|
2011-05-09 11:56:34 -07:00
|
|
|
}
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
// Initialize the variables.
|
|
|
|
|
final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent();
|
|
|
|
|
final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent();
|
2015-02-24 14:12:51 -08:00
|
|
|
Hotseat hotseat = (Hotseat) hotseatLayout.getParent();
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
|
2015-04-16 14:34:09 -07:00
|
|
|
int pageIndex = workspace.getNextPage();
|
2015-02-20 14:25:27 -08:00
|
|
|
int pageCount = workspace.getChildCount();
|
2015-02-24 14:12:51 -08:00
|
|
|
int countX = -1;
|
|
|
|
|
int countY = -1;
|
2015-04-09 18:48:21 -07:00
|
|
|
int iconIndex = hotseatParent.indexOfChild(v);
|
2015-03-17 11:32:21 -07:00
|
|
|
int iconRank = ((CellLayout.LayoutParams) hotseatLayout.getShortcutsAndWidgets()
|
|
|
|
|
.getChildAt(iconIndex).getLayoutParams()).cellX;
|
2015-02-20 14:25:27 -08:00
|
|
|
|
|
|
|
|
final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex);
|
2015-04-16 14:34:09 -07:00
|
|
|
if (iconLayout == null) {
|
|
|
|
|
// This check is to guard against cases where key strokes rushes in when workspace
|
|
|
|
|
// child creation/deletion is still in flux. (e.g., during drop or fling
|
|
|
|
|
// animation.)
|
|
|
|
|
return consume;
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
|
|
|
|
|
|
|
|
|
|
ViewGroup parent = null;
|
2015-02-24 14:12:51 -08:00
|
|
|
int[][] matrix = null;
|
2015-02-20 14:25:27 -08:00
|
|
|
|
|
|
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_UP &&
|
2015-03-17 11:32:21 -07:00
|
|
|
!profile.isVerticalBarLayout()) {
|
|
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
|
|
|
|
|
true /* hotseat horizontal */, hotseat.getAllAppsButtonRank(),
|
|
|
|
|
iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */);
|
2015-02-20 14:25:27 -08:00
|
|
|
iconIndex += iconParent.getChildCount();
|
|
|
|
|
countX = iconLayout.getCountX();
|
|
|
|
|
countY = iconLayout.getCountY() + hotseatLayout.getCountY();
|
|
|
|
|
parent = iconParent;
|
|
|
|
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
|
2015-03-17 11:32:21 -07:00
|
|
|
profile.isVerticalBarLayout()) {
|
|
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
|
|
|
|
|
false /* hotseat horizontal */, hotseat.getAllAppsButtonRank(),
|
|
|
|
|
iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */);
|
2015-02-20 14:25:27 -08:00
|
|
|
iconIndex += iconParent.getChildCount();
|
|
|
|
|
countX = iconLayout.getCountX() + hotseatLayout.getCountX();
|
|
|
|
|
countY = iconLayout.getCountY();
|
|
|
|
|
parent = iconParent;
|
2015-02-24 14:12:51 -08:00
|
|
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
|
2015-03-17 11:32:21 -07:00
|
|
|
profile.isVerticalBarLayout()) {
|
2015-02-24 14:12:51 -08:00
|
|
|
keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
|
|
|
|
|
}else {
|
2015-02-20 14:25:27 -08:00
|
|
|
// For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
|
|
|
|
|
// matrix extended with hotseat.
|
|
|
|
|
matrix = FocusLogic.createSparseMatrix(hotseatLayout);
|
|
|
|
|
countX = hotseatLayout.getCountX();
|
|
|
|
|
countY = hotseatLayout.getCountY();
|
2015-02-24 14:12:51 -08:00
|
|
|
parent = hotseatParent;
|
2011-04-13 11:27:36 -07:00
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
|
|
|
|
|
// Process the focus.
|
2015-05-06 11:42:25 -07:00
|
|
|
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
|
2015-05-21 20:46:33 -07:00
|
|
|
countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources()));
|
2015-02-20 14:25:27 -08:00
|
|
|
|
2015-02-24 14:12:51 -08:00
|
|
|
View newIcon = null;
|
|
|
|
|
if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
|
|
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
|
|
|
|
|
newIcon = parent.getChildAt(0);
|
|
|
|
|
// TODO(hyunyoungs): handle cases where the child is not an icon but
|
|
|
|
|
// a folder or a widget.
|
|
|
|
|
workspace.snapToPage(pageIndex + 1);
|
|
|
|
|
}
|
|
|
|
|
if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
|
2015-02-20 14:25:27 -08:00
|
|
|
newIconIndex -= iconParent.getChildCount();
|
2011-04-13 11:27:36 -07:00
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
if (parent != null) {
|
2015-02-24 14:12:51 -08:00
|
|
|
if (newIcon == null && newIconIndex >=0) {
|
|
|
|
|
newIcon = parent.getChildAt(newIconIndex);
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
if (newIcon != null) {
|
|
|
|
|
newIcon.requestFocus();
|
|
|
|
|
playSoundEffect(keyCode, v);
|
2011-04-13 11:27:36 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
return consume;
|
2011-04-13 11:27:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-02-20 14:25:27 -08:00
|
|
|
* Handles key events in a workspace containing icons.
|
2011-04-13 11:27:36 -07:00
|
|
|
*/
|
2011-09-28 20:45:37 -07:00
|
|
|
static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
|
2015-02-20 14:25:27 -08:00
|
|
|
boolean consume = FocusLogic.shouldConsume(keyCode);
|
|
|
|
|
if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
|
|
|
|
|
return consume;
|
|
|
|
|
}
|
2015-03-17 11:32:21 -07:00
|
|
|
|
2015-05-06 11:42:25 -07:00
|
|
|
Launcher launcher = (Launcher) v.getContext();
|
|
|
|
|
DeviceProfile profile = launcher.getDeviceProfile();
|
2015-03-17 11:32:21 -07:00
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
if (DEBUG) {
|
2015-03-17 11:32:21 -07:00
|
|
|
Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s",
|
|
|
|
|
KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
|
2015-02-20 14:25:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize the variables.
|
2012-03-20 03:18:20 -07:00
|
|
|
ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
|
2015-03-03 19:25:16 -08:00
|
|
|
CellLayout iconLayout = (CellLayout) parent.getParent();
|
2015-02-24 14:12:51 -08:00
|
|
|
final Workspace workspace = (Workspace) iconLayout.getParent();
|
2015-05-06 11:42:25 -07:00
|
|
|
final ViewGroup dragLayer = (ViewGroup) workspace.getParent();
|
|
|
|
|
final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.search_drop_target_bar);
|
|
|
|
|
final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat);
|
2015-04-09 18:48:21 -07:00
|
|
|
|
|
|
|
|
final int iconIndex = parent.indexOfChild(v);
|
|
|
|
|
final int pageIndex = workspace.indexOfChild(iconLayout);
|
|
|
|
|
final int pageCount = workspace.getChildCount();
|
2015-02-24 14:12:51 -08:00
|
|
|
int countX = iconLayout.getCountX();
|
|
|
|
|
int countY = iconLayout.getCountY();
|
2011-04-13 11:27:36 -07:00
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0);
|
|
|
|
|
ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets();
|
|
|
|
|
int[][] matrix;
|
|
|
|
|
|
2015-02-24 14:12:51 -08:00
|
|
|
// KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed
|
2015-02-20 14:25:27 -08:00
|
|
|
// to take a user to the hotseat. For other dpad navigation, do not use the matrix extended
|
|
|
|
|
// with the hotseat.
|
2015-03-17 11:32:21 -07:00
|
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) {
|
|
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */,
|
2015-05-20 15:03:13 -07:00
|
|
|
hotseat.getAllAppsButtonRank(),
|
|
|
|
|
!hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
|
2015-02-20 14:25:27 -08:00
|
|
|
countY = countY + 1;
|
2015-02-24 14:12:51 -08:00
|
|
|
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
|
2015-03-17 11:32:21 -07:00
|
|
|
profile.isVerticalBarLayout()) {
|
|
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */,
|
2015-05-20 15:03:13 -07:00
|
|
|
hotseat.getAllAppsButtonRank(),
|
|
|
|
|
!hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
|
2015-02-24 14:12:51 -08:00
|
|
|
countX = countX + 1;
|
|
|
|
|
} else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
|
|
|
|
|
workspace.removeWorkspaceItem(v);
|
|
|
|
|
return consume;
|
2015-02-20 14:25:27 -08:00
|
|
|
} else {
|
2015-02-24 14:12:51 -08:00
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout);
|
2015-02-20 14:25:27 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process the focus.
|
2015-05-06 11:42:25 -07:00
|
|
|
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
|
2015-05-21 20:46:33 -07:00
|
|
|
countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources()));
|
2015-02-20 14:25:27 -08:00
|
|
|
View newIcon = null;
|
|
|
|
|
switch (newIconIndex) {
|
|
|
|
|
case FocusLogic.NOOP:
|
|
|
|
|
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
|
|
|
|
|
newIcon = tabs;
|
2011-04-13 11:27:36 -07:00
|
|
|
}
|
|
|
|
|
break;
|
2015-03-03 19:25:16 -08:00
|
|
|
case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
|
2015-04-10 14:35:23 -07:00
|
|
|
case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
|
|
|
|
|
int newPageIndex = pageIndex - 1;
|
|
|
|
|
if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) {
|
|
|
|
|
newPageIndex = pageIndex + 1;
|
|
|
|
|
}
|
2015-04-09 18:48:21 -07:00
|
|
|
int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
|
2015-04-10 14:35:23 -07:00
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
|
2015-04-16 14:34:09 -07:00
|
|
|
workspace.snapToPage(newPageIndex);
|
2015-03-03 19:25:16 -08:00
|
|
|
if (parent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
workspace.snapToPage(newPageIndex);
|
2015-03-03 19:25:16 -08:00
|
|
|
iconLayout = (CellLayout) parent.getParent();
|
2015-03-04 16:33:56 -08:00
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout,
|
2015-03-03 19:25:16 -08:00
|
|
|
iconLayout.getCountX(), row);
|
2015-05-06 11:42:25 -07:00
|
|
|
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
|
2015-05-21 20:46:33 -07:00
|
|
|
matrix, FocusLogic.PIVOT, newPageIndex, pageCount,
|
|
|
|
|
Utilities.isRtl(v.getResources()));
|
2015-03-03 19:25:16 -08:00
|
|
|
newIcon = parent.getChildAt(newIconIndex);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
|
|
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
|
|
|
|
|
newIcon = parent.getChildAt(0);
|
|
|
|
|
workspace.snapToPage(pageIndex - 1);
|
2015-03-03 19:25:16 -08:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
|
|
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
|
|
|
|
|
newIcon = parent.getChildAt(parent.getChildCount() - 1);
|
|
|
|
|
workspace.snapToPage(pageIndex - 1);
|
2011-04-13 11:27:36 -07:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
|
|
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
|
|
|
|
|
newIcon = parent.getChildAt(0);
|
2015-02-24 14:12:51 -08:00
|
|
|
workspace.snapToPage(pageIndex + 1);
|
2011-04-13 11:27:36 -07:00
|
|
|
break;
|
2015-03-03 19:25:16 -08:00
|
|
|
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
|
2015-04-10 14:35:23 -07:00
|
|
|
case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
|
|
|
|
|
newPageIndex = pageIndex + 1;
|
|
|
|
|
if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
|
|
|
|
|
newPageIndex = pageIndex - 1;
|
|
|
|
|
}
|
2015-04-16 14:34:09 -07:00
|
|
|
workspace.snapToPage(newPageIndex);
|
2015-04-09 18:48:21 -07:00
|
|
|
row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
|
2015-04-10 14:35:23 -07:00
|
|
|
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
|
2015-03-03 19:25:16 -08:00
|
|
|
if (parent != null) {
|
2015-04-09 18:48:21 -07:00
|
|
|
workspace.snapToPage(newPageIndex);
|
2015-03-03 19:25:16 -08:00
|
|
|
iconLayout = (CellLayout) parent.getParent();
|
2015-03-04 16:33:56 -08:00
|
|
|
matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row);
|
2015-05-06 11:42:25 -07:00
|
|
|
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
|
2015-05-21 20:46:33 -07:00
|
|
|
matrix, FocusLogic.PIVOT, newPageIndex, pageCount,
|
|
|
|
|
Utilities.isRtl(v.getResources()));
|
2015-03-03 19:25:16 -08:00
|
|
|
newIcon = parent.getChildAt(newIconIndex);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
|
|
|
|
|
newIcon = parent.getChildAt(0);
|
2011-04-13 11:27:36 -07:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case FocusLogic.CURRENT_PAGE_LAST_ITEM:
|
|
|
|
|
newIcon = parent.getChildAt(parent.getChildCount() - 1);
|
2011-09-28 20:45:37 -07:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
default:
|
|
|
|
|
// current page, some item.
|
|
|
|
|
if (0 <= newIconIndex && newIconIndex < parent.getChildCount()) {
|
|
|
|
|
newIcon = parent.getChildAt(newIconIndex);
|
|
|
|
|
} else if (parent.getChildCount() <= newIconIndex &&
|
|
|
|
|
newIconIndex < parent.getChildCount() + hotseatParent.getChildCount()) {
|
|
|
|
|
newIcon = hotseatParent.getChildAt(newIconIndex - parent.getChildCount());
|
2011-09-28 20:45:37 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-02-20 14:25:27 -08:00
|
|
|
if (newIcon != null) {
|
|
|
|
|
newIcon.requestFocus();
|
|
|
|
|
playSoundEffect(keyCode, v);
|
|
|
|
|
}
|
|
|
|
|
return consume;
|
2011-09-28 20:45:37 -07:00
|
|
|
}
|
|
|
|
|
|
2015-02-20 14:25:27 -08:00
|
|
|
//
|
|
|
|
|
// Helper methods.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Private helper method to get the CellLayoutChildren given a CellLayout index.
|
|
|
|
|
*/
|
2015-06-02 09:38:28 -07:00
|
|
|
@Thunk static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
|
2015-02-20 14:25:27 -08:00
|
|
|
ViewGroup container, int i) {
|
|
|
|
|
CellLayout parent = (CellLayout) container.getChildAt(i);
|
|
|
|
|
return parent.getShortcutsAndWidgets();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper method to be used for playing sound effects.
|
|
|
|
|
*/
|
2015-03-18 14:16:05 -07:00
|
|
|
@Thunk static void playSoundEffect(int keyCode, View v) {
|
2015-02-20 14:25:27 -08:00
|
|
|
switch (keyCode) {
|
|
|
|
|
case KeyEvent.KEYCODE_DPAD_LEFT:
|
|
|
|
|
v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
|
|
|
|
|
break;
|
|
|
|
|
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
|
|
|
|
v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
|
2011-09-28 20:45:37 -07:00
|
|
|
break;
|
|
|
|
|
case KeyEvent.KEYCODE_DPAD_DOWN:
|
2015-02-20 14:25:27 -08:00
|
|
|
case KeyEvent.KEYCODE_PAGE_DOWN:
|
|
|
|
|
case KeyEvent.KEYCODE_MOVE_END:
|
|
|
|
|
v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
|
2011-09-28 20:45:37 -07:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
case KeyEvent.KEYCODE_DPAD_UP:
|
|
|
|
|
case KeyEvent.KEYCODE_PAGE_UP:
|
2011-09-28 20:45:37 -07:00
|
|
|
case KeyEvent.KEYCODE_MOVE_HOME:
|
2015-02-20 14:25:27 -08:00
|
|
|
v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
|
2011-04-13 11:27:36 -07:00
|
|
|
break;
|
2015-02-20 14:25:27 -08:00
|
|
|
default:
|
2011-04-13 11:27:36 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|