diff options
author | Winson Chung <winsonc@google.com> | 2011-04-13 11:27:36 -0700 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2011-04-14 10:13:09 -0700 |
commit | 97d85d23b013347bead4e2f5fa430a79ce69431e (patch) | |
tree | 4e72157c6814cb5c517b09ea14fd4474acb9c7c9 /src/com/android/launcher2/FocusHelper.java | |
parent | 721a06bb6564a4ebe6dc6bf364cb569d255705ac (diff) | |
download | android_packages_apps_Trebuchet-97d85d23b013347bead4e2f5fa430a79ce69431e.tar.gz android_packages_apps_Trebuchet-97d85d23b013347bead4e2f5fa430a79ce69431e.tar.bz2 android_packages_apps_Trebuchet-97d85d23b013347bead4e2f5fa430a79ce69431e.zip |
Fixing focus issues in Launcher (keyboard support).
Change-Id: Ieafd713393daf5628f229a66441bd3ed293245da
Diffstat (limited to 'src/com/android/launcher2/FocusHelper.java')
-rw-r--r-- | src/com/android/launcher2/FocusHelper.java | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java new file mode 100644 index 000000000..c9bd58cd0 --- /dev/null +++ b/src/com/android/launcher2/FocusHelper.java @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.TabHost; +import android.widget.TabWidget; + +import com.android.launcher.R; + +/** + * A keyboard listener we set on all the button bar buttons. + */ +class ButtonBarKeyEventListener implements View.OnKeyListener { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + return FocusHelper.handleButtonBarButtonKeyEvent(v, keyCode, event); + } +} + +/** + * A keyboard listener we set on the last tab button in AllApps to jump to then + * market icon and vice versa. + */ +class AllAppsTabKeyEventListener implements View.OnKeyListener { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + return FocusHelper.handleAllAppsTabKeyEvent(v, keyCode, event); + } +} + +public class FocusHelper { + /** + * Private helper to get the parent TabHost in the view hiearchy. + */ + private static TabHost findTabHostParent(View v) { + ViewParent p = v.getParent(); + while (p != null && !(p instanceof TabHost)) { + p = p.getParent(); + } + return (TabHost) p; + } + + /** + * Handles key events in a AllApps tab between the last tab view and the shop button. + */ + static boolean handleAllAppsTabKeyEvent(View v, int keyCode, KeyEvent e) { + final TabHost tabHost = findTabHostParent(v); + final ViewGroup contents = (ViewGroup) + tabHost.findViewById(com.android.internal.R.id.tabcontent); + final View shop = tabHost.findViewById(R.id.market_button); + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the shop button if we aren't on it + if (v != shop) { + shop.requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // Select the content view (down is handled by the tab key handler otherwise) + if (v == shop) { + contents.requestFocus(); + wasHandled = true; + } + } + break; + default: break; + } + return wasHandled; + } + + /** + * Private helper to determine whether a view is visible. + */ + private static boolean isVisible(View v) { + return v.getVisibility() == View.VISIBLE; + } + + /** + * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets. + */ + static boolean handlePagedViewWidgetKeyEvent(PagedViewWidget w, int keyCode, KeyEvent e) { + if (!LauncherApplication.isScreenXLarge()) return false; + + final PagedViewExtendedLayout parent = (PagedViewExtendedLayout) w.getParent(); + final ViewGroup container = (ViewGroup) parent.getParent(); + final TabHost tabHost = findTabHostParent(container); + final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs); + final int widgetIndex = parent.indexOfChild(w); + final int widgetCount = parent.getChildCount(); + final int pageIndex = container.indexOfChild(parent); + final int pageCount = container.getChildCount(); + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + PagedViewExtendedLayout newParent = null; + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (handleKeyEvent) { + // Select the previous widget or the last widget on the previous page + if (widgetIndex > 0) { + parent.getChildAt(widgetIndex - 1).requestFocus(); + } else { + if (pageIndex > 0) { + newParent = (PagedViewExtendedLayout) + container.getChildAt(pageIndex - 1); + newParent.getChildAt(newParent.getChildCount() - 1).requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the next widget or the first widget on the next page + if (widgetIndex < (widgetCount - 1)) { + parent.getChildAt(widgetIndex + 1).requestFocus(); + } else { + if (pageIndex < (pageCount - 1)) { + newParent = (PagedViewExtendedLayout) + container.getChildAt(pageIndex + 1); + newParent.getChildAt(0).requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_UP: + if (handleKeyEvent) { + // Select widgets tab on the tab bar + tabs.requestFocus(); + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // TODO: Should focus the global search bar + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (handleKeyEvent) { + // Simulate a click on the widget + View.OnClickListener clickListener = (View.OnClickListener) container; + clickListener.onClick(w); + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_PAGE_UP: + if (handleKeyEvent) { + // Select the first item on the previous page, or the first item on this page + // if there is no previous page + if (pageIndex > 0) { + newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex - 1); + newParent.getChildAt(0).requestFocus(); + } else { + parent.getChildAt(0).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_PAGE_DOWN: + if (handleKeyEvent) { + // Select the first item on the next page, or the last item on this page + // if there is no next page + if (pageIndex < (pageCount - 1)) { + newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex + 1); + newParent.getChildAt(0).requestFocus(); + } else { + parent.getChildAt(widgetCount - 1).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_HOME: + if (handleKeyEvent) { + // Select the first item on this page + parent.getChildAt(0).requestFocus(); + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_END: + if (handleKeyEvent) { + // Select the last item on this page + parent.getChildAt(widgetCount - 1).requestFocus(); + } + wasHandled = true; + break; + default: break; + } + return wasHandled; + } + + /** + * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout + * index. + */ + private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex( + ViewGroup container, int i) { + ViewGroup parent = (ViewGroup) container.getChildAt(i); + return (PagedViewCellLayoutChildren) parent.getChildAt(0); + } + + /** + * Handles key events in a PageViewCellLayout containing PagedViewIcons. + */ + static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) { + if (!LauncherApplication.isScreenXLarge()) return false; + + final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent(); + final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent(); + // Note we have an extra parent because of the + // PagedViewCellLayout/PagedViewCellLayoutChildren relationship + final ViewGroup container = (ViewGroup) parentLayout.getParent(); + final TabHost tabHost = findTabHostParent(container); + final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs); + final int widgetIndex = parent.indexOfChild(v); + final int widgetCount = parent.getChildCount(); + final int pageIndex = container.indexOfChild(parentLayout); + final int pageCount = container.getChildCount(); + final int cellCountX = parentLayout.getCellCountX(); + final int cellCountY = parentLayout.getCellCountY(); + final int x = widgetIndex % cellCountX; + final int y = widgetIndex / cellCountX; + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + PagedViewCellLayoutChildren newParent = null; + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (handleKeyEvent) { + // Select the previous icon or the last icon on the previous page + if (widgetIndex > 0) { + parent.getChildAt(widgetIndex - 1).requestFocus(); + } else { + if (pageIndex > 0) { + newParent = getPagedViewCellLayoutChildrenForIndex(container, + pageIndex - 1); + newParent.getChildAt(newParent.getChildCount() - 1).requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the next icon or the first icon on the next page + if (widgetIndex < (widgetCount - 1)) { + parent.getChildAt(widgetIndex + 1).requestFocus(); + } else { + if (pageIndex < (pageCount - 1)) { + newParent = getPagedViewCellLayoutChildrenForIndex(container, + pageIndex + 1); + newParent.getChildAt(0).requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_UP: + if (handleKeyEvent) { + // Select the closest icon in the previous row, otherwise select the tab bar + if (y > 0) { + int newWidgetIndex = ((y - 1) * cellCountX) + x; + parent.getChildAt(newWidgetIndex).requestFocus(); + } else { + tabs.requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // Select the closest icon in the previous row, otherwise do nothing + if (y < (cellCountY - 1)) { + int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x); + parent.getChildAt(newWidgetIndex).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_ENTER: + case KeyEvent.KEYCODE_DPAD_CENTER: + if (handleKeyEvent) { + // Simulate a click on the icon + View.OnClickListener clickListener = (View.OnClickListener) container; + clickListener.onClick(v); + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_PAGE_UP: + if (handleKeyEvent) { + // Select the first icon on the previous page, or the first icon on this page + // if there is no previous page + if (pageIndex > 0) { + newParent = getPagedViewCellLayoutChildrenForIndex(container, + pageIndex - 1); + newParent.getChildAt(0).requestFocus(); + } else { + parent.getChildAt(0).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_PAGE_DOWN: + if (handleKeyEvent) { + // Select the first icon on the next page, or the last icon on this page + // if there is no next page + if (pageIndex < (pageCount - 1)) { + newParent = getPagedViewCellLayoutChildrenForIndex(container, + pageIndex + 1); + newParent.getChildAt(0).requestFocus(); + } else { + parent.getChildAt(widgetCount - 1).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_HOME: + if (handleKeyEvent) { + // Select the first icon on this page + parent.getChildAt(0).requestFocus(); + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_END: + if (handleKeyEvent) { + // Select the last icon on this page + parent.getChildAt(widgetCount - 1).requestFocus(); + } + wasHandled = true; + break; + default: break; + } + return wasHandled; + } + + /** + * Handles key events in the tab widget. + */ + static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) { + if (!LauncherApplication.isScreenXLarge()) return false; + + final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent(); + final TabHost tabHost = findTabHostParent(parent); + final ViewGroup contents = (ViewGroup) + tabHost.findViewById(com.android.internal.R.id.tabcontent); + final int tabCount = parent.getTabCount(); + final int tabIndex = parent.getChildTabIndex(v); + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (handleKeyEvent) { + // Select the previous tab + if (tabIndex > 0) { + parent.getChildTabViewAt(tabIndex - 1).requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the next tab, or if the last tab has a focus right id, select that + if (tabIndex < (tabCount - 1)) { + parent.getChildTabViewAt(tabIndex + 1).requestFocus(); + } else { + if (v.getNextFocusRightId() != View.NO_ID) { + tabHost.findViewById(v.getNextFocusRightId()).requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_UP: + // Do nothing + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // Select the content view + contents.requestFocus(); + } + wasHandled = true; + break; + default: break; + } + return wasHandled; + } + + /** + * Handles key events in a the workspace button bar. + */ + static boolean handleButtonBarButtonKeyEvent(View v, int keyCode, KeyEvent e) { + if (!LauncherApplication.isScreenXLarge()) return false; + + final ViewGroup parent = (ViewGroup) v.getParent(); + final ViewGroup launcher = (ViewGroup) parent.getParent(); + final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace); + final int buttonIndex = parent.indexOfChild(v); + final int buttonCount = parent.getChildCount(); + final int pageIndex = workspace.getCurrentPage(); + final int pageCount = workspace.getChildCount(); + final int firstButtonIndex = parent.indexOfChild(parent.findViewById(R.id.search_button)); + final int lastButtonIndex = parent.indexOfChild(parent.findViewById(R.id.configure_button)); + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (handleKeyEvent) { + // Select the previous button, otherwise do nothing (since the button bar is + // static) + if (buttonIndex > firstButtonIndex) { + int newButtonIndex = buttonIndex - 1; + while (newButtonIndex >= firstButtonIndex) { + View prev = parent.getChildAt(newButtonIndex); + if (isVisible(prev) && prev.isFocusable()) { + prev.requestFocus(); + break; + } + --newButtonIndex; + } + } else { + if (pageIndex > 0) { + // Snap to previous page and clear focus + workspace.snapToPage(pageIndex - 1); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the next button, otherwise do nothing (since the button bar is + // static) + if (buttonIndex < lastButtonIndex) { + int newButtonIndex = buttonIndex + 1; + while (newButtonIndex <= lastButtonIndex) { + View next = parent.getChildAt(newButtonIndex); + if (isVisible(next) && next.isFocusable()) { + next.requestFocus(); + break; + } + ++newButtonIndex; + } + } else { + if (pageIndex < (pageCount - 1)) { + // Snap to next page and clear focus + workspace.snapToPage(pageIndex + 1); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_UP: + // Do nothing + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // Select the first bubble text view in the current page of the workspace + final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex); + final CellLayoutChildren children = layout.getChildrenLayout(); + final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + workspace.requestFocus(); + } + } + wasHandled = true; + break; + default: break; + } + return wasHandled; + } + + /** + * Private helper method to get the CellLayoutChildren given a CellLayout index. + */ + private static CellLayoutChildren getCellLayoutChildrenForIndex(ViewGroup container, int i) { + ViewGroup parent = (ViewGroup) container.getChildAt(i); + return (CellLayoutChildren) parent.getChildAt(0); + } + + /** + * Private helper method to sort all the CellLayout children in order of their (x,y) spatially + * from top left to bottom right. + */ + private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout, + ViewGroup parent) { + // First we order each the CellLayout children by their x,y coordinates + final int cellCountX = layout.getCountX(); + final int count = parent.getChildCount(); + ArrayList<View> views = new ArrayList<View>(); + for (int j = 0; j < count; ++j) { + views.add(parent.getChildAt(j)); + } + Collections.sort(views, new Comparator<View>() { + @Override + public int compare(View lhs, View rhs) { + CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams(); + CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams(); + int lvIndex = (llp.cellY * cellCountX) + llp.cellX; + int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX; + return lvIndex - rvIndex; + } + }); + return views; + } + /** + * Private helper method to find the index of the next BubbleTextView in the delta direction. + * @param delta either -1 or 1 depending on the direction we want to search + */ + private static View findIndexOfBubbleTextView(ArrayList<View> views, int i, int delta) { + // Then we find the next BubbleTextView offset by delta from i + final int count = views.size(); + int newI = i + delta; + while (0 <= newI && newI < count) { + View newV = views.get(newI); + if (newV instanceof BubbleTextView) { + return newV; + } + newI += delta; + } + return null; + } + private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, int i, + int delta) { + final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent); + return findIndexOfBubbleTextView(views, i, delta); + } + private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, View v, + int delta) { + final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent); + return findIndexOfBubbleTextView(views, views.indexOf(v), delta); + } + /** + * Private helper method to find the next closest BubbleTextView in the delta direction on the + * next line. + * @param delta either -1 or 1 depending on the line and direction we want to search + */ + private static View getClosestBubbleTextViewOnLine(CellLayout layout, ViewGroup parent, View v, + int lineDelta) { + final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent); + final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams(); + final int cellCountX = layout.getCountX(); + final int cellCountY = layout.getCountY(); + final int row = lp.cellY; + final int newRow = row + lineDelta; + if (0 <= newRow && newRow < cellCountY) { + float closestDistance = Float.MAX_VALUE; + int closestIndex = -1; + int index = views.indexOf(v); + int endIndex = (lineDelta < 0) ? -1 : views.size(); + while (index != endIndex) { + View newV = views.get(index); + CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams(); + boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row); + if (satisfiesRow && newV instanceof BubbleTextView) { + float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) + + Math.pow(tmpLp.cellY - lp.cellY, 2)); + if (tmpDistance < closestDistance) { + closestIndex = index; + closestDistance = tmpDistance; + } + } + if (index <= endIndex) { + ++index; + } else { + --index; + } + } + if (closestIndex > -1) { + return views.get(closestIndex); + } + } + return null; + } + + /** + * Handles key events in a Workspace containing BubbleTextView. + */ + static boolean handleBubbleTextViewKeyEvent(BubbleTextView v, int keyCode, KeyEvent e) { + if (!LauncherApplication.isScreenXLarge()) return false; + + CellLayoutChildren parent = (CellLayoutChildren) v.getParent(); + final CellLayout layout = (CellLayout) parent.getParent(); + final Workspace workspace = (Workspace) layout.getParent(); + final ViewGroup launcher = (ViewGroup) workspace.getParent(); + final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster); + int iconIndex = parent.indexOfChild(v); + int iconCount = parent.getChildCount(); + int pageIndex = workspace.indexOfChild(layout); + int pageCount = workspace.getChildCount(); + + final int action = e.getAction(); + final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); + boolean wasHandled = false; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (handleKeyEvent) { + // Select the previous icon or the last icon on the previous page if possible + View newIcon = getBubbleTextViewInDirection(layout, parent, v, -1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + if (pageIndex > 0) { + parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + newIcon = getBubbleTextViewInDirection(layout, parent, + parent.getChildCount(), -1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + // Snap to the previous page + workspace.snapToPage(pageIndex - 1); + } + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (handleKeyEvent) { + // Select the next icon or the first icon on the next page if possible + View newIcon = getBubbleTextViewInDirection(layout, parent, v, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + if (pageIndex < (pageCount - 1)) { + parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + // Snap to the next page + workspace.snapToPage(pageIndex + 1); + } + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_DPAD_UP: + if (handleKeyEvent) { + // Select the closest icon in the previous line, otherwise select the tab bar + View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, -1); + if (newIcon != null) { + newIcon.requestFocus(); + wasHandled = true; + } else { + tabs.requestFocus(); + } + } + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (handleKeyEvent) { + // Select the closest icon in the next line, otherwise select the tab bar + View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, 1); + if (newIcon != null) { + newIcon.requestFocus(); + wasHandled = true; + } + } + break; + case KeyEvent.KEYCODE_PAGE_UP: + if (handleKeyEvent) { + // Select the first icon on the previous page or the first icon on this page + // if there is no previous page + if (pageIndex > 0) { + parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + // Snap to the previous page + workspace.snapToPage(pageIndex - 1); + } + } else { + View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_PAGE_DOWN: + if (handleKeyEvent) { + // Select the first icon on the next page or the last icon on this page + // if there is no previous page + if (pageIndex < (pageCount - 1)) { + parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } else { + // Snap to the next page + workspace.snapToPage(pageIndex + 1); + } + } else { + View newIcon = getBubbleTextViewInDirection(layout, parent, + parent.getChildCount(), -1); + if (newIcon != null) { + newIcon.requestFocus(); + } + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_HOME: + if (handleKeyEvent) { + // Select the first icon on this page + View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1); + if (newIcon != null) { + newIcon.requestFocus(); + } + } + wasHandled = true; + break; + case KeyEvent.KEYCODE_MOVE_END: + if (handleKeyEvent) { + // Select the last icon on this page + View newIcon = getBubbleTextViewInDirection(layout, parent, + parent.getChildCount(), -1); + if (newIcon != null) { + newIcon.requestFocus(); + } + } + wasHandled = true; + break; + default: break; + } + return wasHandled; + } +} |