FocusHelper.java revision ac56cff1860b71d3f164aedd268703936e08fdc0
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
1797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungpackage com.android.launcher2;
1897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
194e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chungimport android.content.res.Configuration;
2097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.KeyEvent;
2197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.View;
2297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.ViewGroup;
2397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.view.ViewParent;
2497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.widget.TabHost;
2597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport android.widget.TabWidget;
26ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenimport android.widget.TextView;
2797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
2897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungimport com.android.launcher.R;
2997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
30faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.ArrayList;
31faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.Collections;
32faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport java.util.Comparator;
33faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung
3497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung/**
354d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung * A keyboard listener we set on all the workspace icons.
364d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung */
37ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass IconKeyEventListener implements View.OnKeyListener {
384d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
39ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return FocusHelper.handleIconKeyEvent(v, keyCode, event);
40ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
41ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen}
42ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
43ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen/**
44ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen * A keyboard listener we set on all the workspace icons.
45ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen */
46ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass FolderKeyEventListener implements View.OnKeyListener {
47ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    public boolean onKey(View v, int keyCode, KeyEvent event) {
48ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
494d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung    }
504d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung}
514d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung
524d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung/**
533d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung * A keyboard listener we set on all the hotseat buttons.
544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung */
55ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohenclass HotseatIconKeyEventListener implements View.OnKeyListener {
564e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final Configuration configuration = v.getResources().getConfiguration();
583d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation);
594e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
604e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung}
614e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
624e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung/**
63faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung * A keyboard listener we set on the last tab button in AppsCustomize to jump to then
6497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung * market icon and vice versa.
6597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung */
66faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungclass AppsCustomizeTabKeyEventListener implements View.OnKeyListener {
6797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    public boolean onKey(View v, int keyCode, KeyEvent event) {
68faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung        return FocusHelper.handleAppsCustomizeTabKeyEvent(v, keyCode, event);
6997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
7097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung}
7197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
7297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chungpublic class FocusHelper {
7397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
7497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper to get the parent TabHost in the view hiearchy.
7597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
7697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static TabHost findTabHostParent(View v) {
7797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ViewParent p = v.getParent();
7897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        while (p != null && !(p instanceof TabHost)) {
7997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            p = p.getParent();
8097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
8197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return (TabHost) p;
8297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
8397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
8497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
85faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung     * Handles key events in a AppsCustomize tab between the last tab view and the shop button.
8697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
87faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung    static boolean handleAppsCustomizeTabKeyEvent(View v, int keyCode, KeyEvent e) {
8897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final TabHost tabHost = findTabHostParent(v);
8997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ViewGroup contents = (ViewGroup)
9097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                tabHost.findViewById(com.android.internal.R.id.tabcontent);
9197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final View shop = tabHost.findViewById(R.id.market_button);
9297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
9397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
9497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
9597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
9697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
9797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
9897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
9997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the shop button if we aren't on it
10097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (v != shop) {
10197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        shop.requestFocus();
10297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
10397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
10497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
10597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
10697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
10797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
10897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the content view (down is handled by the tab key handler otherwise)
10997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (v == shop) {
11097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        contents.requestFocus();
11197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        wasHandled = true;
11297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
11397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
11497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
11597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
11697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
11797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
11897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
11997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
12097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
12197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper to determine whether a view is visible.
12297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
12397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static boolean isVisible(View v) {
12497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return v.getVisibility() == View.VISIBLE;
12597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
12697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
12797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
12897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
1294e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung     */
1304e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
1314e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            KeyEvent e) {
1324e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
1334e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
1344e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final ViewGroup container = (ViewGroup) parent.getParent();
1354e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final TabHost tabHost = findTabHostParent(container);
1364e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
1374e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int widgetIndex = parent.indexOfChild(w);
1384e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int widgetCount = parent.getChildCount();
1394e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int pageIndex = container.indexOfChild(parent);
1404e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int pageCount = container.getChildCount();
1414e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int cellCountX = parent.getCellCountX();
1424e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int cellCountY = parent.getCellCountY();
1434e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int x = widgetIndex % cellCountX;
1444e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int y = widgetIndex / cellCountX;
1454e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
1464e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int action = e.getAction();
1474e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
1484e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        PagedViewGridLayout newParent = null;
1493b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        // Now that we load items in the bg asynchronously, we can't just focus
1503b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        // child siblings willy-nilly
1513b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung        View child = null;
1524e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        boolean wasHandled = false;
1534e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        switch (keyCode) {
1544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
1554e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1564e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the previous widget or the last widget on the previous page
1574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (widgetIndex > 0) {
1584e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(widgetIndex - 1).requestFocus();
1594e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1604e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        if (pageIndex > 0) {
1614e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                            newParent = (PagedViewGridLayout)
1624e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                                    container.getChildAt(pageIndex - 1);
1633b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                            child = newParent.getChildAt(newParent.getChildCount() - 1);
1643b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                            if (child != null) child.requestFocus();
1654e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        }
1664e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1674e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1684e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1694e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1704e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
1714e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1724e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the next widget or the first widget on the next page
1734e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (widgetIndex < (widgetCount - 1)) {
1744e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(widgetIndex + 1).requestFocus();
1754e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1764e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        if (pageIndex < (pageCount - 1)) {
1774e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                            newParent = (PagedViewGridLayout)
1784e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                                    container.getChildAt(pageIndex + 1);
1793b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                            child = newParent.getChildAt(0);
1803b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                            if (child != null) child.requestFocus();
1814e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        }
1824e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1834e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1844e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1854e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1864e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_UP:
1874e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
1884e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the closest icon in the previous row, otherwise select the tab bar
1894e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (y > 0) {
1904e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        int newWidgetIndex = ((y - 1) * cellCountX) + x;
1913b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(newWidgetIndex);
1923b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        if (child != null) child.requestFocus();
1934e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
1944e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        tabs.requestFocus();
1954e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
1964e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
1974e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
1984e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
1994e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
2004e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2014e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the closest icon in the previous row, otherwise do nothing
2024e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (y < (cellCountY - 1)) {
2034e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
2043b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(newWidgetIndex);
2053b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        if (child != null) child.requestFocus();
2064e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
2074e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2084e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2094e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2104e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_ENTER:
2114e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_CENTER:
2124e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2134e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Simulate a click on the widget
2144e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    View.OnClickListener clickListener = (View.OnClickListener) container;
2154e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    clickListener.onClick(w);
2164e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2174e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2184e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2194e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_PAGE_UP:
2204e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2214e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on the previous page, or the first item on this page
2224e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // if there is no previous page
2234e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (pageIndex > 0) {
2244e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex - 1);
2253b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = newParent.getChildAt(0);
2264e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
2273b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(0);
2284e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
2293b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
2304e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2314e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2324e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2334e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
2344e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2354e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on the next page, or the last item on this page
2364e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // if there is no next page
2374e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (pageIndex < (pageCount - 1)) {
2384e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex + 1);
2393b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = newParent.getChildAt(0);
2404e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
2413b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                        child = parent.getChildAt(widgetCount - 1);
2424e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
2433b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
2444e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2454e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2464e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2474e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
2484e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2494e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first item on this page
2503b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    child = parent.getChildAt(0);
2513b0b46af5dd09ae00cd0ff7fcce6cff17447acadWinson Chung                    if (child != null) child.requestFocus();
2524e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2534e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2544e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2554e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_MOVE_END:
2564e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
2574e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the last item on this page
2584e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    parent.getChildAt(widgetCount - 1).requestFocus();
2594e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
2604e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
2614e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
2624e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            default: break;
2634e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        }
2644e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        return wasHandled;
2654e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
2664e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
2674e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    /**
26897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout
26997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * index.
27097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
27197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex(
27297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            ViewGroup container, int i) {
27397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ViewGroup parent = (ViewGroup) container.getChildAt(i);
27497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return (PagedViewCellLayoutChildren) parent.getChildAt(0);
27597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
27697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
27797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
27897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in a PageViewCellLayout containing PagedViewIcons.
27997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
28097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) {
28197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent();
28297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent();
28397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // Note we have an extra parent because of the
28497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
28597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ViewGroup container = (ViewGroup) parentLayout.getParent();
28697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final TabHost tabHost = findTabHostParent(container);
28797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
28890576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        final int iconIndex = parent.indexOfChild(v);
28997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int widgetCount = parent.getChildCount();
29097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int pageIndex = container.indexOfChild(parentLayout);
29197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int pageCount = container.getChildCount();
29297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountX = parentLayout.getCellCountX();
29397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountY = parentLayout.getCellCountY();
29490576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        final int x = iconIndex % cellCountX;
29590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        final int y = iconIndex / cellCountX;
29697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
29797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
29897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
29997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        PagedViewCellLayoutChildren newParent = null;
30090576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        // Side pages do not always load synchronously, so check before focusing child siblings
30190576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        // willy-nilly
30290576b5f095371e1ba4fedcb775f43715adf9634Winson Chung        View child = null;
30397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
30497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
30597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
30697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
30797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous icon or the last icon on the previous page
30890576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                    if (iconIndex > 0) {
30990576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        parent.getChildAt(iconIndex - 1).requestFocus();
31097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
31197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex > 0) {
31297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
31397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                    pageIndex - 1);
31490576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (newParent != null) {
31590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                child = newParent.getChildAt(newParent.getChildCount() - 1);
31690576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                if (child != null) child.requestFocus();
31790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            }
31897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
31997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
32097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
32197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
32297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
32397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
32497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
32597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next icon or the first icon on the next page
32690576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                    if (iconIndex < (widgetCount - 1)) {
32790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        parent.getChildAt(iconIndex + 1).requestFocus();
32897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
32997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex < (pageCount - 1)) {
33097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
33197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                    pageIndex + 1);
33290576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (newParent != null) {
33390576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                child = newParent.getChildAt(0);
33490576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                                if (child != null) child.requestFocus();
33590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            }
33697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
33797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
33897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
33997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
34097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
34197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
34297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
34397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the closest icon in the previous row, otherwise select the tab bar
34497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (y > 0) {
34590576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        int newiconIndex = ((y - 1) * cellCountX) + x;
34690576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        parent.getChildAt(newiconIndex).requestFocus();
34797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
34897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        tabs.requestFocus();
34997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
35097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
35197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
35297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
35397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
35497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
35597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the closest icon in the previous row, otherwise do nothing
35697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (y < (cellCountY - 1)) {
35790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        int newiconIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
35890576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        parent.getChildAt(newiconIndex).requestFocus();
35997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
36097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
36197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
36297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
36397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_ENTER:
36497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_CENTER:
36597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
36697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Simulate a click on the icon
36797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    View.OnClickListener clickListener = (View.OnClickListener) container;
36897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    clickListener.onClick(v);
36997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
37097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
37197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
37297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_UP:
37397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
37497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the previous page, or the first icon on this page
37597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
37697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex > 0) {
37797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
37897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                pageIndex - 1);
37990576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        if (newParent != null) {
38090576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            child = newParent.getChildAt(0);
38190576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (child != null) child.requestFocus();
38290576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        }
38397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
38497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildAt(0).requestFocus();
38597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
38697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
38797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
38897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
38997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
39097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
39197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the next page, or the last icon on this page
39297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no next page
39397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex < (pageCount - 1)) {
39497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
39597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                pageIndex + 1);
39690576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        if (newParent != null) {
39790576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            child = newParent.getChildAt(0);
39890576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                            if (child != null) child.requestFocus();
39990576b5f095371e1ba4fedcb775f43715adf9634Winson Chung                        }
40097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
40197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildAt(widgetCount - 1).requestFocus();
40297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
40397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
40497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
40597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
40697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
40797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
40897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on this page
40997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    parent.getChildAt(0).requestFocus();
41097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
41197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
41297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
41397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_END:
41497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
41597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the last icon on this page
41697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    parent.getChildAt(widgetCount - 1).requestFocus();
41797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
41897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
41997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
42097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
42197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
42297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
42397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
42497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
42597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
42697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Handles key events in the tab widget.
42797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
42897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
429a2eb17095dcffa75c1e9681fdc318fe6e0564321Michael Jurka        if (!LauncherApplication.isScreenLarge()) return false;
43097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
43197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
43297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final TabHost tabHost = findTabHostParent(parent);
43397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ViewGroup contents = (ViewGroup)
43497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                tabHost.findViewById(com.android.internal.R.id.tabcontent);
43597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int tabCount = parent.getTabCount();
43697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int tabIndex = parent.getChildTabIndex(v);
43797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
43897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
43997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
44097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
44197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
44297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
44397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
44497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous tab
44597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tabIndex > 0) {
44697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildTabViewAt(tabIndex - 1).requestFocus();
44797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
44897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
44997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
45097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
45197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
45297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
45397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next tab, or if the last tab has a focus right id, select that
45497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tabIndex < (tabCount - 1)) {
45597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent.getChildTabViewAt(tabIndex + 1).requestFocus();
45697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
45797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (v.getNextFocusRightId() != View.NO_ID) {
45897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
45997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
46097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
46197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
46297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
46397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
46497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
46597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                // Do nothing
46697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
46797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
46897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
46997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
47097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the content view
47197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    contents.requestFocus();
47297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
47397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
47497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
47597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
47697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
47797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
47897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
47997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
48097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
4813d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung     * Handles key events in the workspace hotseat (bottom of the screen).
4824e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung     */
4833d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung    static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
4844e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final ViewGroup parent = (ViewGroup) v.getParent();
4854e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final ViewGroup launcher = (ViewGroup) parent.getParent();
4864e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
4874e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int buttonIndex = parent.indexOfChild(v);
4884e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int buttonCount = parent.getChildCount();
4894e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int pageIndex = workspace.getCurrentPage();
4904e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
4914e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        // NOTE: currently we don't special case for the phone UI in different
4923d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung        // orientations, even though the hotseat is on the side in landscape mode.  This
4934e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        // is to ensure that accessibility consistency is maintained across rotations.
4944e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
4954e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final int action = e.getAction();
4964e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
4974e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        boolean wasHandled = false;
4984e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        switch (keyCode) {
4994e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
5004e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
50174608b5dfc22811eb16a39056e9c2d1e6681306bWinson Chung                    // Select the previous button, otherwise snap to the previous page
5024e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (buttonIndex > 0) {
5034e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(buttonIndex - 1).requestFocus();
5044e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
50574608b5dfc22811eb16a39056e9c2d1e6681306bWinson Chung                        workspace.snapToPage(pageIndex - 1);
5064e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
5074e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
5084e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5094e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5104e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
5114e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
51274608b5dfc22811eb16a39056e9c2d1e6681306bWinson Chung                    // Select the next button, otherwise snap to the next page
5134e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (buttonIndex < (buttonCount - 1)) {
5144e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        parent.getChildAt(buttonIndex + 1).requestFocus();
5154e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
51674608b5dfc22811eb16a39056e9c2d1e6681306bWinson Chung                        workspace.snapToPage(pageIndex + 1);
5174e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
5184e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
5194e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5204e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5214e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_UP:
5224e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                if (handleKeyEvent) {
5234e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    // Select the first bubble text view in the current page of the workspace
5244e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
5254e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    final CellLayoutChildren children = layout.getChildrenLayout();
526ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    final View newIcon = getIconInDirection(layout, children, -1, 1);
5274e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    if (newIcon != null) {
5284e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        newIcon.requestFocus();
5294e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    } else {
5304e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                        workspace.requestFocus();
5314e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                    }
5324e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                }
5334e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5344e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5354e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
5364e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                // Do nothing
5374e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                wasHandled = true;
5384e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung                break;
5394e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung            default: break;
5404e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        }
5414e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung        return wasHandled;
5424e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    }
5434e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung
5444e6a976c2d85f7261ae4318a9ccffd2440f73124Winson Chung    /**
54597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper method to get the CellLayoutChildren given a CellLayout index.
54697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
54797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static CellLayoutChildren getCellLayoutChildrenForIndex(ViewGroup container, int i) {
54897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ViewGroup parent = (ViewGroup) container.getChildAt(i);
54997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return (CellLayoutChildren) parent.getChildAt(0);
55097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
55197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
55297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
55397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
55497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * from top left to bottom right.
55597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
55697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
55797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            ViewGroup parent) {
55897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // First we order each the CellLayout children by their x,y coordinates
55997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountX = layout.getCountX();
56097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int count = parent.getChildCount();
56197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        ArrayList<View> views = new ArrayList<View>();
56297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        for (int j = 0; j < count; ++j) {
56397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            views.add(parent.getChildAt(j));
56497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
56597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        Collections.sort(views, new Comparator<View>() {
56697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            @Override
56797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            public int compare(View lhs, View rhs) {
56897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
56997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
57097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
57197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
57297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return lvIndex - rvIndex;
57397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
57497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        });
57597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return views;
57697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
57797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
578ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Private helper method to find the index of the next BubbleTextView or FolderIcon in the
579ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * direction delta.
580ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     *
58197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * @param delta either -1 or 1 depending on the direction we want to search
58297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
583ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View findIndexOfIcon(ArrayList<View> views, int i, int delta) {
58497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        // Then we find the next BubbleTextView offset by delta from i
58597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int count = views.size();
58697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int newI = i + delta;
58797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        while (0 <= newI && newI < count) {
58897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            View newV = views.get(newI);
589ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            if (newV instanceof BubbleTextView || newV instanceof FolderIcon) {
59097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return newV;
59197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
59297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            newI += delta;
59397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
59497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return null;
59597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
596ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getIconInDirection(CellLayout layout, ViewGroup parent, int i,
59797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int delta) {
59897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
599ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return findIndexOfIcon(views, i, delta);
60097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
601ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getIconInDirection(CellLayout layout, ViewGroup parent, View v,
60297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int delta) {
60397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
604ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return findIndexOfIcon(views, views.indexOf(v), delta);
60597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
60697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
607ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Private helper method to find the next closest BubbleTextView or FolderIcon in the direction
608ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * delta on the next line.
609ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     *
61097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     * @param delta either -1 or 1 depending on the line and direction we want to search
61197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
612ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    private static View getClosestIconOnLine(CellLayout layout, ViewGroup parent, View v,
61397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int lineDelta) {
61497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
61597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
61697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountX = layout.getCountX();
61797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int cellCountY = layout.getCountY();
61897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int row = lp.cellY;
61997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int newRow = row + lineDelta;
62097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        if (0 <= newRow && newRow < cellCountY) {
62197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            float closestDistance = Float.MAX_VALUE;
62297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int closestIndex = -1;
62397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int index = views.indexOf(v);
62497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            int endIndex = (lineDelta < 0) ? -1 : views.size();
62597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            while (index != endIndex) {
62697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                View newV = views.get(index);
62797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
62897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
629ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (satisfiesRow &&
630ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        (newV instanceof BubbleTextView || newV instanceof FolderIcon)) {
63197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
63297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            Math.pow(tmpLp.cellY - lp.cellY, 2));
63397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (tmpDistance < closestDistance) {
63497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        closestIndex = index;
63597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        closestDistance = tmpDistance;
63697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
63797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
63897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (index <= endIndex) {
63997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    ++index;
64097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                } else {
64197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    --index;
64297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
64397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
64497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            if (closestIndex > -1) {
64597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                return views.get(closestIndex);
64697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            }
64797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
64897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return null;
64997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
65097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
65197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    /**
652ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Handles key events in a Workspace containing.
65397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung     */
654ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
65597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        CellLayoutChildren parent = (CellLayoutChildren) v.getParent();
65697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final CellLayout layout = (CellLayout) parent.getParent();
65797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final Workspace workspace = (Workspace) layout.getParent();
65897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final ViewGroup launcher = (ViewGroup) workspace.getParent();
659faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung        final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.qsb_bar);
6604d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung        final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat);
66197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int pageIndex = workspace.indexOfChild(layout);
66297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        int pageCount = workspace.getChildCount();
66397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung
66497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final int action = e.getAction();
66597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
66697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        boolean wasHandled = false;
66797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        switch (keyCode) {
66897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_LEFT:
66997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
67097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the previous icon or the last icon on the previous page if possible
671ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, -1);
67297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
67397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
67497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
67597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex > 0) {
67697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
677ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            newIcon = getIconInDirection(layout, parent,
67897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                    parent.getChildCount(), -1);
67997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            if (newIcon != null) {
68097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                newIcon.requestFocus();
68197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            } else {
68297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                // Snap to the previous page
68397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                workspace.snapToPage(pageIndex - 1);
68497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            }
68597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
68697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
68797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
68897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
68997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
69097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_RIGHT:
69197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
69297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the next icon or the first icon on the next page if possible
693ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, 1);
69497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
69597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
69697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
69797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (pageIndex < (pageCount - 1)) {
69897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
699ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            newIcon = getIconInDirection(layout, parent, -1, 1);
70097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            if (newIcon != null) {
70197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                newIcon.requestFocus();
70297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            } else {
70397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                // Snap to the next page
70497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                workspace.snapToPage(pageIndex + 1);
70597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            }
70697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
70797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
70897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
70997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
71097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
71197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_UP:
71297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
71397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the closest icon in the previous line, otherwise select the tab bar
714ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
71597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
71697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
71797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        wasHandled = true;
71897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
71997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        tabs.requestFocus();
72097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
72197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
72297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
72397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_DPAD_DOWN:
72497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
7254d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                    // Select the closest icon in the next line, otherwise select the button bar
726ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
72797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
72897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
72997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        wasHandled = true;
7304d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                    } else if (hotseat != null) {
7314d279d94ade1c0d455404312b3c9cfde0078c547Winson Chung                        hotseat.requestFocus();
73297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
73397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
73497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
73597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_UP:
73697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
73797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the previous page or the first icon on this page
73897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
73997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex > 0) {
74097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
741ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
74297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
74397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
74497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        } else {
74597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            // Snap to the previous page
74697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            workspace.snapToPage(pageIndex - 1);
74797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
74897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
749ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
75097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
75197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
75297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
75397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
75497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
75597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
75697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
75797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_PAGE_DOWN:
75897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
75997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on the next page or the last icon on this page
76097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // if there is no previous page
76197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (pageIndex < (pageCount - 1)) {
76297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
763ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent, -1, 1);
76497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
76597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
76697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        } else {
76797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            // Snap to the next page
76897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            workspace.snapToPage(pageIndex + 1);
76997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
77097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    } else {
771ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        View newIcon = getIconInDirection(layout, parent,
77297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                                parent.getChildCount(), -1);
77397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        if (newIcon != null) {
77497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            newIcon.requestFocus();
77597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        }
77697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
77797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
77897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
77997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
78097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_HOME:
78197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
78297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the first icon on this page
783ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, -1, 1);
784ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
785ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
786ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
787ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
788ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
789ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
790ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_MOVE_END:
791ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
792ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the last icon on this page
793ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent,
794ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                            parent.getChildCount(), -1);
795ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
796ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
797ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
798ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
799ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
800ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
801ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            default: break;
802ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        }
803ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        return wasHandled;
804ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    }
805ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
806ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    /**
807ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     * Handles key events for items in a Folder.
808ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen     */
809ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen    static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
810ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        CellLayoutChildren parent = (CellLayoutChildren) v.getParent();
811ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final CellLayout layout = (CellLayout) parent.getParent();
812ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final Folder folder = (Folder) layout.getParent();
813ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        View title = folder.mFolderName;
814ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen
815ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final int action = e.getAction();
816ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
817ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        boolean wasHandled = false;
818ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen        switch (keyCode) {
819ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_LEFT:
820ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
821ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the previous icon
822ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, -1);
823ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
824ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
825ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
826ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
827ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
828ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
829ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_RIGHT:
830ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
831ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the next icon
832ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, v, 1);
833ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
834ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
835ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    } else {
836ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        title.requestFocus();
837ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
838ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
839ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
840ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
841ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_UP:
842ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
843ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the closest icon in the previous line
844ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
845ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
846ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
847ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
848ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
849ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
850ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
851ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_DPAD_DOWN:
852ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
853ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the closest icon in the next line
854ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
855ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    if (newIcon != null) {
856ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        newIcon.requestFocus();
857ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    } else {
858ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                        title.requestFocus();
859ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    }
860ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                }
861ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                wasHandled = true;
862ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                break;
863ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen            case KeyEvent.KEYCODE_MOVE_HOME:
864ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                if (handleKeyEvent) {
865ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    // Select the first icon on this page
866ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent, -1, 1);
86797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
86897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
86997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
87097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
87197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
87297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
87397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            case KeyEvent.KEYCODE_MOVE_END:
87497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                if (handleKeyEvent) {
87597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    // Select the last icon on this page
876ac56cff1860b71d3f164aedd268703936e08fdc0Adam Cohen                    View newIcon = getIconInDirection(layout, parent,
87797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                            parent.getChildCount(), -1);
87897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    if (newIcon != null) {
87997d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                        newIcon.requestFocus();
88097d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                    }
88197d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                }
88297d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                wasHandled = true;
88397d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung                break;
88497d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung            default: break;
88597d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        }
88697d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung        return wasHandled;
88797d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung    }
88897d85d23b013347bead4e2f5fa430a79ce69431eWinson Chung}
889