197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung/*
297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * Copyright (C) 2011 The Android Open Source Project
397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung *
497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * Licensed under the Apache License, Version 2.0 (the "License");
597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * you may not use this file except in compliance with the License.
697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * You may obtain a copy of the License at
797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung *
897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung *      http://www.apache.org/licenses/LICENSE-2.0
997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung *
1097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * Unless required by applicable law or agreed to in writing, software
1197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * distributed under the License is distributed on an "AS IS" BASIS,
1297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * See the License for the specific language governing permissions and
1497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * limitations under the License.
1597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung */
1697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
194e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chungimport android.content.res.Configuration;
20b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyalimport android.util.Log;
2197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.KeyEvent;
22b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyalimport android.view.SoundEffectConstants;
2397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.View;
2497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.ViewGroup;
2597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.ViewParent;
26a1f133de788823603a2c62aba5dc5d84c5a39cc6Winson Chungimport android.widget.ScrollView;
2797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
28faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.ArrayList;
29faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.Collections;
30faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.Comparator;
31faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung
3297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung/**
334d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung * A keyboard listener we set on all the workspace icons.
344d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung */
35ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass IconKeyEventListener implements View.OnKeyListener {
364d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
37ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return FocusHelper.handleIconKeyEvent(v, keyCode, event);
38ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
39ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen}
40ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
41ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen/**
42ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen * A keyboard listener we set on all the workspace icons.
43ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen */
44ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass FolderKeyEventListener implements View.OnKeyListener {
45ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    public boolean onKey(View v, int keyCode, KeyEvent event) {
46ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
474d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung    }
484d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung}
494d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung
504d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung/**
513d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung * A keyboard listener we set on all the hotseat buttons.
524e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung */
53ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass HotseatIconKeyEventListener implements View.OnKeyListener {
544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
554e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final Configuration configuration = v.getResources().getConfiguration();
563d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation);
574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
584e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung}
594e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
6097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungpublic class FocusHelper {
6197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
6297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper to get the parent TabHost in the view hiearchy.
6397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
64c956cbaee26c173ff3f9ec6625822b92dd07766fAdam Cohen    private static AppsCustomizeTabHost findTabHostParent(View v) {
6597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ViewParent p = v.getParent();
66c956cbaee26c173ff3f9ec6625822b92dd07766fAdam Cohen        while (p != null && !(p instanceof AppsCustomizeTabHost)) {
6797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            p = p.getParent();
6897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
69c956cbaee26c173ff3f9ec6625822b92dd07766fAdam Cohen        return (AppsCustomizeTabHost) p;
7097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
7197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
7297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
73ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen     * Returns the Viewgroup containing page contents for the page at the index specified.
74ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen     */
75ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
76ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index);
77c58497ee619416c4949b16eb43486c11618b69e5Winson Chung        if (page instanceof CellLayout) {
78ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
79c58497ee619416c4949b16eb43486c11618b69e5Winson Chung            page = ((CellLayout) page).getShortcutsAndWidgets();
80ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        }
81ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        return page;
82ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    }
83ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen
84ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    /**
8597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
864e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung     */
874e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
884e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            KeyEvent e) {
894e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
904e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
91ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final PagedView container = (PagedView) parent.getParent();
924e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int widgetIndex = parent.indexOfChild(w);
934e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int widgetCount = parent.getChildCount();
94ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent));
954e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int pageCount = container.getChildCount();
964e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int cellCountX = parent.getCellCountX();
974e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int cellCountY = parent.getCellCountY();
984e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int x = widgetIndex % cellCountX;
994e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int y = widgetIndex / cellCountX;
1004e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
1014e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int action = e.getAction();
1024e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
103ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        ViewGroup newParent = null;
1043b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        // Now that we load items in the bg asynchronously, we can't just focus
1053b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        // child siblings willy-nilly
1063b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        View child = null;
1074e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        boolean wasHandled = false;
1084e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        switch (keyCode) {
1094e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
1104e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1114e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the previous widget or the last widget on the previous page
1124e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (widgetIndex > 0) {
1134e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(widgetIndex - 1).requestFocus();
1144e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1154e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        if (pageIndex > 0) {
116ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            newParent = getAppsCustomizePage(container, pageIndex - 1);
117ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            if (newParent != null) {
118ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                child = newParent.getChildAt(newParent.getChildCount() - 1);
119ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                if (child != null) child.requestFocus();
120ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            }
1214e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        }
1224e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1234e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1244e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1254e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1264e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
1274e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1284e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the next widget or the first widget on the next page
1294e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (widgetIndex < (widgetCount - 1)) {
1304e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(widgetIndex + 1).requestFocus();
1314e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1324e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        if (pageIndex < (pageCount - 1)) {
133ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            newParent = getAppsCustomizePage(container, pageIndex + 1);
134ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            if (newParent != null) {
135ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                child = newParent.getChildAt(0);
136ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                if (child != null) child.requestFocus();
137ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            }
1384e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        }
1394e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1404e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1414e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1424e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1434e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_UP:
1444e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1454e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the closest icon in the previous row, otherwise select the tab bar
1464e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (y > 0) {
1474e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        int newWidgetIndex = ((y - 1) * cellCountX) + x;
1483b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(newWidgetIndex);
1493b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        if (child != null) child.requestFocus();
1504e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1514e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1524e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1534e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
1554e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1564e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the closest icon in the previous row, otherwise do nothing
1574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (y < (cellCountY - 1)) {
1584e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
1593b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(newWidgetIndex);
1603b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        if (child != null) child.requestFocus();
1614e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1624e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1634e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1644e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1654e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_ENTER:
1664e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_CENTER:
1674e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1684e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Simulate a click on the widget
1694e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    View.OnClickListener clickListener = (View.OnClickListener) container;
1704e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    clickListener.onClick(w);
1714e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1724e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1734e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1744e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_PAGE_UP:
1754e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1764e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on the previous page, or the first item on this page
1774e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // if there is no previous page
1784e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (pageIndex > 0) {
179ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        newParent = getAppsCustomizePage(container, pageIndex - 1);
180ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        if (newParent != null) {
181ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            child = newParent.getChildAt(0);
182ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        }
1834e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1843b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(0);
1854e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1863b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
1874e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1884e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1894e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1904e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
1914e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1924e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on the next page, or the last item on this page
1934e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // if there is no next page
1944e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (pageIndex < (pageCount - 1)) {
195ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        newParent = getAppsCustomizePage(container, pageIndex + 1);
196ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        if (newParent != null) {
197ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            child = newParent.getChildAt(0);
198ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        }
1994e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
2003b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(widgetCount - 1);
2014e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
2023b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
2034e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2044e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2054e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2064e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
2074e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2084e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on this page
2093b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    child = parent.getChildAt(0);
2103b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
2114e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2124e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2134e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2144e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_MOVE_END:
2154e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2164e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the last item on this page
2174e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    parent.getChildAt(widgetCount - 1).requestFocus();
2184e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2194e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2204e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2214e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            default: break;
2224e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        }
2234e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        return wasHandled;
2244e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
2254e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
2264e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    /**
22797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in a PageViewCellLayout containing PagedViewIcons.
22897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
229ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen    static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
230ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        ViewGroup parentLayout;
231ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        ViewGroup itemContainer;
232ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        int countX;
233ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        int countY;
234c58497ee619416c4949b16eb43486c11618b69e5Winson Chung        if (v.getParent() instanceof ShortcutAndWidgetContainer) {
235ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            itemContainer = (ViewGroup) v.getParent();
236ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            parentLayout = (ViewGroup) itemContainer.getParent();
237c58497ee619416c4949b16eb43486c11618b69e5Winson Chung            countX = ((CellLayout) parentLayout).getCountX();
238c58497ee619416c4949b16eb43486c11618b69e5Winson Chung            countY = ((CellLayout) parentLayout).getCountY();
239ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        } else {
240ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            itemContainer = parentLayout = (ViewGroup) v.getParent();
241ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            countX = ((PagedViewGridLayout) parentLayout).getCellCountX();
242ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen            countY = ((PagedViewGridLayout) parentLayout).getCellCountY();
243ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        }
244ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen
24597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // Note we have an extra parent because of the
24697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
247ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final PagedView container = (PagedView) parentLayout.getParent();
248ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int iconIndex = itemContainer.indexOfChild(v);
249ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int itemCount = itemContainer.getChildCount();
250ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
25197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int pageCount = container.getChildCount();
252ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen
253ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int x = iconIndex % countX;
254ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        final int y = iconIndex / countX;
25597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
256b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        final int action = e.getAction();
25797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
258ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen        ViewGroup newParent = null;
25990576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        // Side pages do not always load synchronously, so check before focusing child siblings
26090576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        // willy-nilly
26190576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        View child = null;
26297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
26397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
26497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
26597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
26697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous icon or the last icon on the previous page
26790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                    if (iconIndex > 0) {
268ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        itemContainer.getChildAt(iconIndex - 1).requestFocus();
269b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
27097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
27197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex > 0) {
272ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            newParent = getAppsCustomizePage(container, pageIndex - 1);
27390576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (newParent != null) {
274ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                container.snapToPage(pageIndex - 1);
27590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                child = newParent.getChildAt(newParent.getChildCount() - 1);
276b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                if (child != null) {
277b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                    child.requestFocus();
278b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
279b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                }
28090576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            }
28197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
28297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
28397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
28497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
28597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
28697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
28797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
28897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next icon or the first icon on the next page
289ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                    if (iconIndex < (itemCount - 1)) {
290ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        itemContainer.getChildAt(iconIndex + 1).requestFocus();
291b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
29297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
29397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex < (pageCount - 1)) {
294ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            newParent = getAppsCustomizePage(container, pageIndex + 1);
29590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (newParent != null) {
296ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                                container.snapToPage(pageIndex + 1);
29790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                child = newParent.getChildAt(0);
298b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                if (child != null) {
299b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                    child.requestFocus();
300b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
301b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                }
30290576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            }
30397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
30497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
30597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
30697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
30797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
30897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
30997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
31097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the closest icon in the previous row, otherwise select the tab bar
31197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (y > 0) {
312ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        int newiconIndex = ((y - 1) * countX) + x;
313ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        itemContainer.getChildAt(newiconIndex).requestFocus();
314b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
31597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
31697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
31797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
31897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
31997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
32097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
321b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    // Select the closest icon in the next row, otherwise do nothing
322ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                    if (y < (countY - 1)) {
323ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x);
324b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        int newIconY = newiconIndex / countX;
325b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        if (newIconY != y) {
326b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            itemContainer.getChildAt(newiconIndex).requestFocus();
327b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
328b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        }
32997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
33097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
33197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
33297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
33397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_UP:
33497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
33597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the previous page, or the first icon on this page
33697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
33797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex > 0) {
338ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        newParent = getAppsCustomizePage(container, pageIndex - 1);
33990576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        if (newParent != null) {
340ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            container.snapToPage(pageIndex - 1);
34190576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            child = newParent.getChildAt(0);
342b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            if (child != null) {
343b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                child.requestFocus();
344b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
345b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            }
34690576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        }
34797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
348ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        itemContainer.getChildAt(0).requestFocus();
349b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
35097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
35197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
35297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
35397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
35497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
35597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
35697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the next page, or the last icon on this page
35797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no next page
35897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex < (pageCount - 1)) {
359ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        newParent = getAppsCustomizePage(container, pageIndex + 1);
36090576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        if (newParent != null) {
361ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                            container.snapToPage(pageIndex + 1);
36290576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            child = newParent.getChildAt(0);
363b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            if (child != null) {
364b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                child.requestFocus();
365b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                                v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
366b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            }
36790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        }
36897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
369ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                        itemContainer.getChildAt(itemCount - 1).requestFocus();
370b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
37197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
37297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
37397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
37497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
37597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
37697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
37797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on this page
378ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                    itemContainer.getChildAt(0).requestFocus();
379b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
38097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
38197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
38297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
38397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_END:
38497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
38597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the last icon on this page
386ae4f155e090bf387b989fb738ee34ab045585711Adam Cohen                    itemContainer.getChildAt(itemCount - 1).requestFocus();
387b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
38897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
38997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
39097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
39197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
39297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
39397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
39497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
39597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
39697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
39797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in the tab widget.
39897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
39997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
400e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (!LauncherAppState.getInstance().isScreenLarge()) return false;
40197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
40297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
403c956cbaee26c173ff3f9ec6625822b92dd07766fAdam Cohen        final AppsCustomizeTabHost tabHost = findTabHostParent(parent);
404c956cbaee26c173ff3f9ec6625822b92dd07766fAdam Cohen        final ViewGroup contents = tabHost.getContent();
40597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int tabCount = parent.getTabCount();
40697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int tabIndex = parent.getChildTabIndex(v);
40797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
40897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
40997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
41097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
41197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
41297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
41397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
41497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous tab
41597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tabIndex > 0) {
41697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildTabViewAt(tabIndex - 1).requestFocus();
41797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
41897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
41997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
42097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
42197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
42297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
42397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next tab, or if the last tab has a focus right id, select that
42497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tabIndex < (tabCount - 1)) {
42597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildTabViewAt(tabIndex + 1).requestFocus();
42697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
42797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (v.getNextFocusRightId() != View.NO_ID) {
42897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
42997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
43097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
43197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
43297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
43397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
43497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
43597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                // Do nothing
43697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
43797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
43897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
43997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
44097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the content view
44197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    contents.requestFocus();
44297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
44397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
44497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
44597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
44697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
44797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
44897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
44997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
45097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
4513d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung     * Handles key events in the workspace hotseat (bottom of the screen).
4524e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung     */
4533d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
454b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
455b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        final CellLayout layout = (CellLayout) parent.getParent();
4564e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
4574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        // NOTE: currently we don't special case for the phone UI in different
458b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        // orientations, even though the hotseat is on the side in landscape mode. This
4594e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        // is to ensure that accessibility consistency is maintained across rotations.
4604e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int action = e.getAction();
4614e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
4624e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        boolean wasHandled = false;
4634e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        switch (keyCode) {
4644e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
4654e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
466b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
467b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    int myIndex = views.indexOf(v);
468b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    // Select the previous button, otherwise do nothing
469b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    if (myIndex > 0) {
470b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        views.get(myIndex - 1).requestFocus();
471b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
4724e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
4734e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
4744e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
4754e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
4764e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
4774e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
478b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
479b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    int myIndex = views.indexOf(v);
480b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    // Select the next button, otherwise do nothing
481b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    if (myIndex < views.size() - 1) {
482b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        views.get(myIndex + 1).requestFocus();
483b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
4844e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
4854e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
4864e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
4874e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
4884e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_UP:
4894e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
490b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    final Workspace workspace = (Workspace)
491b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.getRootView().findViewById(R.id.workspace);
492b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    if (workspace != null) {
493b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        int pageIndex = workspace.getCurrentPage();
494b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        CellLayout topLayout = (CellLayout) workspace.getChildAt(pageIndex);
495b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        ShortcutAndWidgetContainer children = topLayout.getShortcutsAndWidgets();
496b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        final View newIcon = getIconInDirection(layout, children, -1, 1);
497b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        // Select the first bubble text view in the current page of the workspace
498b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        if (newIcon != null) {
499b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            newIcon.requestFocus();
500b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
501b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        } else {
502b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            workspace.requestFocus();
503b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        }
5044e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
5054e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
5064e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5074e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5084e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
5094e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                // Do nothing
5104e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5114e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5124e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            default: break;
5134e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        }
5144e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        return wasHandled;
5154e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
5164e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
5174e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    /**
51897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper method to get the CellLayoutChildren given a CellLayout index.
51997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
520a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka    private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
521a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka            ViewGroup container, int i) {
522b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        CellLayout parent = (CellLayout) container.getChildAt(i);
523b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal        return parent.getShortcutsAndWidgets();
52497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
52597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
52697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
52797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
52897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * from top left to bottom right.
52997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
53097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
53197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            ViewGroup parent) {
53297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // First we order each the CellLayout children by their x,y coordinates
53397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountX = layout.getCountX();
53497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int count = parent.getChildCount();
53597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ArrayList<View> views = new ArrayList<View>();
53697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        for (int j = 0; j < count; ++j) {
53797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            views.add(parent.getChildAt(j));
53897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
53997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        Collections.sort(views, new Comparator<View>() {
54097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            @Override
54197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            public int compare(View lhs, View rhs) {
54297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
54397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
54497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
54597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
54697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return lvIndex - rvIndex;
54797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
54897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        });
54997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return views;
55097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
55197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
552ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Private helper method to find the index of the next BubbleTextView or FolderIcon in the
553ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * direction delta.
554ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     *
55597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * @param delta either -1 or 1 depending on the direction we want to search
55697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
557ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View findIndexOfIcon(ArrayList<View> views, int i, int delta) {
55897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // Then we find the next BubbleTextView offset by delta from i
55997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int count = views.size();
56097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int newI = i + delta;
56197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        while (0 <= newI && newI < count) {
56297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            View newV = views.get(newI);
563ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            if (newV instanceof BubbleTextView || newV instanceof FolderIcon) {
56497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return newV;
56597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
56697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            newI += delta;
56797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
56897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return null;
56997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
570ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getIconInDirection(CellLayout layout, ViewGroup parent, int i,
57197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int delta) {
57297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
573ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return findIndexOfIcon(views, i, delta);
57497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
575ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getIconInDirection(CellLayout layout, ViewGroup parent, View v,
57697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int delta) {
57797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
578ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return findIndexOfIcon(views, views.indexOf(v), delta);
57997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
58097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
581ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Private helper method to find the next closest BubbleTextView or FolderIcon in the direction
582ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * delta on the next line.
583ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     *
58497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * @param delta either -1 or 1 depending on the line and direction we want to search
58597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
586ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getClosestIconOnLine(CellLayout layout, ViewGroup parent, View v,
58797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int lineDelta) {
58897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
58997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
59097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountY = layout.getCountY();
59197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int row = lp.cellY;
59297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int newRow = row + lineDelta;
59397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        if (0 <= newRow && newRow < cellCountY) {
59497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            float closestDistance = Float.MAX_VALUE;
59597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int closestIndex = -1;
59697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int index = views.indexOf(v);
59797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int endIndex = (lineDelta < 0) ? -1 : views.size();
59897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            while (index != endIndex) {
59997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                View newV = views.get(index);
60097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
60197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
602ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (satisfiesRow &&
603ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        (newV instanceof BubbleTextView || newV instanceof FolderIcon)) {
60497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
60597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            Math.pow(tmpLp.cellY - lp.cellY, 2));
60697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tmpDistance < closestDistance) {
60797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        closestIndex = index;
60897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        closestDistance = tmpDistance;
60997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
61097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
61197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (index <= endIndex) {
61297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    ++index;
61397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                } else {
61497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    --index;
61597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
61697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
61797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            if (closestIndex > -1) {
61897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return views.get(closestIndex);
61997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
62097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
62197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return null;
62297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
62397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
62497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
625ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Handles key events in a Workspace containing.
62697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
627ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
628a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
62997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final CellLayout layout = (CellLayout) parent.getParent();
63097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final Workspace workspace = (Workspace) layout.getParent();
63197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ViewGroup launcher = (ViewGroup) workspace.getParent();
63224ce0b3708b44e738d6ee52477aa4dd917b547e7Adam Cohen        final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar);
6334d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung        final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat);
63497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int pageIndex = workspace.indexOfChild(layout);
63597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int pageCount = workspace.getChildCount();
63697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
63797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
63897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
63997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
64097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
64197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
64297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
64397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous icon or the last icon on the previous page if possible
644ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, -1);
64597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
64697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
647b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
64897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
64997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex > 0) {
65097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
651ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            newIcon = getIconInDirection(layout, parent,
65297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                    parent.getChildCount(), -1);
65397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            if (newIcon != null) {
65497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                newIcon.requestFocus();
65597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            } else {
65697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                // Snap to the previous page
65797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                workspace.snapToPage(pageIndex - 1);
65897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            }
659b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
66097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
66197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
66297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
66397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
66497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
66597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
66697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
66797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next icon or the first icon on the next page if possible
668ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, 1);
66997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
67097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
671b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
67297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
67397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex < (pageCount - 1)) {
67497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
675ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            newIcon = getIconInDirection(layout, parent, -1, 1);
67697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            if (newIcon != null) {
67797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                newIcon.requestFocus();
67897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            } else {
67997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                // Snap to the next page
68097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                workspace.snapToPage(pageIndex + 1);
68197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            }
682b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
68397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
68497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
68597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
68697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
68797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
68897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
68997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
69097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the closest icon in the previous line, otherwise select the tab bar
691ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
69297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
69397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
69497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        wasHandled = true;
69597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
69697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        tabs.requestFocus();
69797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
698b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
69997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
70097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
70197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
70297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
7034d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                    // Select the closest icon in the next line, otherwise select the button bar
704ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
70597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
70697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
707b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
70897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        wasHandled = true;
7094d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                    } else if (hotseat != null) {
7104d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                        hotseat.requestFocus();
711b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
71297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
71397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
71497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
71597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_UP:
71697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
71797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the previous page or the first icon on this page
71897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
71997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex > 0) {
72097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
721ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
72297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
72397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
72497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        } else {
72597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            // Snap to the previous page
72697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            workspace.snapToPage(pageIndex - 1);
72797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
728b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
72997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
730ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
73197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
73297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
733b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
73497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
73597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
73697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
73797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
73897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
73997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
74097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
74197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the next page or the last icon on this page
74297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
74397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex < (pageCount - 1)) {
74497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
745ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
74697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
74797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
74897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        } else {
74997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            // Snap to the next page
75097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            workspace.snapToPage(pageIndex + 1);
75197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
752b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
75397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
754ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent,
75597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                parent.getChildCount(), -1);
75697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
75797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
758b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
75997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
76097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
76197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
76297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
76397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
76497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
76597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
76697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on this page
767ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, -1, 1);
768ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
769ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
770b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
771ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
772ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
773ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
774ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
775ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_MOVE_END:
776ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
777ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the last icon on this page
778ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent,
779ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            parent.getChildCount(), -1);
780ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
781ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
782b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
783ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
784ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
785ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
786ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
787ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            default: break;
788ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
789ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return wasHandled;
790ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
791ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
792ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    /**
793ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Handles key events for items in a Folder.
794ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     */
795ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
796a52570f8f9ad65b85e33a2f2e87722f9edd6c6f4Michael Jurka        ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
797ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final CellLayout layout = (CellLayout) parent.getParent();
798a1f133de788823603a2c62aba5dc5d84c5a39cc6Winson Chung        final ScrollView scrollView = (ScrollView) layout.getParent();
799a1f133de788823603a2c62aba5dc5d84c5a39cc6Winson Chung        final Folder folder = (Folder) scrollView.getParent();
800ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View title = folder.mFolderName;
801ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
802ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final int action = e.getAction();
803ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
804ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        boolean wasHandled = false;
805ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        switch (keyCode) {
806ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_LEFT:
807ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
808ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the previous icon
809ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, -1);
810ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
811ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
812b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
813ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
814ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
815ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
816ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
817ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_RIGHT:
818ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
819ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the next icon
820ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, 1);
821ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
822ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
823ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    } else {
824ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        title.requestFocus();
825ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
826b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
827ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
828ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
829ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
830ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_UP:
831ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
832ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the closest icon in the previous line
833ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
834ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
835ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
836b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
837ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
838ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
839ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
840ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
841ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_DOWN:
842ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
843ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the closest icon in the next line
844ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
845ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
846ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
847ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    } else {
848ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        title.requestFocus();
849ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
850b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
851ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
852ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
853ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
854ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_MOVE_HOME:
855ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
856ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the first icon on this page
857ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, -1, 1);
85897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
85997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
860b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
86197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
86297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
86397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
86497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
86597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_END:
86697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
86797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the last icon on this page
868ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent,
86997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent.getChildCount(), -1);
87097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
87197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
872b3726d90a567e992e4d0f43e7c7acdd8739ae805Sunny Goyal                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
87397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
87497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
87597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
87697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
87797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
87897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
87997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
88097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
88197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung}
882