blob: 737f6cca7ccf3e174711e1d9934e620edc374af3 [file] [log] [blame]
Winson Chung97d85d22011-04-13 11:27:36 -07001/*
Hyunyoung Songee3e6a72015-02-20 14:25:27 -08002 * Copyright (C) 2015 The Android Open Source Project
Winson Chung97d85d22011-04-13 11:27:36 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
Winson Chung97d85d22011-04-13 11:27:36 -070018
Winson Chung4e6a9762011-05-09 11:56:34 -070019import android.content.res.Configuration;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080020import android.util.Log;
Winson Chung97d85d22011-04-13 11:27:36 -070021import android.view.KeyEvent;
Sunny Goyalb3726d92014-08-20 16:58:17 -070022import android.view.SoundEffectConstants;
Winson Chung97d85d22011-04-13 11:27:36 -070023import android.view.View;
24import android.view.ViewGroup;
Winson Chung97d85d22011-04-13 11:27:36 -070025
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080026import com.android.launcher3.util.FocusLogic;
Winson Chungfaa13252011-06-13 18:15:54 -070027
Winson Chung97d85d22011-04-13 11:27:36 -070028/**
Winson Chung4d279d92011-07-21 11:46:32 -070029 * A keyboard listener we set on all the workspace icons.
30 */
Adam Cohenac56cff2011-09-28 20:45:37 -070031class IconKeyEventListener implements View.OnKeyListener {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080032 @Override
Winson Chung4d279d92011-07-21 11:46:32 -070033 public boolean onKey(View v, int keyCode, KeyEvent event) {
Adam Cohenac56cff2011-09-28 20:45:37 -070034 return FocusHelper.handleIconKeyEvent(v, keyCode, event);
35 }
36}
37
38/**
39 * A keyboard listener we set on all the workspace icons.
40 */
41class FolderKeyEventListener implements View.OnKeyListener {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080042 @Override
Adam Cohenac56cff2011-09-28 20:45:37 -070043 public boolean onKey(View v, int keyCode, KeyEvent event) {
44 return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
Winson Chung4d279d92011-07-21 11:46:32 -070045 }
46}
47
48/**
Winson Chung3d503fb2011-07-13 17:25:49 -070049 * A keyboard listener we set on all the hotseat buttons.
Winson Chung4e6a9762011-05-09 11:56:34 -070050 */
Adam Cohenac56cff2011-09-28 20:45:37 -070051class HotseatIconKeyEventListener implements View.OnKeyListener {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080052 @Override
Winson Chung4e6a9762011-05-09 11:56:34 -070053 public boolean onKey(View v, int keyCode, KeyEvent event) {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080054 return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event);
Winson Chung4e6a9762011-05-09 11:56:34 -070055 }
56}
57
Winson Chung97d85d22011-04-13 11:27:36 -070058public class FocusHelper {
Winson Chung97d85d22011-04-13 11:27:36 -070059
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080060 private static final String TAG = "FocusHelper";
61 private static final boolean DEBUG = false;
62
63 //
64 // Key code handling methods.
65 //
66
67 /**
68 * Handles key events in the all apps screen.
69 */
70 static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
71 boolean consume = FocusLogic.shouldConsume(keyCode);
72 if (e.getAction() == KeyEvent.ACTION_UP) {
73 return consume;
74 }
75 if (DEBUG) {
76 Log.v(TAG, String.format("Handle ALL APPS keyevent=[%s].",
77 KeyEvent.keyCodeToString(keyCode)));
78 }
79
80 // Initialize variables.
81 ViewGroup parentLayout;
82 ViewGroup itemContainer;
83 int countX;
84 int countY;
85 if (v.getParent() instanceof ShortcutAndWidgetContainer) {
86 itemContainer = (ViewGroup) v.getParent();
87 parentLayout = (ViewGroup) itemContainer.getParent();
88 countX = ((CellLayout) parentLayout).getCountX();
89 countY = ((CellLayout) parentLayout).getCountY();
90 } else if (v.getParent() instanceof ViewGroup) {
Hyunyoung Song38531712015-03-03 19:25:16 -080091 //TODO(hyunyoungs): figure out when this needs to be called.
Hyunyoung Songee3e6a72015-02-20 14:25:27 -080092 itemContainer = parentLayout = (ViewGroup) v.getParent();
93 countX = ((PagedViewGridLayout) parentLayout).getCellCountX();
94 countY = ((PagedViewGridLayout) parentLayout).getCellCountY();
95 } else {
96 throw new IllegalStateException(
97 "Parent of the focused item inside all apps screen is not a supported type.");
98 }
99 final int iconIndex = itemContainer.indexOfChild(v);
100 final PagedView container = (PagedView) parentLayout.getParent();
101 final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout));
102 final int pageCount = container.getChildCount();
103 ViewGroup newParent = null;
104 View child = null;
Hyunyoung Song38531712015-03-03 19:25:16 -0800105 // TODO(hyunyoungs): this matrix is not applicable on the last page.
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800106 int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true);
107
108 // Process focus.
109 int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix,
110 iconIndex, pageIndex, pageCount);
111 if (newIconIndex == FocusLogic.NOOP) {
112 return consume;
113 }
114 switch (newIconIndex) {
Hyunyoung Song38531712015-03-03 19:25:16 -0800115 case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
116 newParent = getAppsCustomizePage(container, pageIndex -1);
117 if (newParent != null) {
118 int row = FocusLogic.findRow(matrix, iconIndex);
119 container.snapToPage(pageIndex - 1);
120 // no need to create a new matrix.
121 child = newParent.getChildAt(matrix[countX-1][row]);
122 }
123 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800124 case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
125 newParent = getAppsCustomizePage(container, pageIndex - 1);
126 if (newParent != null) {
127 container.snapToPage(pageIndex - 1);
128 child = newParent.getChildAt(0);
129 }
Hyunyoung Song38531712015-03-03 19:25:16 -0800130 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800131 case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
132 newParent = getAppsCustomizePage(container, pageIndex - 1);
133 if (newParent != null) {
134 container.snapToPage(pageIndex - 1);
135 child = newParent.getChildAt(newParent.getChildCount() - 1);
136 }
137 break;
138 case FocusLogic.NEXT_PAGE_FIRST_ITEM:
139 newParent = getAppsCustomizePage(container, pageIndex + 1);
140 if (newParent != null) {
141 container.snapToPage(pageIndex + 1);
142 child = newParent.getChildAt(0);
143 }
144 break;
Hyunyoung Song38531712015-03-03 19:25:16 -0800145 case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
146 newParent = getAppsCustomizePage(container, pageIndex + 1);
147 if (newParent != null) {
148 container.snapToPage(pageIndex + 1);
149 int row = FocusLogic.findRow(matrix, iconIndex);
150 child = newParent.getChildAt(matrix[0][row]);
151 }
152 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800153 case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
154 child = container.getChildAt(0);
155 break;
156 case FocusLogic.CURRENT_PAGE_LAST_ITEM:
157 child = itemContainer.getChildAt(itemContainer.getChildCount() - 1);
158 break;
159 default: // Go to some item on the current page.
160 child = itemContainer.getChildAt(newIconIndex);
161 break;
162 }
163 if (child != null) {
164 child.requestFocus();
165 playSoundEffect(keyCode, v);
166 }
167 return consume;
168 }
169
170 /**
171 * Handles key events in the workspace hot seat (bottom of the screen).
172 * <p>Currently we don't special case for the phone UI in different orientations, even though
173 * the hotseat is on the side in landscape mode. This is to ensure that accessibility
174 * consistency is maintained across rotations.
175 */
176 static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e) {
177 boolean consume = FocusLogic.shouldConsume(keyCode);
178 if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
179 return consume;
180 }
181 int orientation = v.getResources().getConfiguration().orientation;
182
183 if (DEBUG) {
184 Log.v(TAG, String.format(
185 "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, orientation=%d",
186 KeyEvent.keyCodeToString(keyCode), orientation));
187 }
188
189 // Initialize the variables.
190 final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent();
191 final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800192 Hotseat hotseat = (Hotseat) hotseatLayout.getParent();
193
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800194 Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
195 int pageIndex = workspace.getCurrentPage();
196 int pageCount = workspace.getChildCount();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800197 int countX = -1;
198 int countY = -1;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800199 int iconIndex = findIndexOfView(hotseatParent, v);
200
201 final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex);
202 final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
203
204 ViewGroup parent = null;
Hyunyoung Song31178b82015-02-24 14:12:51 -0800205 int[][] matrix = null;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800206
207 if (keyCode == KeyEvent.KEYCODE_DPAD_UP &&
208 orientation == Configuration.ORIENTATION_PORTRAIT) {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800209 matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation,
210 hotseat.getAllAppsButtonRank(), true /* include all apps icon */);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800211 iconIndex += iconParent.getChildCount();
212 countX = iconLayout.getCountX();
213 countY = iconLayout.getCountY() + hotseatLayout.getCountY();
214 parent = iconParent;
215 } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
216 orientation == Configuration.ORIENTATION_LANDSCAPE) {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800217 matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation,
218 hotseat.getAllAppsButtonRank(), true /* include all apps icon */);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800219 iconIndex += iconParent.getChildCount();
220 countX = iconLayout.getCountX() + hotseatLayout.getCountX();
221 countY = iconLayout.getCountY();
222 parent = iconParent;
Hyunyoung Song31178b82015-02-24 14:12:51 -0800223 } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
224 orientation == Configuration.ORIENTATION_LANDSCAPE) {
225 keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
226 }else {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800227 // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
228 // matrix extended with hotseat.
229 matrix = FocusLogic.createSparseMatrix(hotseatLayout);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800230 countX = hotseatLayout.getCountX();
231 countY = hotseatLayout.getCountY();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800232 parent = hotseatParent;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800233 }
234
235 // Process the focus.
236 int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix,
237 iconIndex, pageIndex, pageCount);
238
Hyunyoung Song31178b82015-02-24 14:12:51 -0800239 View newIcon = null;
240 if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
241 parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
242 newIcon = parent.getChildAt(0);
243 // TODO(hyunyoungs): handle cases where the child is not an icon but
244 // a folder or a widget.
245 workspace.snapToPage(pageIndex + 1);
246 }
247 if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800248 newIconIndex -= iconParent.getChildCount();
249 }
250 if (parent != null) {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800251 if (newIcon == null && newIconIndex >=0) {
252 newIcon = parent.getChildAt(newIconIndex);
253 }
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800254 if (newIcon != null) {
255 newIcon.requestFocus();
256 playSoundEffect(keyCode, v);
257 }
258 }
259 return consume;
260 }
261
262 /**
263 * Handles key events in a workspace containing icons.
264 */
265 static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
266 boolean consume = FocusLogic.shouldConsume(keyCode);
267 if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
268 return consume;
269 }
270 int orientation = v.getResources().getConfiguration().orientation;
271 if (DEBUG) {
272 Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] orientation=%d",
273 KeyEvent.keyCodeToString(keyCode), orientation));
274 }
275
276 // Initialize the variables.
277 ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
Hyunyoung Song38531712015-03-03 19:25:16 -0800278 CellLayout iconLayout = (CellLayout) parent.getParent();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800279 final Workspace workspace = (Workspace) iconLayout.getParent();
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800280 final ViewGroup launcher = (ViewGroup) workspace.getParent();
281 final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar);
Hyunyoung Song31178b82015-02-24 14:12:51 -0800282 final Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat);
283 int pageIndex = workspace.indexOfChild(iconLayout);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800284 int pageCount = workspace.getChildCount();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800285 int countX = iconLayout.getCountX();
286 int countY = iconLayout.getCountY();
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800287 final int iconIndex = findIndexOfView(parent, v);
288
289 CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0);
290 ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets();
291 int[][] matrix;
292
Hyunyoung Song31178b82015-02-24 14:12:51 -0800293 // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800294 // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended
295 // with the hotseat.
296 if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN &&
297 orientation == Configuration.ORIENTATION_PORTRAIT) {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800298 matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation,
299 hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800300 countY = countY + 1;
Hyunyoung Song31178b82015-02-24 14:12:51 -0800301 } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800302 orientation == Configuration.ORIENTATION_LANDSCAPE) {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800303 matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation,
304 hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */);
305 countX = countX + 1;
306 } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
307 workspace.removeWorkspaceItem(v);
308 return consume;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800309 } else {
Hyunyoung Song31178b82015-02-24 14:12:51 -0800310 matrix = FocusLogic.createSparseMatrix(iconLayout);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800311 }
312
313 // Process the focus.
314 int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix,
315 iconIndex, pageIndex, pageCount);
316 View newIcon = null;
317 switch (newIconIndex) {
318 case FocusLogic.NOOP:
319 if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
320 newIcon = tabs;
321 }
322 break;
Hyunyoung Song38531712015-03-03 19:25:16 -0800323 case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
324 int row = FocusLogic.findRow(matrix, iconIndex);
325 parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
326 if (parent != null) {
327 iconLayout = (CellLayout) parent.getParent();
Hyunyoung Songac721f82015-03-04 16:33:56 -0800328 matrix = FocusLogic.createSparseMatrix(iconLayout,
Hyunyoung Song38531712015-03-03 19:25:16 -0800329 iconLayout.getCountX(), row);
330 newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix,
331 FocusLogic.PIVOT, pageIndex - 1, pageCount);
332 newIcon = parent.getChildAt(newIconIndex);
333 }
334 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800335 case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
336 parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
337 newIcon = parent.getChildAt(0);
338 workspace.snapToPage(pageIndex - 1);
Hyunyoung Song38531712015-03-03 19:25:16 -0800339 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800340 case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
341 parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
342 newIcon = parent.getChildAt(parent.getChildCount() - 1);
343 workspace.snapToPage(pageIndex - 1);
344 break;
345 case FocusLogic.NEXT_PAGE_FIRST_ITEM:
346 parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
347 newIcon = parent.getChildAt(0);
Hyunyoung Song31178b82015-02-24 14:12:51 -0800348 workspace.snapToPage(pageIndex + 1);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800349 break;
Hyunyoung Song38531712015-03-03 19:25:16 -0800350 case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
351 row = FocusLogic.findRow(matrix, iconIndex);
352 parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
353 if (parent != null) {
354 iconLayout = (CellLayout) parent.getParent();
Hyunyoung Songac721f82015-03-04 16:33:56 -0800355 matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row);
Hyunyoung Song38531712015-03-03 19:25:16 -0800356 newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix,
357 FocusLogic.PIVOT, pageIndex, pageCount);
358 newIcon = parent.getChildAt(newIconIndex);
359 }
360 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800361 case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
362 newIcon = parent.getChildAt(0);
363 break;
364 case FocusLogic.CURRENT_PAGE_LAST_ITEM:
365 newIcon = parent.getChildAt(parent.getChildCount() - 1);
366 break;
367 default:
368 // current page, some item.
369 if (0 <= newIconIndex && newIconIndex < parent.getChildCount()) {
370 newIcon = parent.getChildAt(newIconIndex);
371 } else if (parent.getChildCount() <= newIconIndex &&
372 newIconIndex < parent.getChildCount() + hotseatParent.getChildCount()) {
373 newIcon = hotseatParent.getChildAt(newIconIndex - parent.getChildCount());
374 }
375 break;
376 }
377 if (newIcon != null) {
378 newIcon.requestFocus();
379 playSoundEffect(keyCode, v);
380 }
381 return consume;
382 }
383
384 /**
385 * Handles key events for items in a Folder.
386 */
387 static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
388 boolean consume = FocusLogic.shouldConsume(keyCode);
389 if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
390 return consume;
391 }
392 if (DEBUG) {
393 Log.v(TAG, String.format("Handle FOLDER keyevent=[%s].",
394 KeyEvent.keyCodeToString(keyCode)));
395 }
396
397 // Initialize the variables.
398 ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
399 final CellLayout layout = (CellLayout) parent.getParent();
Sunny Goyalc3a609f2015-02-26 17:43:50 -0800400 final Folder folder = (Folder) layout.getParent().getParent();
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800401 View title = folder.mFolderName;
402 Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
403 final int countX = layout.getCountX();
404 final int countY = layout.getCountY();
405 final int iconIndex = findIndexOfView(parent, v);
406 int pageIndex = workspace.indexOfChild(layout);
407 int pageCount = workspace.getChildCount();
Hyunyoung Song31178b82015-02-24 14:12:51 -0800408 int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order */);
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800409
410 // Process the focus.
411 int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, map, iconIndex,
412 pageIndex, pageCount);
413 View newIcon = null;
414 switch (newIconIndex) {
415 case FocusLogic.NOOP:
416 if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
417 newIcon = title;
418 }
419 break;
420 case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
421 case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
422 case FocusLogic.NEXT_PAGE_FIRST_ITEM:
423 case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
424 case FocusLogic.CURRENT_PAGE_LAST_ITEM:
425 if (DEBUG) {
426 Log.v(TAG, "Page advance handling not supported on folder icons.");
427 }
428 break;
429 default: // current page some item.
430 newIcon = parent.getChildAt(newIconIndex);
431 break;
432 }
433 if (newIcon != null) {
434 newIcon.requestFocus();
435 playSoundEffect(keyCode, v);
436 }
437 return consume;
438 }
439
440 //
441 // Helper methods.
442 //
443
Winson Chung97d85d22011-04-13 11:27:36 -0700444 /**
Adam Cohenae4f1552011-10-20 00:15:42 -0700445 * Returns the Viewgroup containing page contents for the page at the index specified.
446 */
447 private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
448 ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index);
Winson Chungc58497e2013-09-03 17:48:37 -0700449 if (page instanceof CellLayout) {
Adam Cohenae4f1552011-10-20 00:15:42 -0700450 // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
Winson Chungc58497e2013-09-03 17:48:37 -0700451 page = ((CellLayout) page).getShortcutsAndWidgets();
Adam Cohenae4f1552011-10-20 00:15:42 -0700452 }
453 return page;
454 }
455
456 /**
Winson Chung97d85d22011-04-13 11:27:36 -0700457 * Private helper method to get the CellLayoutChildren given a CellLayout index.
458 */
Michael Jurkaa52570f2012-03-20 03:18:20 -0700459 private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
460 ViewGroup container, int i) {
Sunny Goyalb3726d92014-08-20 16:58:17 -0700461 CellLayout parent = (CellLayout) container.getChildAt(i);
462 return parent.getShortcutsAndWidgets();
Winson Chung97d85d22011-04-13 11:27:36 -0700463 }
464
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800465 private static int findIndexOfView(ViewGroup parent, View v) {
466 for (int i = 0; i < parent.getChildCount(); i++) {
467 if (v != null && v.equals(parent.getChildAt(i))) {
468 return i;
Winson Chung97d85d22011-04-13 11:27:36 -0700469 }
470 }
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800471 return -1;
Winson Chung97d85d22011-04-13 11:27:36 -0700472 }
473
474 /**
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800475 * Helper method to be used for playing sound effects.
Winson Chung97d85d22011-04-13 11:27:36 -0700476 */
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800477 private static void playSoundEffect(int keyCode, View v) {
Winson Chung97d85d22011-04-13 11:27:36 -0700478 switch (keyCode) {
479 case KeyEvent.KEYCODE_DPAD_LEFT:
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800480 v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
Winson Chung97d85d22011-04-13 11:27:36 -0700481 break;
482 case KeyEvent.KEYCODE_DPAD_RIGHT:
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800483 v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
Winson Chung97d85d22011-04-13 11:27:36 -0700484 break;
485 case KeyEvent.KEYCODE_DPAD_DOWN:
Winson Chung97d85d22011-04-13 11:27:36 -0700486 case KeyEvent.KEYCODE_PAGE_DOWN:
Winson Chung97d85d22011-04-13 11:27:36 -0700487 case KeyEvent.KEYCODE_MOVE_END:
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800488 v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
Adam Cohenac56cff2011-09-28 20:45:37 -0700489 break;
490 case KeyEvent.KEYCODE_DPAD_UP:
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800491 case KeyEvent.KEYCODE_PAGE_UP:
Adam Cohenac56cff2011-09-28 20:45:37 -0700492 case KeyEvent.KEYCODE_MOVE_HOME:
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800493 v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
Adam Cohenac56cff2011-09-28 20:45:37 -0700494 break;
Hyunyoung Songee3e6a72015-02-20 14:25:27 -0800495 default:
Winson Chung97d85d22011-04-13 11:27:36 -0700496 break;
Winson Chung97d85d22011-04-13 11:27:36 -0700497 }
Winson Chung97d85d22011-04-13 11:27:36 -0700498 }
499}