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