Merge "Focus handling - RTL support" into ub-launcher3-burnaby

This commit is contained in:
Hyunyoung Song
2015-04-14 00:49:16 +00:00
committed by Android (Google) Code Review
3 changed files with 149 additions and 180 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ public class DeviceProfile {
boolean isLandscape;
boolean isTablet;
boolean isLargeTablet;
boolean isLayoutRtl;
public boolean isLayoutRtl;
boolean transposeLayoutWithOrientation;
+123 -170
View File
@@ -37,16 +37,6 @@ class IconKeyEventListener implements View.OnKeyListener {
}
}
/**
* A keyboard listener we set on all the workspace icons.
*/
class FolderKeyEventListener implements View.OnKeyListener {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
}
}
/**
* A keyboard listener we set on all the hotseat buttons.
*/
@@ -91,110 +81,120 @@ public class FocusHelper {
*/
public static class PagedViewKeyListener implements View.OnKeyListener {
@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) {
Log.v(TAG, String.format("Handle ALL APPS keyevent=[%s].",
KeyEvent.keyCodeToString(keyCode)));
}
// Initialize variables.
ViewGroup parentLayout;
ViewGroup itemContainer;
int countX;
int countY;
if (v.getParent() instanceof ShortcutAndWidgetContainer) {
itemContainer = (ViewGroup) v.getParent();
parentLayout = (ViewGroup) itemContainer.getParent();
countX = ((CellLayout) parentLayout).getCountX();
countY = ((CellLayout) parentLayout).getCountY();
} else {
if (LauncherAppState.isDogfoodBuild()) {
throw new IllegalStateException("Parent of the focused item is not supported.");
} else {
return false;
@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) {
Log.v(TAG, String.format("Handle ALL APPS and Folders keyevent=[%s].",
KeyEvent.keyCodeToString(keyCode)));
}
}
final int iconIndex = itemContainer.indexOfChild(v);
final PagedView container = (PagedView) parentLayout.getParent();
final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout));
final int pageCount = container.getChildCount();
ViewGroup newParent = null;
View child = null;
// TODO(hyunyoungs): this matrix is not applicable on the last page.
int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true);
// Initialize variables.
ViewGroup parentLayout;
ViewGroup itemContainer;
int countX;
int countY;
if (v.getParent() instanceof ShortcutAndWidgetContainer) {
itemContainer = (ViewGroup) v.getParent();
parentLayout = (ViewGroup) itemContainer.getParent();
countX = ((CellLayout) parentLayout).getCountX();
countY = ((CellLayout) parentLayout).getCountY();
} else {
if (LauncherAppState.isDogfoodBuild()) {
throw new IllegalStateException("Parent of the focused item is not supported.");
} else {
return false;
}
}
// Process focus.
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix,
iconIndex, pageIndex, pageCount);
if (newIconIndex == FocusLogic.NOOP) {
handleNoopKey(keyCode, v);
final int iconIndex = itemContainer.indexOfChild(v);
final PagedView container = (PagedView) parentLayout.getParent();
final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout));
final int pageCount = container.getChildCount();
ViewGroup newParent = null;
View child = null;
// TODO(hyunyoungs): this matrix is not applicable on the last page.
int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true);
// Process focus.
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix,
iconIndex, pageIndex, pageCount);
if (newIconIndex == FocusLogic.NOOP) {
handleNoopKey(keyCode, v);
return consume;
}
switch (newIconIndex) {
case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
int newPageIndex = pageIndex - 1;
if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) {
newPageIndex = pageIndex + 1;
}
newParent = getAppsCustomizePage(container, newPageIndex);
if (newParent != null) {
int row = FocusLogic.findRow(matrix, iconIndex);
container.snapToPage(newPageIndex);
// no need to create a new matrix.
child = newParent.getChildAt(matrix[countX-1][row]);
}
break;
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex - 1);
if (newParent != null) {
container.snapToPage(pageIndex - 1);
child = newParent.getChildAt(0);
}
break;
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex - 1);
if (newParent != null) {
container.snapToPage(pageIndex - 1);
child = newParent.getChildAt(newParent.getChildCount() - 1);
}
break;
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex + 1);
if (newParent != null) {
container.snapToPage(pageIndex + 1);
child = newParent.getChildAt(0);
}
break;
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
newPageIndex = pageIndex + 1;
if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
newPageIndex = pageIndex -1;
}
newParent = getAppsCustomizePage(container, newPageIndex);
if (newParent != null) {
container.snapToPage(newPageIndex);
int row = FocusLogic.findRow(matrix, iconIndex);
child = newParent.getChildAt(matrix[0][row]);
}
break;
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
child = container.getChildAt(0);
break;
case FocusLogic.CURRENT_PAGE_LAST_ITEM:
child = itemContainer.getChildAt(itemContainer.getChildCount() - 1);
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);
}
return consume;
}
switch (newIconIndex) {
case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
newParent = getAppsCustomizePage(container, pageIndex -1);
if (newParent != null) {
int row = FocusLogic.findRow(matrix, iconIndex);
container.snapToPage(pageIndex - 1);
// no need to create a new matrix.
child = newParent.getChildAt(matrix[countX-1][row]);
}
break;
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex - 1);
if (newParent != null) {
container.snapToPage(pageIndex - 1);
child = newParent.getChildAt(0);
}
break;
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex - 1);
if (newParent != null) {
container.snapToPage(pageIndex - 1);
child = newParent.getChildAt(newParent.getChildCount() - 1);
}
break;
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
newParent = getAppsCustomizePage(container, pageIndex + 1);
if (newParent != null) {
container.snapToPage(pageIndex + 1);
child = newParent.getChildAt(0);
}
break;
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
newParent = getAppsCustomizePage(container, pageIndex + 1);
if (newParent != null) {
container.snapToPage(pageIndex + 1);
int row = FocusLogic.findRow(matrix, iconIndex);
child = newParent.getChildAt(matrix[0][row]);
}
break;
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
child = container.getChildAt(0);
break;
case FocusLogic.CURRENT_PAGE_LAST_ITEM:
child = itemContainer.getChildAt(itemContainer.getChildCount() - 1);
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);
}
return consume;
}
public void handleNoopKey(int keyCode, View v) { }
public void handleNoopKey(int keyCode, View v) { }
}
/**
@@ -209,8 +209,7 @@ public class FocusHelper {
return consume;
}
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile profile = app.getDynamicGrid().getDeviceProfile();
DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
if (DEBUG) {
Log.v(TAG, String.format(
"Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s",
@@ -358,14 +357,19 @@ public class FocusHelper {
}
break;
case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
int newPageIndex = pageIndex - 1;
if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) {
newPageIndex = pageIndex + 1;
}
int row = FocusLogic.findRow(matrix, iconIndex);
parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
if (parent != null) {
iconLayout = (CellLayout) parent.getParent();
matrix = FocusLogic.createSparseMatrix(iconLayout,
iconLayout.getCountX(), row);
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix,
FocusLogic.PIVOT, pageIndex - 1, pageCount);
FocusLogic.PIVOT, newPageIndex, pageCount);
newIcon = parent.getChildAt(newIconIndex);
}
break;
@@ -385,13 +389,18 @@ public class FocusHelper {
workspace.snapToPage(pageIndex + 1);
break;
case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
newPageIndex = pageIndex + 1;
if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
newPageIndex = pageIndex - 1;
}
row = FocusLogic.findRow(matrix, iconIndex);
parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
if (parent != null) {
iconLayout = (CellLayout) parent.getParent();
matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row);
newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix,
FocusLogic.PIVOT, pageIndex, pageCount);
FocusLogic.PIVOT, newPageIndex, pageCount);
newIcon = parent.getChildAt(newIconIndex);
}
break;
@@ -418,62 +427,6 @@ public class FocusHelper {
return consume;
}
/**
* Handles key events for items in a Folder.
*/
static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
boolean consume = FocusLogic.shouldConsume(keyCode);
if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
return consume;
}
if (DEBUG) {
Log.v(TAG, String.format("Handle FOLDER keyevent=[%s].",
KeyEvent.keyCodeToString(keyCode)));
}
// Initialize the variables.
ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
final CellLayout layout = (CellLayout) parent.getParent();
final Folder folder = (Folder) layout.getParent().getParent();
View title = folder.mFolderName;
Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
final int countX = layout.getCountX();
final int countY = layout.getCountY();
final int iconIndex = findIndexOfView(parent, v);
int pageIndex = workspace.indexOfChild(layout);
int pageCount = workspace.getChildCount();
int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order */);
// Process the focus.
int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, map, iconIndex,
pageIndex, pageCount);
View newIcon = null;
switch (newIconIndex) {
case FocusLogic.NOOP:
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
newIcon = title;
}
break;
case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
case FocusLogic.NEXT_PAGE_FIRST_ITEM:
case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
case FocusLogic.CURRENT_PAGE_LAST_ITEM:
if (DEBUG) {
Log.v(TAG, "Page advance handling not supported on folder icons.");
}
break;
default: // current page some item.
newIcon = parent.getChildAt(newIconIndex);
break;
}
if (newIcon != null) {
newIcon.requestFocus();
playSoundEffect(keyCode, v);
}
return consume;
}
//
// Helper methods.
//
+25 -9
View File
@@ -16,12 +16,13 @@
package com.android.launcher3.util;
import android.content.res.Configuration;
import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewGroup;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
/**
* Calculates the next item that a {@link KeyEvent} should change the focus to.
@@ -42,7 +43,7 @@ import com.android.launcher3.CellLayout;
*/
public class FocusLogic {
private static final String TAG = "Focus";
private static final String TAG = "FocusLogic";
private static final boolean DEBUG = false;
// Item and page index related constant used by {@link #handleKeyEvent}.
@@ -51,12 +52,14 @@ public class FocusLogic {
public static final int PREVIOUS_PAGE_RIGHT_COLUMN = -2;
public static final int PREVIOUS_PAGE_FIRST_ITEM = -3;
public static final int PREVIOUS_PAGE_LAST_ITEM = -4;
public static final int PREVIOUS_PAGE_LEFT_COLUMN = -5;
public static final int CURRENT_PAGE_FIRST_ITEM = -5;
public static final int CURRENT_PAGE_LAST_ITEM = -6;
public static final int CURRENT_PAGE_FIRST_ITEM = -6;
public static final int CURRENT_PAGE_LAST_ITEM = -7;
public static final int NEXT_PAGE_FIRST_ITEM = -7;
public static final int NEXT_PAGE_LEFT_COLUMN = -8;
public static final int NEXT_PAGE_FIRST_ITEM = -8;
public static final int NEXT_PAGE_LEFT_COLUMN = -9;
public static final int NEXT_PAGE_RIGHT_COLUMN = -10;
// Matrix related constant.
public static final int EMPTY = -1;
@@ -85,18 +88,24 @@ public class FocusLogic {
cntX, cntY, iconIdx, pageIndex, pageCount));
}
DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid()
.getDeviceProfile();
int newIndex = NOOP;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, -1 /*increment*/);
if (newIndex == NOOP && pageIndex > 0) {
if (!profile.isLayoutRtl && newIndex == NOOP && pageIndex > 0) {
newIndex = PREVIOUS_PAGE_RIGHT_COLUMN;
} else if (profile.isLayoutRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
newIndex = NEXT_PAGE_RIGHT_COLUMN;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, 1 /*increment*/);
if (newIndex == NOOP && pageIndex < pageCount - 1) {
if (!profile.isLayoutRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
newIndex = NEXT_PAGE_LEFT_COLUMN;
} else if (profile.isLayoutRtl && newIndex == NOOP && pageIndex > 0) {
newIndex = PREVIOUS_PAGE_LEFT_COLUMN;
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
@@ -140,11 +149,18 @@ public class FocusLogic {
*/
// TODO: get rid of dynamic matrix creation.
public static int[][] createFullMatrix(int m, int n, boolean incrementOrder) {
DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid()
.getDeviceProfile();
int[][] matrix = new int [m][n];
for (int i=0; i < m;i++) {
for (int j=0; j < n; j++) {
if (incrementOrder) {
matrix[i][j] = j * m + i;
if (!profile.isLayoutRtl) {
matrix[i][j] = j * m + i;
} else {
matrix[i][j] = j * m + m - i -1;
}
} else {
matrix[i][j] = EMPTY;
}