diff options
-rw-r--r-- | src/com/android/launcher3/FocusHelper.java | 22 | ||||
-rw-r--r-- | src/com/android/launcher3/Hotseat.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/util/FocusLogic.java | 108 | ||||
-rw-r--r-- | tests/src/com/android/launcher3/util/FocusLogicTest.java | 150 |
4 files changed, 232 insertions, 50 deletions
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 8516afb4e..3d12aa3e2 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -223,20 +223,18 @@ public class FocusHelper { if (keyCode == KeyEvent.KEYCODE_DPAD_UP && !profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, - true /* hotseat horizontal */, profile.inv.hotseatAllAppsRank, - iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */); + true /* hotseat horizontal */, profile.inv.hotseatAllAppsRank); iconIndex += iconParent.getChildCount(); - countX = iconLayout.getCountX(); + countX = hotseatLayout.getCountX(); countY = iconLayout.getCountY() + hotseatLayout.getCountY(); parent = iconParent; } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, - false /* hotseat horizontal */, profile.inv.hotseatAllAppsRank, - iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */); + false /* hotseat horizontal */, profile.inv.hotseatAllAppsRank); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX() + hotseatLayout.getCountX(); - countY = iconLayout.getCountY(); + countY = hotseatLayout.getCountY(); parent = iconParent; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && profile.isVerticalBarLayout()) { @@ -326,15 +324,15 @@ public class FocusHelper { // with the hotseat. if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */, - profile.inv.hotseatAllAppsRank, - !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); - countY = countY + 1; + profile.inv.hotseatAllAppsRank); + countX = hotseatLayout.getCountX(); + countY = countY + hotseatLayout.getCountY(); } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */, - profile.inv.hotseatAllAppsRank, - !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); - countX = countX + 1; + profile.inv.hotseatAllAppsRank); + countX = countX + hotseatLayout.getCountX(); + countY = hotseatLayout.getCountY(); } else if (isUninstallKeyChord(e)) { matrix = FocusLogic.createSparseMatrix(iconLayout); if (UninstallDropTarget.supportsDrop(launcher, itemInfo)) { diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 902b6ec61..3e838760e 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -70,7 +70,7 @@ public class Hotseat extends FrameLayout public void setOnLongClickListener(OnLongClickListener l) { mContent.setOnLongClickListener(l); } - + /* Get the orientation invariant order of the item in the hotseat for persistence. */ int getOrderInHotseat(int x, int y) { return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x; diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java index 2aae3c089..f56d16222 100644 --- a/src/com/android/launcher3/util/FocusLogic.java +++ b/src/com/android/launcher3/util/FocusLogic.java @@ -63,6 +63,8 @@ public class FocusLogic { public static final int NEXT_PAGE_LEFT_COLUMN = -9; public static final int NEXT_PAGE_RIGHT_COLUMN = -10; + public static final int ALL_APPS_COLUMN = -11; + // Matrix related constant. public static final int EMPTY = -1; public static final int PIVOT = 100; @@ -186,22 +188,36 @@ public class FocusLogic { */ // TODO: get rid of the dynamic matrix creation public static int[][] createSparseMatrix(CellLayout iconLayout, CellLayout hotseatLayout, - boolean isHorizontal, int allappsiconRank, boolean includeAllappsicon) { + boolean isHotseatHorizontal, int allappsiconRank) { ViewGroup iconParent = iconLayout.getShortcutsAndWidgets(); ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets(); + boolean moreIconsInHotseatThanWorkspace = isHotseatHorizontal ? + hotseatLayout.getCountX() > iconLayout.getCountX() : + hotseatLayout.getCountY() > iconLayout.getCountY(); + int m, n; - if (isHorizontal) { - m = iconLayout.getCountX(); + if (isHotseatHorizontal) { + m = hotseatLayout.getCountX(); n = iconLayout.getCountY() + hotseatLayout.getCountY(); } else { m = iconLayout.getCountX() + hotseatLayout.getCountX(); - n = iconLayout.getCountY(); + n = hotseatLayout.getCountY(); } int[][] matrix = createFullMatrix(m, n); - - // Iterate thru the children of the top parent. + if (moreIconsInHotseatThanWorkspace) { + if (isHotseatHorizontal) { + for (int j = 0; j < n; j++) { + matrix[allappsiconRank][j] = ALL_APPS_COLUMN; + } + } else { + for (int j = 0; j < m; j++) { + matrix[j][allappsiconRank] = ALL_APPS_COLUMN; + } + } + } + // Iterate thru the children of the workspace. for (int i = 0; i < iconParent.getChildCount(); i++) { View cell = iconParent.getChildAt(i); if (!cell.isFocusable()) { @@ -209,31 +225,29 @@ public class FocusLogic { } int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX; int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY; + if (moreIconsInHotseatThanWorkspace) { + if (isHotseatHorizontal && cx >= allappsiconRank) { + // Add 1 to account for the All Apps button. + cx++; + } + if (!isHotseatHorizontal && cy >= allappsiconRank) { + // Add 1 to account for the All Apps button. + cy++; + } + } matrix[cx][cy] = i; } - // Iterate thru the children of the bottom parent - // The hotseat view group contains one more item than iconLayout column count. - // If {@param allappsiconRank} not negative, then the last icon in the hotseat - // is truncated. If it is negative, then all apps icon index is not inserted. - for(int i = hotseatParent.getChildCount() - 1; i >= (includeAllappsicon ? 0 : 1); i--) { - int delta = 0; - if (isHorizontal) { + // Iterate thru the children of the hotseat. + for (int i = hotseatParent.getChildCount() - 1; i >= 0; i--) { + if (isHotseatHorizontal) { int cx = ((CellLayout.LayoutParams) hotseatParent.getChildAt(i).getLayoutParams()).cellX; - if ((includeAllappsicon && cx >= allappsiconRank) || - (!includeAllappsicon && cx > allappsiconRank)) { - delta = -1; - } - matrix[cx + delta][iconLayout.getCountY()] = iconParent.getChildCount() + i; + matrix[cx][iconLayout.getCountY()] = iconParent.getChildCount() + i; } else { int cy = ((CellLayout.LayoutParams) hotseatParent.getChildAt(i).getLayoutParams()).cellY; - if ((includeAllappsicon && cy >= allappsiconRank) || - (!includeAllappsicon && cy > allappsiconRank)) { - delta = -1; - } - matrix[iconLayout.getCountX()][cy + delta] = iconParent.getChildCount() + i; + matrix[iconLayout.getCountX()][cy] = iconParent.getChildCount() + i; } } if (DEBUG) { @@ -323,8 +337,9 @@ public class FocusLogic { } // Rule1: check first in the horizontal direction - for (int i = xPos + increment; 0 <= i && i < cntX; i = i + increment) { - if ((newIconIndex = inspectMatrix(i, yPos, cntX, cntY, matrix)) != NOOP) { + for (int x = xPos + increment; 0 <= x && x < cntX; x += increment) { + if ((newIconIndex = inspectMatrix(x, yPos, cntX, cntY, matrix)) != NOOP + && newIconIndex != ALL_APPS_COLUMN) { return newIconIndex; } } @@ -333,15 +348,23 @@ public class FocusLogic { // (x2-n, yPos + 2*increment), (x2-n, yPos - 2*increment) int nextYPos1; int nextYPos2; - int i = -1; + int x = -1; for (int coeff = 1; coeff < cntY; coeff++) { nextYPos1 = yPos + coeff * increment; nextYPos2 = yPos - coeff * increment; - for (i = xPos + increment * coeff; 0 <= i && i < cntX; i = i + increment) { - if ((newIconIndex = inspectMatrix(i, nextYPos1, cntX, cntY, matrix)) != NOOP) { + x = xPos + increment * coeff; + if (inspectMatrix(x, nextYPos1, cntX, cntY, matrix) == ALL_APPS_COLUMN) { + nextYPos1 += increment; + + } + if (inspectMatrix(x, nextYPos2, cntX, cntY, matrix) == ALL_APPS_COLUMN) { + nextYPos2 -= increment; + } + for (; 0 <= x && x < cntX; x += increment) { + if ((newIconIndex = inspectMatrix(x, nextYPos1, cntX, cntY, matrix)) != NOOP) { return newIconIndex; } - if ((newIconIndex = inspectMatrix(i, nextYPos2, cntX, cntY, matrix)) != NOOP) { + if ((newIconIndex = inspectMatrix(x, nextYPos2, cntX, cntY, matrix)) != NOOP) { return newIconIndex; } } @@ -350,9 +373,10 @@ public class FocusLogic { // Rule 3: if switching between pages, do a brute-force search to find an item that was // missed by rules 1 and 2 (such as when going from a bottom right icon to top left) if (iconIdx == PIVOT) { - for (int x = xPos + increment; 0 <= x && x < cntX; x = x + increment) { + for (x = xPos + increment; 0 <= x && x < cntX; x += increment) { for (int y = 0; y < cntY; y++) { - if ((newIconIndex = inspectMatrix(x, y, cntX, cntY, matrix)) != NOOP) { + if ((newIconIndex = inspectMatrix(x, y, cntX, cntY, matrix)) != NOOP + && newIconIndex != ALL_APPS_COLUMN) { return newIconIndex; } } @@ -396,8 +420,9 @@ public class FocusLogic { } // Rule1: check first in the dpad direction - for (int j = yPos + increment; 0 <= j && j <cntY && 0 <= j; j = j + increment) { - if ((newIconIndex = inspectMatrix(xPos, j, cntX, cntY, matrix)) != NOOP) { + for (int y = yPos + increment; 0 <= y && y <cntY && 0 <= y; y += increment) { + if ((newIconIndex = inspectMatrix(xPos, y, cntX, cntY, matrix)) != NOOP + && newIconIndex != ALL_APPS_COLUMN) { return newIconIndex; } } @@ -406,15 +431,23 @@ public class FocusLogic { // (xPos + 2*increment, y_(2-n))), (xPos - 2*increment, y_(2-n)) int nextXPos1; int nextXPos2; - int j = -1; + int y = -1; for (int coeff = 1; coeff < cntX; coeff++) { nextXPos1 = xPos + coeff * increment; nextXPos2 = xPos - coeff * increment; - for (j = yPos + increment * coeff; 0 <= j && j < cntY; j = j + increment) { - if ((newIconIndex = inspectMatrix(nextXPos1, j, cntX, cntY, matrix)) != NOOP) { + y = yPos + increment * coeff; + if (inspectMatrix(nextXPos1, y, cntX, cntY, matrix) == ALL_APPS_COLUMN) { + nextXPos1 += increment; + + } + if (inspectMatrix(nextXPos2, y, cntX, cntY, matrix) == ALL_APPS_COLUMN) { + nextXPos2 -= increment; + } + for (; 0 <= y && y < cntY; y = y + increment) { + if ((newIconIndex = inspectMatrix(nextXPos1, y, cntX, cntY, matrix)) != NOOP) { return newIconIndex; } - if ((newIconIndex = inspectMatrix(nextXPos2, j, cntX, cntY, matrix)) != NOOP) { + if ((newIconIndex = inspectMatrix(nextXPos2, y, cntX, cntY, matrix)) != NOOP) { return newIconIndex; } } @@ -481,6 +514,7 @@ public class FocusLogic { case CURRENT_PAGE_LAST_ITEM: return "CURRENT_PAGE_LAST"; case NEXT_PAGE_FIRST_ITEM: return "NEXT_PAGE_FIRST"; case NEXT_PAGE_LEFT_COLUMN: return "NEXT_PAGE_LEFT_COLUMN"; + case ALL_APPS_COLUMN: return "ALL_APPS_COLUMN"; default: return Integer.toString(index); } diff --git a/tests/src/com/android/launcher3/util/FocusLogicTest.java b/tests/src/com/android/launcher3/util/FocusLogicTest.java index 2c2f0d3df..f93e91313 100644 --- a/tests/src/com/android/launcher3/util/FocusLogicTest.java +++ b/tests/src/com/android/launcher3/util/FocusLogicTest.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.view.KeyEvent; +import android.view.View; import com.android.launcher3.util.FocusLogic; @@ -82,6 +83,155 @@ public final class FocusLogicTest extends AndroidTestCase { assertEquals(0, i); } + public void testMoveIntoHotseatWithEqualHotseatAndWorkspaceColumns() { + // Test going from an icon right above the All Apps button to the All Apps button. + int[][] map = transpose(new int[][] { + {-1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1}, + {-1, -1, 0, -1, -1}, + { 2, 3, 1, 4, 5}, + }); + int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + // Test going from an icon above and to the right of the All Apps + // button to an icon to the right of the All Apps button. + map = transpose(new int[][] { + {-1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1}, + {-1, -1, -1, -1, -1}, + {-1, -1, -1, 0, -1}, + { 2, 3, 1, 4, 5}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 5, 5, map, 0, 1, 1, true); + assertEquals(4, i); + } + + public void testMoveIntoHotseatWithExtraColumnForAllApps() { + // Test going from an icon above and to the left + // of the All Apps button to the All Apps button. + int[][] map = transpose(new int[][] { + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, 0,-11, -1, -1, -1}, + {-1, -1, -1, 1, 1, -1, -1}, + }); + int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 0, 1, 1, true); + assertEquals(1, i); + // Test going from an icon above and to the right + // of the All Apps button to the All Apps button. + map = transpose(new int[][] { + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, 0, -1, -1}, + {-1, -1, -1, 1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 0, 1, 1, true); + assertEquals(1, i); + // Test going from the All Apps button to an icon + // above and to the right of the All Apps button. + map = transpose(new int[][] { + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, 0, -1, -1}, + {-1, -1, -1, 1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_UP, 7, 6, map, 1, 1, 1, true); + assertEquals(0, i); + // Test going from an icon above and to the left of the + // All Apps button in landscape to the All Apps button. + map = transpose(new int[][] { + { -1, -1, -1, -1, -1}, + { -1, -1, -1, 0, -1}, + {-11,-11,-11,-11, 1}, + { -1, -1, -1, -1, -1}, + { -1, -1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + // Test going from the All Apps button in landscape to + // an icon above and to the left of the All Apps button. + map = transpose(new int[][] { + { -1, -1, -1, -1, -1}, + { -1, -1, -1, 0, -1}, + {-11,-11,-11,-11, 1}, + { -1, -1, -1, -1, -1}, + { -1, -1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT, 5, 5, map, 1, 1, 1, true); + assertEquals(0, i); + // Test that going to the hotseat always goes to the same row as the original icon. + map = transpose(new int[][]{ + { 0, 1, 2,-11, 3, 4, 5}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + {-1, -1, -1,-11, -1, -1, -1}, + { 7, 8, 9, 6, 10, 11, 12}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 0, 1, 1, true); + assertEquals(7, i); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 1, 1, 1, true); + assertEquals(8, i); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 2, 1, 1, true); + assertEquals(9, i); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 3, 1, 1, true); + assertEquals(10, i); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 4, 1, 1, true); + assertEquals(11, i); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 7, 6, map, 5, 1, 1, true); + assertEquals(12, i); + } + + public void testCrossingAllAppsColumn() { + // Test crossing from left to right in portrait. + int[][] map = transpose(new int[][] { + {-1, -1,-11, -1, -1}, + {-1, 0,-11, -1, -1}, + {-1, -1,-11, 1, -1}, + {-1, -1,-11, -1, -1}, + {-1, -1, 2, -1, -1}, + }); + int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + // Test crossing from right to left in portrait. + map = transpose(new int[][] { + {-1, -1,-11, -1, -1}, + {-1, -1,-11, 0, -1}, + {-1, 1,-11, -1, -1}, + {-1, -1,-11, -1, -1}, + {-1, -1, 2, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + // Test crossing from left to right in landscape. + map = transpose(new int[][] { + { -1, -1, -1, -1, -1}, + { -1, -1, -1, 0, -1}, + {-11,-11,-11,-11, 2}, + { -1, 1, -1, -1, -1}, + { -1, -1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + // Test crossing from right to left in landscape. + map = transpose(new int[][] { + { -1, -1, -1, -1, -1}, + { -1, 0, -1, -1, -1}, + {-11,-11,-11,-11, 2}, + { -1, -1, 1, -1, -1}, + { -1, -1, -1, -1, -1}, + }); + i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, 5, 5, map, 0, 1, 1, true); + assertEquals(1, i); + } + /** Transposes the matrix so that we can write it in human-readable format in the tests. */ private int[][] transpose(int[][] m) { int[][] t = new int[m[0].length][m.length]; |