1ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song/*
2ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Copyright (C) 2015 The Android Open Source Project
3ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *
4ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Licensed under the Apache License, Version 2.0 (the "License");
5ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * you may not use this file except in compliance with the License.
6ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * You may obtain a copy of the License at
7ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *
8ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *      http://www.apache.org/licenses/LICENSE-2.0
9ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *
10ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Unless required by applicable law or agreed to in writing, software
11ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * distributed under the License is distributed on an "AS IS" BASIS,
12ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * See the License for the specific language governing permissions and
14ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * limitations under the License.
15ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song */
16ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
17ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songpackage com.android.launcher3.util;
18ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
19ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songimport android.util.Log;
20ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songimport android.view.KeyEvent;
21fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyalimport android.view.View;
22ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songimport android.view.ViewGroup;
23ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
24ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songimport com.android.launcher3.CellLayout;
25ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Songimport com.android.launcher3.DeviceProfile;
262e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohenimport com.android.launcher3.Launcher;
27ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Songimport com.android.launcher3.LauncherAppState;
28fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyalimport com.android.launcher3.ShortcutAndWidgetContainer;
29fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal
30fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyalimport java.util.Arrays;
31ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
32ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song/**
33ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Calculates the next item that a {@link KeyEvent} should change the focus to.
34ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *<p>
35ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Note, this utility class calculates everything regards to icon index and its (x,y) coordinates.
36ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * Currently supports:
37ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * <ul>
38ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *  <li> full matrix of cells that are 1x1
39ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *  <li> sparse matrix of cells that are 1x1
40ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *     [ 1][  ][ 2][  ]
41ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *     [  ][  ][ 3][  ]
42ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *     [  ][ 4][  ][  ]
43ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song *     [  ][ 5][ 6][ 7]
44ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * </ul>
45ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * *<p>
46ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * For testing, one can use a BT keyboard, or use following adb command.
47ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song * ex. $ adb shell input keyevent 20 // KEYCODE_DPAD_LEFT
48ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song */
49ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Songpublic class FocusLogic {
50ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
51ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    private static final String TAG = "FocusLogic";
52ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static final boolean DEBUG = false;
53ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
54ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // Item and page index related constant used by {@link #handleKeyEvent}.
55ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public static final int NOOP = -1;
5631178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song
5738531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    public static final int PREVIOUS_PAGE_RIGHT_COLUMN  = -2;
5838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    public static final int PREVIOUS_PAGE_FIRST_ITEM    = -3;
5938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    public static final int PREVIOUS_PAGE_LAST_ITEM     = -4;
60ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int PREVIOUS_PAGE_LEFT_COLUMN   = -5;
6131178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song
62ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int CURRENT_PAGE_FIRST_ITEM     = -6;
63ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int CURRENT_PAGE_LAST_ITEM      = -7;
6431178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song
65ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int NEXT_PAGE_FIRST_ITEM        = -8;
66ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int NEXT_PAGE_LEFT_COLUMN       = -9;
67ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song    public static final int NEXT_PAGE_RIGHT_COLUMN      = -10;
68ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
69ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // Matrix related constant.
70ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public static final int EMPTY = -1;
7138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    public static final int PIVOT = 100;
72ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
73ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
74ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Returns true only if this utility class handles the key code.
75ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
76ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public static boolean shouldConsume(int keyCode) {
77fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
78ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
79ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END ||
8031178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN ||
81fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal                keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL);
82ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
83ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
842e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen    public static int handleKeyEvent(int keyCode, int cntX, int cntY,
852e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen            int [][] map, int iconIdx, int pageIndex, int pageCount, boolean isRtl) {
86ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
87ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
88ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            Log.v(TAG, String.format(
89ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    "handleKeyEvent START: cntX=%d, cntY=%d, iconIdx=%d, pageIdx=%d, pageCnt=%d",
90ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    cntX, cntY, iconIdx, pageIndex, pageCount));
91ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
92ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
93ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int newIndex = NOOP;
94ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        switch (keyCode) {
95ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_DPAD_LEFT:
96ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, -1 /*increment*/);
972e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                if (isRtl && newIndex == NOOP && pageIndex > 0) {
9838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song                    newIndex = PREVIOUS_PAGE_RIGHT_COLUMN;
992e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                } else if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
100ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song                    newIndex = NEXT_PAGE_RIGHT_COLUMN;
101ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
102ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
103ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_DPAD_RIGHT:
104ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, 1 /*increment*/);
1052e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
10638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song                    newIndex = NEXT_PAGE_LEFT_COLUMN;
1072e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen                } else if (isRtl && newIndex == NOOP && pageIndex > 0) {
108ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song                    newIndex = PREVIOUS_PAGE_LEFT_COLUMN;
109ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
110ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
111ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_DPAD_DOWN:
112ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, 1  /*increment*/);
113ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
114ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_DPAD_UP:
115ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, -1  /*increment*/);
116ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
117ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_MOVE_HOME:
118ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleMoveHome();
119ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
120ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_MOVE_END:
121ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handleMoveEnd();
122ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
123ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_PAGE_DOWN:
124ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handlePageDown(pageIndex, pageCount);
125ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
126ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case KeyEvent.KEYCODE_PAGE_UP:
127ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIndex = handlePageUp(pageIndex);
128ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
129ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            default:
130ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                break;
131ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
132ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
133ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
134ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            Log.v(TAG, String.format("handleKeyEvent FINISH: index [%d -> %s]",
135ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    iconIdx, getStringIndex(newIndex)));
136ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
137ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return newIndex;
138ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
139ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
140ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
141fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal     * Returns a matrix of size (m x n) that has been initialized with {@link #EMPTY}.
142ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     *
143ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * @param m                 number of columns in the matrix
144ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * @param n                 number of rows in the matrix
145ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
146ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // TODO: get rid of dynamic matrix creation.
147fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal    private static int[][] createFullMatrix(int m, int n) {
148ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int[][] matrix = new int [m][n];
149ada50984dc149c1f4337f965fbb59bdeaac8d09fHyunyoung Song
150ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i=0; i < m;i++) {
151fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal            Arrays.fill(matrix[i], EMPTY);
152ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
153ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return matrix;
154ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
155ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
156ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
157ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Returns a matrix of size same as the {@link CellLayout} dimension that is initialized with the
158ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * index of the child view.
159ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
160ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // TODO: get rid of the dynamic matrix creation
161ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public static int[][] createSparseMatrix(CellLayout layout) {
162fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        ShortcutAndWidgetContainer parent = layout.getShortcutsAndWidgets();
163ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        final int m = layout.getCountX();
164ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        final int n = layout.getCountY();
165fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        final boolean invert = parent.invertLayoutHorizontally();
166ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
167fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        int[][] matrix = createFullMatrix(m, n);
168ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
169ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Iterate thru the children.
170ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i = 0; i < parent.getChildCount(); i++ ) {
171ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int cx = ((CellLayout.LayoutParams) parent.getChildAt(i).getLayoutParams()).cellX;
172ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int cy = ((CellLayout.LayoutParams) parent.getChildAt(i).getLayoutParams()).cellY;
173fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal            matrix[invert ? (m - cx - 1) : cx][cy] = i;
174ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
175ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
17638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            printMatrix(matrix);
177ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
178ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return matrix;
179ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
180ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
181ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
182ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Creates a sparse matrix that merges the icon and hotseat view group using the cell layout.
183ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * The size of the returning matrix is [icon column count x (icon + hotseat row count)]
184ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * in portrait orientation. In landscape, [(icon + hotseat) column count x (icon row count)]
185ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
18631178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song    // TODO: get rid of the dynamic matrix creation
187ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    public static int[][] createSparseMatrix(CellLayout iconLayout, CellLayout hotseatLayout,
18818bfaafd3da45dce7b5f73eaa1665f228353338cHyunyoung Song            boolean isHorizontal, int allappsiconRank, boolean includeAllappsicon) {
189ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
190ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
191ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets();
192ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
193ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int m, n;
19418bfaafd3da45dce7b5f73eaa1665f228353338cHyunyoung Song        if (isHorizontal) {
195ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            m = iconLayout.getCountX();
196ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            n = iconLayout.getCountY() + hotseatLayout.getCountY();
19718bfaafd3da45dce7b5f73eaa1665f228353338cHyunyoung Song        } else {
198ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            m = iconLayout.getCountX() + hotseatLayout.getCountX();
199ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            n = iconLayout.getCountY();
200ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
201fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        int[][] matrix = createFullMatrix(m, n);
202ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
203ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Iterate thru the children of the top parent.
204ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i = 0; i < iconParent.getChildCount(); i++) {
205ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int cx = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellX;
206ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int cy = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellY;
207ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            matrix[cx][cy] = i;
208ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
209ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
210ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Iterate thru the children of the bottom parent
21131178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song        // The hotseat view group contains one more item than iconLayout column count.
21231178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song        // If {@param allappsiconRank} not negative, then the last icon in the hotseat
21331178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song        // is truncated. If it is negative, then all apps icon index is not inserted.
21431178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song        for(int i = hotseatParent.getChildCount() - 1; i >= (includeAllappsicon ? 0 : 1); i--) {
21531178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song            int delta = 0;
21618bfaafd3da45dce7b5f73eaa1665f228353338cHyunyoung Song            if (isHorizontal) {
217ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                int cx = ((CellLayout.LayoutParams)
218ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                        hotseatParent.getChildAt(i).getLayoutParams()).cellX;
21931178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                if ((includeAllappsicon && cx >= allappsiconRank) ||
22031178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                        (!includeAllappsicon && cx > allappsiconRank)) {
22131178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                        delta = -1;
222ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
22331178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                matrix[cx + delta][iconLayout.getCountY()] = iconParent.getChildCount() + i;
22418bfaafd3da45dce7b5f73eaa1665f228353338cHyunyoung Song            } else {
225ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                int cy = ((CellLayout.LayoutParams)
226ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                        hotseatParent.getChildAt(i).getLayoutParams()).cellY;
22731178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                if ((includeAllappsicon && cy >= allappsiconRank) ||
22831178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                        (!includeAllappsicon && cy > allappsiconRank)) {
22931178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                        delta = -1;
230ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
23131178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song                matrix[iconLayout.getCountX()][cy + delta] = iconParent.getChildCount() + i;
232ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
233ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
234ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
23538531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            printMatrix(matrix);
23638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        }
23738531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        return matrix;
23838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    }
23938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
24038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    /**
24138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * Creates a sparse matrix that merges the icon of previous/next page and last column of
24238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * current page. When left key is triggered on the leftmost column, sparse matrix is created
24338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * that combines previous page matrix and an extra column on the right. Likewise, when right
24438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * key is triggered on the rightmost column, sparse matrix is created that combines this column
24538531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * on the 0th column and the next page matrix.
24638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     *
24738531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * @param pivotX    x coordinate of the focused item in the current page
24838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * @param pivotY    y coordinate of the focused item in the current page
24938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     */
25038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    // TODO: get rid of the dynamic matrix creation
25138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    public static int[][] createSparseMatrix(CellLayout iconLayout, int pivotX, int pivotY) {
25238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
25338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
25438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
255fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        int[][] matrix = createFullMatrix(iconLayout.getCountX() + 1, iconLayout.getCountY());
25638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
25738531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        // Iterate thru the children of the top parent.
25838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        for (int i = 0; i < iconParent.getChildCount(); i++) {
25938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            int cx = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellX;
26038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            int cy = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellY;
26138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            if (pivotX < 0) {
26238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song                matrix[cx - pivotX][cy] = i;
26338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            } else {
26438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song                matrix[cx][cy] = i;
26538531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            }
26638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        }
26738531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
26838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        if (pivotX < 0) {
26938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            matrix[0][pivotY] = PIVOT;
27038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        } else {
27138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            matrix[pivotX][pivotY] = PIVOT;
27238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        }
27338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        if (DEBUG) {
27438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            printMatrix(matrix);
275ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
276ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return matrix;
277ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
278ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
279ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    //
280ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // key event handling methods.
281ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    //
282ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
283ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
284ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Calculates icon that has is closest to the horizontal axis in reference to the cur icon.
285ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     *
286ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Example of the check order for KEYCODE_DPAD_RIGHT:
287ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][  ][13][14][15]
288ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][ 6][ 8][10][12]
289ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [ X][ 1][ 2][ 3][ 4]
290ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][ 5][ 7][ 9][11]
291ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
292ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // TODO: add unit tests to verify all permutation.
293ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handleDpadHorizontal(int iconIdx, int cntX, int cntY,
294ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int[][] matrix, int increment) {
295ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if(matrix == null) {
296ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            throw new IllegalStateException("Dpad navigation requires a matrix.");
297ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
298ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int newIconIndex = NOOP;
299ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
300ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int xPos = -1;
301ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int yPos = -1;
302ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Figure out the location of the icon.
303ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i = 0; i < cntX; i++) {
304ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            for (int j = 0; j < cntY; j++) {
305ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if (matrix[i][j] == iconIdx) {
306ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    xPos = i;
307ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    yPos = j;
308ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
309ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
310ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
311ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
312ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            Log.v(TAG, String.format("\thandleDpadHorizontal: \t[x, y]=[%d, %d] iconIndex=%d",
313ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    xPos, yPos, iconIdx));
314ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
315ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
316ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Rule1: check first in the horizontal direction
317ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i = xPos + increment; 0 <= i && i < cntX; i = i + increment) {
31831178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song            if ((newIconIndex = inspectMatrix(i, yPos, cntX, cntY, matrix)) != NOOP) {
319ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                return newIconIndex;
320ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
321ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
322ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
323ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Rule2: check (x1-n, yPos + increment),   (x1-n, yPos - increment)
324ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        //              (x2-n, yPos + 2*increment), (x2-n, yPos - 2*increment)
325ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int nextYPos1;
326ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int nextYPos2;
327ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int i = -1;
328ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int coeff = 1; coeff < cntY; coeff++) {
329ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            nextYPos1 = yPos + coeff * increment;
330ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            nextYPos2 = yPos - coeff * increment;
331ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            for (i = xPos + increment * coeff; 0 <= i && i < cntX; i = i + increment) {
332ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if ((newIconIndex = inspectMatrix(i, nextYPos1, cntX, cntY, matrix)) != NOOP) {
333ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    return newIconIndex;
334ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
335ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if ((newIconIndex = inspectMatrix(i, nextYPos2, cntX, cntY, matrix)) != NOOP) {
336ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    return newIconIndex;
337ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
338ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
339ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
340ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return newIconIndex;
341ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
342ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
343ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    /**
344ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Calculates icon that is closest to the vertical axis in reference to the current icon.
345ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     *
346ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * Example of the check order for KEYCODE_DPAD_DOWN:
347ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][  ][  ][ X][  ][  ][  ]
348ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][  ][ 5][ 1][ 4][  ][  ]
349ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [  ][10][ 7][ 2][ 6][ 9][  ]
350ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     * [14][12][ 9][ 3][ 8][11][13]
351ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song     */
352ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // TODO: add unit tests to verify all permutation.
353ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handleDpadVertical(int iconIndex, int cntX, int cntY,
354ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            int [][] matrix, int increment) {
355ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int newIconIndex = NOOP;
356ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if(matrix == null) {
357ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            throw new IllegalStateException("Dpad navigation requires a matrix.");
358ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
359ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
360ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int xPos = -1;
361ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int yPos = -1;
362ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Figure out the location of the icon.
363ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int i = 0; i< cntX; i++) {
364ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            for (int j = 0; j < cntY; j++) {
365ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if (matrix[i][j] == iconIndex) {
366ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    xPos = i;
367ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    yPos = j;
368ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
369ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
370ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
371ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
372ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (DEBUG) {
373ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            Log.v(TAG, String.format("\thandleDpadVertical: \t[x, y]=[%d, %d] iconIndex=%d",
374ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    xPos, yPos, iconIndex));
375ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
376ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
377ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Rule1: check first in the dpad direction
378ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int j = yPos + increment; 0 <= j && j <cntY && 0 <= j; j = j + increment) {
37931178b8237ccb6af666df60ef60c116c8afdf316Hyunyoung Song            if ((newIconIndex = inspectMatrix(xPos, j, cntX, cntY, matrix)) != NOOP) {
380ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                return newIconIndex;
381ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
382ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
383ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
384ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        // Rule2: check (xPos + increment, y_(1-n)),   (xPos - increment, y_(1-n))
385ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        //              (xPos + 2*increment, y_(2-n))), (xPos - 2*increment, y_(2-n))
386ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int nextXPos1;
387ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int nextXPos2;
388ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int j = -1;
389ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int coeff = 1; coeff < cntX; coeff++) {
390ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            nextXPos1 = xPos + coeff * increment;
391ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            nextXPos2 = xPos - coeff * increment;
392ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            for (j = yPos + increment * coeff; 0 <= j && j < cntY; j = j + increment) {
393ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if ((newIconIndex = inspectMatrix(nextXPos1, j, cntX, cntY, matrix)) != NOOP) {
394ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    return newIconIndex;
395ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
396ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if ((newIconIndex = inspectMatrix(nextXPos2, j, cntX, cntY, matrix)) != NOOP) {
397ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    return newIconIndex;
398ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
399ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
400ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
401ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return newIconIndex;
402ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
403ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
404ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handleMoveHome() {
405ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return CURRENT_PAGE_FIRST_ITEM;
406ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
407ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
408ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handleMoveEnd() {
409ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return CURRENT_PAGE_LAST_ITEM;
410ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
411ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
412ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handlePageDown(int pageIndex, int pageCount) {
413ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (pageIndex < pageCount -1) {
414ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            return NEXT_PAGE_FIRST_ITEM;
415ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
416ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return CURRENT_PAGE_LAST_ITEM;
417ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
418ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
419ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int handlePageUp(int pageIndex) {
420ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (pageIndex > 0) {
421ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            return PREVIOUS_PAGE_FIRST_ITEM;
422ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        } else {
423ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            return CURRENT_PAGE_FIRST_ITEM;
424ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
425ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
426ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
427ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    //
428ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    // Helper methods.
429ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    //
430ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
431ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static boolean isValid(int xPos, int yPos, int countX, int countY) {
432ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return (0 <= xPos && xPos < countX && 0 <= yPos && yPos < countY);
433ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
434ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
435ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static int inspectMatrix(int x, int y, int cntX, int cntY, int[][] matrix) {
436ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        int newIconIndex = NOOP;
437ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        if (isValid(x, y, cntX, cntY)) {
438ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            if (matrix[x][y] != -1) {
439ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                newIconIndex = matrix[x][y];
440ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                if (DEBUG) {
441ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                    Log.v(TAG, String.format("\t\tinspect: \t[x, y]=[%d, %d] %d",
442ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                            x, y, matrix[x][y]));
443ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                }
444ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                return newIconIndex;
445ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
446ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
447ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        return newIconIndex;
448ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
449ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
45038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    /**
45138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * Only used for debugging.
45238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     */
453ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    private static String getStringIndex(int index) {
454ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        switch(index) {
455ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case NOOP: return "NOOP";
456ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case PREVIOUS_PAGE_FIRST_ITEM:  return "PREVIOUS_PAGE_FIRST";
457ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case PREVIOUS_PAGE_LAST_ITEM:   return "PREVIOUS_PAGE_LAST";
45838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            case PREVIOUS_PAGE_RIGHT_COLUMN:return "PREVIOUS_PAGE_RIGHT_COLUMN";
459ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case CURRENT_PAGE_FIRST_ITEM:   return "CURRENT_PAGE_FIRST";
460ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case CURRENT_PAGE_LAST_ITEM:    return "CURRENT_PAGE_LAST";
461ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            case NEXT_PAGE_FIRST_ITEM:      return "NEXT_PAGE_FIRST";
46238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            case NEXT_PAGE_LEFT_COLUMN:     return "NEXT_PAGE_LEFT_COLUMN";
463ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            default:
464ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                return Integer.toString(index);
465ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
466ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
467ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song
46838531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    /**
46938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     * Only used for debugging.
47038531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     */
47138531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    private static void printMatrix(int[][] matrix) {
472ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        Log.v(TAG, "\tprintMap:");
47338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        int m = matrix.length;
47438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        int n = matrix[0].length;
47538531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
476ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        for (int j=0; j < n; j++) {
477ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            String colY = "\t\t";
478ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            for (int i=0; i < m; i++) {
479ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song                colY +=  String.format("%3d",matrix[i][j]);
480ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            }
481ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song            Log.v(TAG, colY);
482ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song        }
483ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song    }
48438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song
48538531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    /**
486fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal     * @param edgeColumn the column of the new icon. either {@link #NEXT_PAGE_LEFT_COLUMN} or
487fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal     * {@link #NEXT_PAGE_RIGHT_COLUMN}
488fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal     * @return the view adjacent to {@param oldView} in the {@param nextPage}.
48938531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song     */
490fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal    public static View getAdjacentChildInNextPage(
491fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal            ShortcutAndWidgetContainer nextPage, View oldView, int edgeColumn) {
492fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        final int newRow = ((CellLayout.LayoutParams) oldView.getLayoutParams()).cellY;
493fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal
494fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        int column = (edgeColumn == NEXT_PAGE_LEFT_COLUMN) ^ nextPage.invertLayoutHorizontally()
495fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal                ? 0 : (((CellLayout) nextPage.getParent()).getCountX() - 1);
496fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal
497fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        for (; column >= 0; column--) {
498fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal            for (int row = newRow; row >= 0; row--) {
499fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal                View newView = nextPage.getChildAt(column, row);
500fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal                if (newView != null) {
501fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal                    return newView;
50238531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song                }
50338531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song            }
50438531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song        }
505fc3c1edf7bbc3f7cb23e79520731d13ccc2da046Sunny Goyal        return null;
50638531719636eba7c924e3e71c583ebce2c89a1d0Hyunyoung Song    }
507ee3e6a7b777e58552a26ab8a10641886588e9196Hyunyoung Song}
508