blob: c9bd58cd05ec1cbeebd3cea716f304a5461bfbc0 [file] [log] [blame]
Winson Chung97d85d22011-04-13 11:27:36 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
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
17package com.android.launcher2;
18
19import java.util.ArrayList;
20import java.util.Collections;
21import java.util.Comparator;
22
23import android.view.KeyEvent;
24import android.view.View;
25import android.view.ViewGroup;
26import android.view.ViewParent;
27import android.widget.TabHost;
28import android.widget.TabWidget;
29
30import com.android.launcher.R;
31
32/**
33 * A keyboard listener we set on all the button bar buttons.
34 */
35class ButtonBarKeyEventListener implements View.OnKeyListener {
36 @Override
37 public boolean onKey(View v, int keyCode, KeyEvent event) {
38 return FocusHelper.handleButtonBarButtonKeyEvent(v, keyCode, event);
39 }
40}
41
42/**
43 * A keyboard listener we set on the last tab button in AllApps to jump to then
44 * market icon and vice versa.
45 */
46class AllAppsTabKeyEventListener implements View.OnKeyListener {
47 @Override
48 public boolean onKey(View v, int keyCode, KeyEvent event) {
49 return FocusHelper.handleAllAppsTabKeyEvent(v, keyCode, event);
50 }
51}
52
53public class FocusHelper {
54 /**
55 * Private helper to get the parent TabHost in the view hiearchy.
56 */
57 private static TabHost findTabHostParent(View v) {
58 ViewParent p = v.getParent();
59 while (p != null && !(p instanceof TabHost)) {
60 p = p.getParent();
61 }
62 return (TabHost) p;
63 }
64
65 /**
66 * Handles key events in a AllApps tab between the last tab view and the shop button.
67 */
68 static boolean handleAllAppsTabKeyEvent(View v, int keyCode, KeyEvent e) {
69 final TabHost tabHost = findTabHostParent(v);
70 final ViewGroup contents = (ViewGroup)
71 tabHost.findViewById(com.android.internal.R.id.tabcontent);
72 final View shop = tabHost.findViewById(R.id.market_button);
73
74 final int action = e.getAction();
75 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
76 boolean wasHandled = false;
77 switch (keyCode) {
78 case KeyEvent.KEYCODE_DPAD_RIGHT:
79 if (handleKeyEvent) {
80 // Select the shop button if we aren't on it
81 if (v != shop) {
82 shop.requestFocus();
83 }
84 }
85 wasHandled = true;
86 break;
87 case KeyEvent.KEYCODE_DPAD_DOWN:
88 if (handleKeyEvent) {
89 // Select the content view (down is handled by the tab key handler otherwise)
90 if (v == shop) {
91 contents.requestFocus();
92 wasHandled = true;
93 }
94 }
95 break;
96 default: break;
97 }
98 return wasHandled;
99 }
100
101 /**
102 * Private helper to determine whether a view is visible.
103 */
104 private static boolean isVisible(View v) {
105 return v.getVisibility() == View.VISIBLE;
106 }
107
108 /**
109 * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
110 */
111 static boolean handlePagedViewWidgetKeyEvent(PagedViewWidget w, int keyCode, KeyEvent e) {
112 if (!LauncherApplication.isScreenXLarge()) return false;
113
114 final PagedViewExtendedLayout parent = (PagedViewExtendedLayout) w.getParent();
115 final ViewGroup container = (ViewGroup) parent.getParent();
116 final TabHost tabHost = findTabHostParent(container);
117 final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
118 final int widgetIndex = parent.indexOfChild(w);
119 final int widgetCount = parent.getChildCount();
120 final int pageIndex = container.indexOfChild(parent);
121 final int pageCount = container.getChildCount();
122
123 final int action = e.getAction();
124 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
125 PagedViewExtendedLayout newParent = null;
126 boolean wasHandled = false;
127 switch (keyCode) {
128 case KeyEvent.KEYCODE_DPAD_LEFT:
129 if (handleKeyEvent) {
130 // Select the previous widget or the last widget on the previous page
131 if (widgetIndex > 0) {
132 parent.getChildAt(widgetIndex - 1).requestFocus();
133 } else {
134 if (pageIndex > 0) {
135 newParent = (PagedViewExtendedLayout)
136 container.getChildAt(pageIndex - 1);
137 newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
138 }
139 }
140 }
141 wasHandled = true;
142 break;
143 case KeyEvent.KEYCODE_DPAD_RIGHT:
144 if (handleKeyEvent) {
145 // Select the next widget or the first widget on the next page
146 if (widgetIndex < (widgetCount - 1)) {
147 parent.getChildAt(widgetIndex + 1).requestFocus();
148 } else {
149 if (pageIndex < (pageCount - 1)) {
150 newParent = (PagedViewExtendedLayout)
151 container.getChildAt(pageIndex + 1);
152 newParent.getChildAt(0).requestFocus();
153 }
154 }
155 }
156 wasHandled = true;
157 break;
158 case KeyEvent.KEYCODE_DPAD_UP:
159 if (handleKeyEvent) {
160 // Select widgets tab on the tab bar
161 tabs.requestFocus();
162 }
163 wasHandled = true;
164 break;
165 case KeyEvent.KEYCODE_DPAD_DOWN:
166 if (handleKeyEvent) {
167 // TODO: Should focus the global search bar
168 }
169 wasHandled = true;
170 break;
171 case KeyEvent.KEYCODE_ENTER:
172 case KeyEvent.KEYCODE_DPAD_CENTER:
173 if (handleKeyEvent) {
174 // Simulate a click on the widget
175 View.OnClickListener clickListener = (View.OnClickListener) container;
176 clickListener.onClick(w);
177 }
178 wasHandled = true;
179 break;
180 case KeyEvent.KEYCODE_PAGE_UP:
181 if (handleKeyEvent) {
182 // Select the first item on the previous page, or the first item on this page
183 // if there is no previous page
184 if (pageIndex > 0) {
185 newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex - 1);
186 newParent.getChildAt(0).requestFocus();
187 } else {
188 parent.getChildAt(0).requestFocus();
189 }
190 }
191 wasHandled = true;
192 break;
193 case KeyEvent.KEYCODE_PAGE_DOWN:
194 if (handleKeyEvent) {
195 // Select the first item on the next page, or the last item on this page
196 // if there is no next page
197 if (pageIndex < (pageCount - 1)) {
198 newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex + 1);
199 newParent.getChildAt(0).requestFocus();
200 } else {
201 parent.getChildAt(widgetCount - 1).requestFocus();
202 }
203 }
204 wasHandled = true;
205 break;
206 case KeyEvent.KEYCODE_MOVE_HOME:
207 if (handleKeyEvent) {
208 // Select the first item on this page
209 parent.getChildAt(0).requestFocus();
210 }
211 wasHandled = true;
212 break;
213 case KeyEvent.KEYCODE_MOVE_END:
214 if (handleKeyEvent) {
215 // Select the last item on this page
216 parent.getChildAt(widgetCount - 1).requestFocus();
217 }
218 wasHandled = true;
219 break;
220 default: break;
221 }
222 return wasHandled;
223 }
224
225 /**
226 * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout
227 * index.
228 */
229 private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex(
230 ViewGroup container, int i) {
231 ViewGroup parent = (ViewGroup) container.getChildAt(i);
232 return (PagedViewCellLayoutChildren) parent.getChildAt(0);
233 }
234
235 /**
236 * Handles key events in a PageViewCellLayout containing PagedViewIcons.
237 */
238 static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) {
239 if (!LauncherApplication.isScreenXLarge()) return false;
240
241 final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent();
242 final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent();
243 // Note we have an extra parent because of the
244 // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
245 final ViewGroup container = (ViewGroup) parentLayout.getParent();
246 final TabHost tabHost = findTabHostParent(container);
247 final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
248 final int widgetIndex = parent.indexOfChild(v);
249 final int widgetCount = parent.getChildCount();
250 final int pageIndex = container.indexOfChild(parentLayout);
251 final int pageCount = container.getChildCount();
252 final int cellCountX = parentLayout.getCellCountX();
253 final int cellCountY = parentLayout.getCellCountY();
254 final int x = widgetIndex % cellCountX;
255 final int y = widgetIndex / cellCountX;
256
257 final int action = e.getAction();
258 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
259 PagedViewCellLayoutChildren newParent = null;
260 boolean wasHandled = false;
261 switch (keyCode) {
262 case KeyEvent.KEYCODE_DPAD_LEFT:
263 if (handleKeyEvent) {
264 // Select the previous icon or the last icon on the previous page
265 if (widgetIndex > 0) {
266 parent.getChildAt(widgetIndex - 1).requestFocus();
267 } else {
268 if (pageIndex > 0) {
269 newParent = getPagedViewCellLayoutChildrenForIndex(container,
270 pageIndex - 1);
271 newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
272 }
273 }
274 }
275 wasHandled = true;
276 break;
277 case KeyEvent.KEYCODE_DPAD_RIGHT:
278 if (handleKeyEvent) {
279 // Select the next icon or the first icon on the next page
280 if (widgetIndex < (widgetCount - 1)) {
281 parent.getChildAt(widgetIndex + 1).requestFocus();
282 } else {
283 if (pageIndex < (pageCount - 1)) {
284 newParent = getPagedViewCellLayoutChildrenForIndex(container,
285 pageIndex + 1);
286 newParent.getChildAt(0).requestFocus();
287 }
288 }
289 }
290 wasHandled = true;
291 break;
292 case KeyEvent.KEYCODE_DPAD_UP:
293 if (handleKeyEvent) {
294 // Select the closest icon in the previous row, otherwise select the tab bar
295 if (y > 0) {
296 int newWidgetIndex = ((y - 1) * cellCountX) + x;
297 parent.getChildAt(newWidgetIndex).requestFocus();
298 } else {
299 tabs.requestFocus();
300 }
301 }
302 wasHandled = true;
303 break;
304 case KeyEvent.KEYCODE_DPAD_DOWN:
305 if (handleKeyEvent) {
306 // Select the closest icon in the previous row, otherwise do nothing
307 if (y < (cellCountY - 1)) {
308 int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
309 parent.getChildAt(newWidgetIndex).requestFocus();
310 }
311 }
312 wasHandled = true;
313 break;
314 case KeyEvent.KEYCODE_ENTER:
315 case KeyEvent.KEYCODE_DPAD_CENTER:
316 if (handleKeyEvent) {
317 // Simulate a click on the icon
318 View.OnClickListener clickListener = (View.OnClickListener) container;
319 clickListener.onClick(v);
320 }
321 wasHandled = true;
322 break;
323 case KeyEvent.KEYCODE_PAGE_UP:
324 if (handleKeyEvent) {
325 // Select the first icon on the previous page, or the first icon on this page
326 // if there is no previous page
327 if (pageIndex > 0) {
328 newParent = getPagedViewCellLayoutChildrenForIndex(container,
329 pageIndex - 1);
330 newParent.getChildAt(0).requestFocus();
331 } else {
332 parent.getChildAt(0).requestFocus();
333 }
334 }
335 wasHandled = true;
336 break;
337 case KeyEvent.KEYCODE_PAGE_DOWN:
338 if (handleKeyEvent) {
339 // Select the first icon on the next page, or the last icon on this page
340 // if there is no next page
341 if (pageIndex < (pageCount - 1)) {
342 newParent = getPagedViewCellLayoutChildrenForIndex(container,
343 pageIndex + 1);
344 newParent.getChildAt(0).requestFocus();
345 } else {
346 parent.getChildAt(widgetCount - 1).requestFocus();
347 }
348 }
349 wasHandled = true;
350 break;
351 case KeyEvent.KEYCODE_MOVE_HOME:
352 if (handleKeyEvent) {
353 // Select the first icon on this page
354 parent.getChildAt(0).requestFocus();
355 }
356 wasHandled = true;
357 break;
358 case KeyEvent.KEYCODE_MOVE_END:
359 if (handleKeyEvent) {
360 // Select the last icon on this page
361 parent.getChildAt(widgetCount - 1).requestFocus();
362 }
363 wasHandled = true;
364 break;
365 default: break;
366 }
367 return wasHandled;
368 }
369
370 /**
371 * Handles key events in the tab widget.
372 */
373 static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
374 if (!LauncherApplication.isScreenXLarge()) return false;
375
376 final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
377 final TabHost tabHost = findTabHostParent(parent);
378 final ViewGroup contents = (ViewGroup)
379 tabHost.findViewById(com.android.internal.R.id.tabcontent);
380 final int tabCount = parent.getTabCount();
381 final int tabIndex = parent.getChildTabIndex(v);
382
383 final int action = e.getAction();
384 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
385 boolean wasHandled = false;
386 switch (keyCode) {
387 case KeyEvent.KEYCODE_DPAD_LEFT:
388 if (handleKeyEvent) {
389 // Select the previous tab
390 if (tabIndex > 0) {
391 parent.getChildTabViewAt(tabIndex - 1).requestFocus();
392 }
393 }
394 wasHandled = true;
395 break;
396 case KeyEvent.KEYCODE_DPAD_RIGHT:
397 if (handleKeyEvent) {
398 // Select the next tab, or if the last tab has a focus right id, select that
399 if (tabIndex < (tabCount - 1)) {
400 parent.getChildTabViewAt(tabIndex + 1).requestFocus();
401 } else {
402 if (v.getNextFocusRightId() != View.NO_ID) {
403 tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
404 }
405 }
406 }
407 wasHandled = true;
408 break;
409 case KeyEvent.KEYCODE_DPAD_UP:
410 // Do nothing
411 wasHandled = true;
412 break;
413 case KeyEvent.KEYCODE_DPAD_DOWN:
414 if (handleKeyEvent) {
415 // Select the content view
416 contents.requestFocus();
417 }
418 wasHandled = true;
419 break;
420 default: break;
421 }
422 return wasHandled;
423 }
424
425 /**
426 * Handles key events in a the workspace button bar.
427 */
428 static boolean handleButtonBarButtonKeyEvent(View v, int keyCode, KeyEvent e) {
429 if (!LauncherApplication.isScreenXLarge()) return false;
430
431 final ViewGroup parent = (ViewGroup) v.getParent();
432 final ViewGroup launcher = (ViewGroup) parent.getParent();
433 final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
434 final int buttonIndex = parent.indexOfChild(v);
435 final int buttonCount = parent.getChildCount();
436 final int pageIndex = workspace.getCurrentPage();
437 final int pageCount = workspace.getChildCount();
438 final int firstButtonIndex = parent.indexOfChild(parent.findViewById(R.id.search_button));
439 final int lastButtonIndex = parent.indexOfChild(parent.findViewById(R.id.configure_button));
440
441 final int action = e.getAction();
442 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
443 boolean wasHandled = false;
444 switch (keyCode) {
445 case KeyEvent.KEYCODE_DPAD_LEFT:
446 if (handleKeyEvent) {
447 // Select the previous button, otherwise do nothing (since the button bar is
448 // static)
449 if (buttonIndex > firstButtonIndex) {
450 int newButtonIndex = buttonIndex - 1;
451 while (newButtonIndex >= firstButtonIndex) {
452 View prev = parent.getChildAt(newButtonIndex);
453 if (isVisible(prev) && prev.isFocusable()) {
454 prev.requestFocus();
455 break;
456 }
457 --newButtonIndex;
458 }
459 } else {
460 if (pageIndex > 0) {
461 // Snap to previous page and clear focus
462 workspace.snapToPage(pageIndex - 1);
463 }
464 }
465 }
466 wasHandled = true;
467 break;
468 case KeyEvent.KEYCODE_DPAD_RIGHT:
469 if (handleKeyEvent) {
470 // Select the next button, otherwise do nothing (since the button bar is
471 // static)
472 if (buttonIndex < lastButtonIndex) {
473 int newButtonIndex = buttonIndex + 1;
474 while (newButtonIndex <= lastButtonIndex) {
475 View next = parent.getChildAt(newButtonIndex);
476 if (isVisible(next) && next.isFocusable()) {
477 next.requestFocus();
478 break;
479 }
480 ++newButtonIndex;
481 }
482 } else {
483 if (pageIndex < (pageCount - 1)) {
484 // Snap to next page and clear focus
485 workspace.snapToPage(pageIndex + 1);
486 }
487 }
488 }
489 wasHandled = true;
490 break;
491 case KeyEvent.KEYCODE_DPAD_UP:
492 // Do nothing
493 wasHandled = true;
494 break;
495 case KeyEvent.KEYCODE_DPAD_DOWN:
496 if (handleKeyEvent) {
497 // Select the first bubble text view in the current page of the workspace
498 final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
499 final CellLayoutChildren children = layout.getChildrenLayout();
500 final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
501 if (newIcon != null) {
502 newIcon.requestFocus();
503 } else {
504 workspace.requestFocus();
505 }
506 }
507 wasHandled = true;
508 break;
509 default: break;
510 }
511 return wasHandled;
512 }
513
514 /**
515 * Private helper method to get the CellLayoutChildren given a CellLayout index.
516 */
517 private static CellLayoutChildren getCellLayoutChildrenForIndex(ViewGroup container, int i) {
518 ViewGroup parent = (ViewGroup) container.getChildAt(i);
519 return (CellLayoutChildren) parent.getChildAt(0);
520 }
521
522 /**
523 * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
524 * from top left to bottom right.
525 */
526 private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
527 ViewGroup parent) {
528 // First we order each the CellLayout children by their x,y coordinates
529 final int cellCountX = layout.getCountX();
530 final int count = parent.getChildCount();
531 ArrayList<View> views = new ArrayList<View>();
532 for (int j = 0; j < count; ++j) {
533 views.add(parent.getChildAt(j));
534 }
535 Collections.sort(views, new Comparator<View>() {
536 @Override
537 public int compare(View lhs, View rhs) {
538 CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
539 CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
540 int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
541 int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
542 return lvIndex - rvIndex;
543 }
544 });
545 return views;
546 }
547 /**
548 * Private helper method to find the index of the next BubbleTextView in the delta direction.
549 * @param delta either -1 or 1 depending on the direction we want to search
550 */
551 private static View findIndexOfBubbleTextView(ArrayList<View> views, int i, int delta) {
552 // Then we find the next BubbleTextView offset by delta from i
553 final int count = views.size();
554 int newI = i + delta;
555 while (0 <= newI && newI < count) {
556 View newV = views.get(newI);
557 if (newV instanceof BubbleTextView) {
558 return newV;
559 }
560 newI += delta;
561 }
562 return null;
563 }
564 private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, int i,
565 int delta) {
566 final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
567 return findIndexOfBubbleTextView(views, i, delta);
568 }
569 private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, View v,
570 int delta) {
571 final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
572 return findIndexOfBubbleTextView(views, views.indexOf(v), delta);
573 }
574 /**
575 * Private helper method to find the next closest BubbleTextView in the delta direction on the
576 * next line.
577 * @param delta either -1 or 1 depending on the line and direction we want to search
578 */
579 private static View getClosestBubbleTextViewOnLine(CellLayout layout, ViewGroup parent, View v,
580 int lineDelta) {
581 final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
582 final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
583 final int cellCountX = layout.getCountX();
584 final int cellCountY = layout.getCountY();
585 final int row = lp.cellY;
586 final int newRow = row + lineDelta;
587 if (0 <= newRow && newRow < cellCountY) {
588 float closestDistance = Float.MAX_VALUE;
589 int closestIndex = -1;
590 int index = views.indexOf(v);
591 int endIndex = (lineDelta < 0) ? -1 : views.size();
592 while (index != endIndex) {
593 View newV = views.get(index);
594 CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
595 boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
596 if (satisfiesRow && newV instanceof BubbleTextView) {
597 float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
598 Math.pow(tmpLp.cellY - lp.cellY, 2));
599 if (tmpDistance < closestDistance) {
600 closestIndex = index;
601 closestDistance = tmpDistance;
602 }
603 }
604 if (index <= endIndex) {
605 ++index;
606 } else {
607 --index;
608 }
609 }
610 if (closestIndex > -1) {
611 return views.get(closestIndex);
612 }
613 }
614 return null;
615 }
616
617 /**
618 * Handles key events in a Workspace containing BubbleTextView.
619 */
620 static boolean handleBubbleTextViewKeyEvent(BubbleTextView v, int keyCode, KeyEvent e) {
621 if (!LauncherApplication.isScreenXLarge()) return false;
622
623 CellLayoutChildren parent = (CellLayoutChildren) v.getParent();
624 final CellLayout layout = (CellLayout) parent.getParent();
625 final Workspace workspace = (Workspace) layout.getParent();
626 final ViewGroup launcher = (ViewGroup) workspace.getParent();
627 final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster);
628 int iconIndex = parent.indexOfChild(v);
629 int iconCount = parent.getChildCount();
630 int pageIndex = workspace.indexOfChild(layout);
631 int pageCount = workspace.getChildCount();
632
633 final int action = e.getAction();
634 final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
635 boolean wasHandled = false;
636 switch (keyCode) {
637 case KeyEvent.KEYCODE_DPAD_LEFT:
638 if (handleKeyEvent) {
639 // Select the previous icon or the last icon on the previous page if possible
640 View newIcon = getBubbleTextViewInDirection(layout, parent, v, -1);
641 if (newIcon != null) {
642 newIcon.requestFocus();
643 } else {
644 if (pageIndex > 0) {
645 parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
646 newIcon = getBubbleTextViewInDirection(layout, parent,
647 parent.getChildCount(), -1);
648 if (newIcon != null) {
649 newIcon.requestFocus();
650 } else {
651 // Snap to the previous page
652 workspace.snapToPage(pageIndex - 1);
653 }
654 }
655 }
656 }
657 wasHandled = true;
658 break;
659 case KeyEvent.KEYCODE_DPAD_RIGHT:
660 if (handleKeyEvent) {
661 // Select the next icon or the first icon on the next page if possible
662 View newIcon = getBubbleTextViewInDirection(layout, parent, v, 1);
663 if (newIcon != null) {
664 newIcon.requestFocus();
665 } else {
666 if (pageIndex < (pageCount - 1)) {
667 parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
668 newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
669 if (newIcon != null) {
670 newIcon.requestFocus();
671 } else {
672 // Snap to the next page
673 workspace.snapToPage(pageIndex + 1);
674 }
675 }
676 }
677 }
678 wasHandled = true;
679 break;
680 case KeyEvent.KEYCODE_DPAD_UP:
681 if (handleKeyEvent) {
682 // Select the closest icon in the previous line, otherwise select the tab bar
683 View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, -1);
684 if (newIcon != null) {
685 newIcon.requestFocus();
686 wasHandled = true;
687 } else {
688 tabs.requestFocus();
689 }
690 }
691 break;
692 case KeyEvent.KEYCODE_DPAD_DOWN:
693 if (handleKeyEvent) {
694 // Select the closest icon in the next line, otherwise select the tab bar
695 View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, 1);
696 if (newIcon != null) {
697 newIcon.requestFocus();
698 wasHandled = true;
699 }
700 }
701 break;
702 case KeyEvent.KEYCODE_PAGE_UP:
703 if (handleKeyEvent) {
704 // Select the first icon on the previous page or the first icon on this page
705 // if there is no previous page
706 if (pageIndex > 0) {
707 parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
708 View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
709 if (newIcon != null) {
710 newIcon.requestFocus();
711 } else {
712 // Snap to the previous page
713 workspace.snapToPage(pageIndex - 1);
714 }
715 } else {
716 View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
717 if (newIcon != null) {
718 newIcon.requestFocus();
719 }
720 }
721 }
722 wasHandled = true;
723 break;
724 case KeyEvent.KEYCODE_PAGE_DOWN:
725 if (handleKeyEvent) {
726 // Select the first icon on the next page or the last icon on this page
727 // if there is no previous page
728 if (pageIndex < (pageCount - 1)) {
729 parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
730 View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
731 if (newIcon != null) {
732 newIcon.requestFocus();
733 } else {
734 // Snap to the next page
735 workspace.snapToPage(pageIndex + 1);
736 }
737 } else {
738 View newIcon = getBubbleTextViewInDirection(layout, parent,
739 parent.getChildCount(), -1);
740 if (newIcon != null) {
741 newIcon.requestFocus();
742 }
743 }
744 }
745 wasHandled = true;
746 break;
747 case KeyEvent.KEYCODE_MOVE_HOME:
748 if (handleKeyEvent) {
749 // Select the first icon on this page
750 View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
751 if (newIcon != null) {
752 newIcon.requestFocus();
753 }
754 }
755 wasHandled = true;
756 break;
757 case KeyEvent.KEYCODE_MOVE_END:
758 if (handleKeyEvent) {
759 // Select the last icon on this page
760 View newIcon = getBubbleTextViewInDirection(layout, parent,
761 parent.getChildCount(), -1);
762 if (newIcon != null) {
763 newIcon.requestFocus();
764 }
765 }
766 wasHandled = true;
767 break;
768 default: break;
769 }
770 return wasHandled;
771 }
772}