From ee3e6a7b777e58552a26ab8a10641886588e9196 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 20 Feb 2015 14:25:27 -0800 Subject: [key event focus handling] Cleanup/Refactor/Feature 1) Focus navigation handling is refactored to Focus utility class. New 2 step dpad navigation algorithm is inside Focus class 2) Introduced a map (or matrix) that indicates where sparse icons are located inside a grid. This enables getting rid of the icon sorting logic which was costly. 3) Unified all the dpad handling logic inside the handleXXKeyEvent methods 4) DOWN/UP key will allow navigation between workspace icons and the hotseat 5) Folder icons allow DOWN/UP to navigate to the title b/19381790 Change-Id: Id45b3f215ef7c1ca5f99b08e3d721e219298627a --- src/com/android/launcher3/FocusHelper.java | 826 +++++++++++------------------ 1 file changed, 296 insertions(+), 530 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index e60704718..c02d73cb6 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,20 +17,20 @@ package com.android.launcher3; import android.content.res.Configuration; +import android.util.Log; import android.view.KeyEvent; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; import android.widget.ScrollView; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import com.android.launcher3.util.FocusLogic; /** * A keyboard listener we set on all the workspace icons. */ class IconKeyEventListener implements View.OnKeyListener { + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { return FocusHelper.handleIconKeyEvent(v, keyCode, event); } @@ -40,6 +40,7 @@ class IconKeyEventListener implements View.OnKeyListener { * A keyboard listener we set on all the workspace icons. */ class FolderKeyEventListener implements View.OnKeyListener { + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { return FocusHelper.handleFolderKeyEvent(v, keyCode, event); } @@ -49,30 +50,35 @@ class FolderKeyEventListener implements View.OnKeyListener { * A keyboard listener we set on all the hotseat buttons. */ class HotseatIconKeyEventListener implements View.OnKeyListener { + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { - final Configuration configuration = v.getResources().getConfiguration(); - return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation); + return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event); } } public class FocusHelper { - /** - * Returns the Viewgroup containing page contents for the page at the index specified. - */ - private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) { - ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index); - if (page instanceof CellLayout) { - // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren - page = ((CellLayout) page).getShortcutsAndWidgets(); - } - return page; - } + private static final String TAG = "FocusHelper"; + private static final boolean DEBUG = false; + + // + // Key code handling methods. + // /** - * Handles key events in a PageViewCellLayout containing PagedViewIcons. + * Handles key events in the all apps screen. */ static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) { + boolean consume = FocusLogic.shouldConsume(keyCode); + if (e.getAction() == KeyEvent.ACTION_UP) { + return consume; + } + if (DEBUG) { + Log.v(TAG, String.format("Handle ALL APPS keyevent=[%s].", + KeyEvent.keyCodeToString(keyCode))); + } + + // Initialize variables. ViewGroup parentLayout; ViewGroup itemContainer; int countX; @@ -82,341 +88,159 @@ public class FocusHelper { parentLayout = (ViewGroup) itemContainer.getParent(); countX = ((CellLayout) parentLayout).getCountX(); countY = ((CellLayout) parentLayout).getCountY(); - } else { + } else if (v.getParent() instanceof ViewGroup) { itemContainer = parentLayout = (ViewGroup) v.getParent(); countX = ((PagedViewGridLayout) parentLayout).getCellCountX(); countY = ((PagedViewGridLayout) parentLayout).getCellCountY(); + } else { + throw new IllegalStateException( + "Parent of the focused item inside all apps screen is not a supported type."); } - - // Note we have an extra parent because of the - // PagedViewCellLayout/PagedViewCellLayoutChildren relationship - final PagedView container = (PagedView) parentLayout.getParent(); final int iconIndex = itemContainer.indexOfChild(v); - final int itemCount = itemContainer.getChildCount(); - final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout)); + final PagedView container = (PagedView) parentLayout.getParent(); + final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); final int pageCount = container.getChildCount(); - - final int x = iconIndex % countX; - final int y = iconIndex / countX; - - final int action = e.getAction(); - final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); ViewGroup newParent = null; - // Side pages do not always load synchronously, so check before focusing child siblings - // willy-nilly View child = null; - boolean wasHandled = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (handleKeyEvent) { - // Select the previous icon or the last icon on the previous page - if (iconIndex > 0) { - itemContainer.getChildAt(iconIndex - 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } else { - if (pageIndex > 0) { - newParent = getAppsCustomizePage(container, pageIndex - 1); - if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(newParent.getChildCount() - 1); - if (child != null) { - child.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } - } - } - } + int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true); + + // Process focus. + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, + iconIndex, pageIndex, pageCount); + if (newIconIndex == FocusLogic.NOOP) { + return consume; + } + switch (newIconIndex) { + case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex - 1); + if (newParent != null) { + container.snapToPage(pageIndex - 1); + child = newParent.getChildAt(0); } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (handleKeyEvent) { - // Select the next icon or the first icon on the next page - if (iconIndex < (itemCount - 1)) { - itemContainer.getChildAt(iconIndex + 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); - } else { - if (pageIndex < (pageCount - 1)) { - newParent = getAppsCustomizePage(container, pageIndex + 1); - if (newParent != null) { - container.snapToPage(pageIndex + 1); - child = newParent.getChildAt(0); - if (child != null) { - child.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); - } - } - } - } + case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex - 1); + if (newParent != null) { + container.snapToPage(pageIndex - 1); + child = newParent.getChildAt(newParent.getChildCount() - 1); } - wasHandled = true; break; - case KeyEvent.KEYCODE_DPAD_UP: - if (handleKeyEvent) { - // Select the closest icon in the previous row, otherwise select the tab bar - if (y > 0) { - int newiconIndex = ((y - 1) * countX) + x; - itemContainer.getChildAt(newiconIndex).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } + case FocusLogic.NEXT_PAGE_FIRST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex + 1); + if (newParent != null) { + container.snapToPage(pageIndex + 1); + child = newParent.getChildAt(0); } - wasHandled = true; break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (handleKeyEvent) { - // Select the closest icon in the next row, otherwise do nothing - if (y < (countY - 1)) { - int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x); - int newIconY = newiconIndex / countX; - if (newIconY != y) { - itemContainer.getChildAt(newiconIndex).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } - } - wasHandled = true; + case FocusLogic.CURRENT_PAGE_FIRST_ITEM: + child = container.getChildAt(0); break; - case KeyEvent.KEYCODE_PAGE_UP: - if (handleKeyEvent) { - // Select the first icon on the previous page, or the first icon on this page - // if there is no previous page - if (pageIndex > 0) { - newParent = getAppsCustomizePage(container, pageIndex - 1); - if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(0); - if (child != null) { - child.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - } else { - itemContainer.getChildAt(0).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_PAGE_DOWN: - if (handleKeyEvent) { - // Select the first icon on the next page, or the last icon on this page - // if there is no next page - if (pageIndex < (pageCount - 1)) { - newParent = getAppsCustomizePage(container, pageIndex + 1); - if (newParent != null) { - container.snapToPage(pageIndex + 1); - child = newParent.getChildAt(0); - if (child != null) { - child.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } - } else { - itemContainer.getChildAt(itemCount - 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_MOVE_HOME: - if (handleKeyEvent) { - // Select the first icon on this page - itemContainer.getChildAt(0).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - wasHandled = true; + case FocusLogic.CURRENT_PAGE_LAST_ITEM: + child = itemContainer.getChildAt(itemContainer.getChildCount() - 1); break; - case KeyEvent.KEYCODE_MOVE_END: - if (handleKeyEvent) { - // Select the last icon on this page - itemContainer.getChildAt(itemCount - 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - wasHandled = true; + default: // Go to some item on the current page. + child = itemContainer.getChildAt(newIconIndex); break; - default: break; } - return wasHandled; + if (child != null) { + child.requestFocus(); + playSoundEffect(keyCode, v); + } + return consume; } /** - * Handles key events in the workspace hotseat (bottom of the screen). + * Handles key events in the workspace hot seat (bottom of the screen). + *

Currently we don't special case for the phone UI in different orientations, even though + * the hotseat is on the side in landscape mode. This is to ensure that accessibility + * consistency is maintained across rotations. */ - static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) { - ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); - final CellLayout layout = (CellLayout) parent.getParent(); + static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e) { + boolean consume = FocusLogic.shouldConsume(keyCode); + if (e.getAction() == KeyEvent.ACTION_UP || !consume) { + return consume; + } + int orientation = v.getResources().getConfiguration().orientation; - // NOTE: currently we don't special case for the phone UI in different - // orientations, even though the hotseat is on the side in landscape mode. This - // is to ensure that accessibility consistency is maintained across rotations. - final int action = e.getAction(); - final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - boolean wasHandled = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (handleKeyEvent) { - ArrayList views = getCellLayoutChildrenSortedSpatially(layout, parent); - int myIndex = views.indexOf(v); - // Select the previous button, otherwise do nothing - if (myIndex > 0) { - views.get(myIndex - 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (handleKeyEvent) { - ArrayList views = getCellLayoutChildrenSortedSpatially(layout, parent); - int myIndex = views.indexOf(v); - // Select the next button, otherwise do nothing - if (myIndex < views.size() - 1) { - views.get(myIndex + 1).requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_UP: - if (handleKeyEvent) { - final Workspace workspace = (Workspace) - v.getRootView().findViewById(R.id.workspace); - if (workspace != null) { - int pageIndex = workspace.getCurrentPage(); - CellLayout topLayout = (CellLayout) workspace.getChildAt(pageIndex); - ShortcutAndWidgetContainer children = topLayout.getShortcutsAndWidgets(); - final View newIcon = getIconInDirection(layout, children, -1, 1); - // Select the first bubble text view in the current page of the workspace - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } else { - workspace.requestFocus(); - } - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - // Do nothing - wasHandled = true; - break; - default: break; + if (DEBUG) { + Log.v(TAG, String.format( + "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, orientation=%d", + KeyEvent.keyCodeToString(keyCode), orientation)); } - return wasHandled; - } - /** - * Private helper method to get the CellLayoutChildren given a CellLayout index. - */ - private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex( - ViewGroup container, int i) { - CellLayout parent = (CellLayout) container.getChildAt(i); - return parent.getShortcutsAndWidgets(); - } + // Initialize the variables. + final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent(); + final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent(); + Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); + int pageIndex = workspace.getCurrentPage(); + int pageCount = workspace.getChildCount(); + int countX, countY; + int iconIndex = findIndexOfView(hotseatParent, v); + + final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex); + final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets(); + + ViewGroup parent = null; + int[][] matrix; + + if (keyCode == KeyEvent.KEYCODE_DPAD_UP && + orientation == Configuration.ORIENTATION_PORTRAIT) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation); + // TODO: hotseat indexing should be symmetric. + iconIndex += iconParent.getChildCount(); + countX = iconLayout.getCountX(); + countY = iconLayout.getCountY() + hotseatLayout.getCountY(); + parent = iconParent; + } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && + orientation == Configuration.ORIENTATION_LANDSCAPE) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation); + // TODO: hotseat indexing should be symmetric. + iconIndex += iconParent.getChildCount(); + countX = iconLayout.getCountX() + hotseatLayout.getCountX(); + countY = iconLayout.getCountY(); + parent = iconParent; + } else { + // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the + // matrix extended with hotseat. + matrix = FocusLogic.createSparseMatrix(hotseatLayout); + parent = hotseatParent; + countX = hotseatLayout.getCountX(); + countY = hotseatLayout.getCountY(); - /** - * Private helper method to sort all the CellLayout children in order of their (x,y) spatially - * from top left to bottom right. - */ - private static ArrayList getCellLayoutChildrenSortedSpatially(CellLayout layout, - ViewGroup parent) { - // First we order each the CellLayout children by their x,y coordinates - final int cellCountX = layout.getCountX(); - final int count = parent.getChildCount(); - ArrayList views = new ArrayList(); - for (int j = 0; j < count; ++j) { - views.add(parent.getChildAt(j)); } - Collections.sort(views, new Comparator() { - @Override - public int compare(View lhs, View rhs) { - CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams(); - CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams(); - int lvIndex = (llp.cellY * cellCountX) + llp.cellX; - int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX; - return lvIndex - rvIndex; - } - }); - return views; - } - /** - * Private helper method to find the index of the next BubbleTextView or FolderIcon in the - * direction delta. - * - * @param delta either -1 or 1 depending on the direction we want to search - */ - private static View findIndexOfIcon(ArrayList views, int i, int delta) { - // Then we find the next BubbleTextView offset by delta from i - final int count = views.size(); - int newI = i + delta; - while (0 <= newI && newI < count) { - View newV = views.get(newI); - if (newV instanceof BubbleTextView || newV instanceof FolderIcon) { - return newV; - } - newI += delta; + + // Process the focus. + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, + iconIndex, pageIndex, pageCount); + + if (iconParent.getChildCount() <= newIconIndex && + newIconIndex < iconParent.getChildCount() + hotseatParent.getChildCount()) { + newIconIndex -= iconParent.getChildCount(); } - return null; - } - private static View getIconInDirection(CellLayout layout, ViewGroup parent, int i, - int delta) { - final ArrayList views = getCellLayoutChildrenSortedSpatially(layout, parent); - return findIndexOfIcon(views, i, delta); - } - private static View getIconInDirection(CellLayout layout, ViewGroup parent, View v, - int delta) { - final ArrayList views = getCellLayoutChildrenSortedSpatially(layout, parent); - return findIndexOfIcon(views, views.indexOf(v), delta); - } - /** - * Private helper method to find the next closest BubbleTextView or FolderIcon in the direction - * delta on the next line. - * - * @param delta either -1 or 1 depending on the line and direction we want to search - */ - private static View getClosestIconOnLine(CellLayout layout, ViewGroup parent, View v, - int lineDelta) { - final ArrayList views = getCellLayoutChildrenSortedSpatially(layout, parent); - final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams(); - final int cellCountY = layout.getCountY(); - final int row = lp.cellY; - final int newRow = row + lineDelta; - if (0 <= newRow && newRow < cellCountY) { - float closestDistance = Float.MAX_VALUE; - int closestIndex = -1; - int index = views.indexOf(v); - int endIndex = (lineDelta < 0) ? -1 : views.size(); - while (index != endIndex) { - View newV = views.get(index); - CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams(); - boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row); - if (satisfiesRow && - (newV instanceof BubbleTextView || newV instanceof FolderIcon)) { - float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) + - Math.pow(tmpLp.cellY - lp.cellY, 2)); - if (tmpDistance < closestDistance) { - closestIndex = index; - closestDistance = tmpDistance; - } - } - if (index <= endIndex) { - ++index; - } else { - --index; - } - } - if (closestIndex > -1) { - return views.get(closestIndex); + if (parent != null) { + View newIcon = parent.getChildAt(newIconIndex); + if (newIcon != null) { + newIcon.requestFocus(); + playSoundEffect(keyCode, v); } } - return null; + return consume; } /** - * Handles key events in a Workspace containing. + * Handles key events in a workspace containing icons. */ static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) { + boolean consume = FocusLogic.shouldConsume(keyCode); + if (e.getAction() == KeyEvent.ACTION_UP || !consume) { + return consume; + } + int orientation = v.getResources().getConfiguration().orientation; + if (DEBUG) { + Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] orientation=%d", + KeyEvent.keyCodeToString(keyCode), orientation)); + } + + // Initialize the variables. ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); final CellLayout layout = (CellLayout) parent.getParent(); final Workspace workspace = (Workspace) layout.getParent(); @@ -425,249 +249,191 @@ public class FocusHelper { final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat); int pageIndex = workspace.indexOfChild(layout); int pageCount = workspace.getChildCount(); + final int countX = layout.getCountX(); + int countY = layout.getCountY(); + final int iconIndex = findIndexOfView(parent, v); - final int action = e.getAction(); - final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - boolean wasHandled = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (handleKeyEvent) { - // Select the previous icon or the last icon on the previous page if possible - View newIcon = getIconInDirection(layout, parent, v, -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } else { - if (pageIndex > 0) { - parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); - newIcon = getIconInDirection(layout, parent, - parent.getChildCount(), -1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - // Snap to the previous page - workspace.snapToPage(pageIndex - 1); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (handleKeyEvent) { - // Select the next icon or the first icon on the next page if possible - View newIcon = getIconInDirection(layout, parent, v, 1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); - } else { - if (pageIndex < (pageCount - 1)) { - parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); - newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - // Snap to the next page - workspace.snapToPage(pageIndex + 1); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); - } - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_UP: - if (handleKeyEvent) { - // Select the closest icon in the previous line, otherwise select the tab bar - View newIcon = getClosestIconOnLine(layout, parent, v, -1); - if (newIcon != null) { - newIcon.requestFocus(); - wasHandled = true; - } else { - tabs.requestFocus(); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); + CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0); + ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets(); + int[][] matrix; + + // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_LEFT in landscape) is the only key allowed + // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended + // with the hotseat. + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && + orientation == Configuration.ORIENTATION_PORTRAIT) { + matrix = FocusLogic.createSparseMatrix(layout, hotseatLayout, orientation); + countY = countY + 1; + } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && + orientation == Configuration.ORIENTATION_LANDSCAPE) { + matrix = FocusLogic.createSparseMatrix(layout, hotseatLayout, orientation); + countY = countY + 1; + } else { + matrix = FocusLogic.createSparseMatrix(layout); + } + + // Process the focus. + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, + iconIndex, pageIndex, pageCount); + View newIcon = null; + switch (newIconIndex) { + case FocusLogic.NOOP: + if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { + newIcon = tabs; } break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (handleKeyEvent) { - // Select the closest icon in the next line, otherwise select the button bar - View newIcon = getClosestIconOnLine(layout, parent, v, 1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - wasHandled = true; - } else if (hotseat != null) { - hotseat.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } + case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: + parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + newIcon = parent.getChildAt(0); + workspace.snapToPage(pageIndex - 1); + case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: + parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + newIcon = parent.getChildAt(parent.getChildCount() - 1); + workspace.snapToPage(pageIndex - 1); break; - case KeyEvent.KEYCODE_PAGE_UP: - if (handleKeyEvent) { - // Select the first icon on the previous page or the first icon on this page - // if there is no previous page - if (pageIndex > 0) { - parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); - View newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - // Snap to the previous page - workspace.snapToPage(pageIndex - 1); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } else { - View newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - } - wasHandled = true; + case FocusLogic.NEXT_PAGE_FIRST_ITEM: + parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + newIcon = parent.getChildAt(0); + workspace.snapToPage(pageIndex - 1); break; - case KeyEvent.KEYCODE_PAGE_DOWN: - if (handleKeyEvent) { - // Select the first icon on the next page or the last icon on this page - // if there is no previous page - if (pageIndex < (pageCount - 1)) { - parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); - View newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - // Snap to the next page - workspace.snapToPage(pageIndex + 1); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } else { - View newIcon = getIconInDirection(layout, parent, - parent.getChildCount(), -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } - } - wasHandled = true; + case FocusLogic.CURRENT_PAGE_FIRST_ITEM: + newIcon = parent.getChildAt(0); break; - case KeyEvent.KEYCODE_MOVE_HOME: - if (handleKeyEvent) { - // Select the first icon on this page - View newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - wasHandled = true; + case FocusLogic.CURRENT_PAGE_LAST_ITEM: + newIcon = parent.getChildAt(parent.getChildCount() - 1); break; - case KeyEvent.KEYCODE_MOVE_END: - if (handleKeyEvent) { - // Select the last icon on this page - View newIcon = getIconInDirection(layout, parent, - parent.getChildCount(), -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } + default: + // current page, some item. + if (0 <= newIconIndex && newIconIndex < parent.getChildCount()) { + newIcon = parent.getChildAt(newIconIndex); + } else if (parent.getChildCount() <= newIconIndex && + newIconIndex < parent.getChildCount() + hotseatParent.getChildCount()) { + newIcon = hotseatParent.getChildAt(newIconIndex - parent.getChildCount()); } - wasHandled = true; break; - default: break; } - return wasHandled; + if (newIcon != null) { + newIcon.requestFocus(); + playSoundEffect(keyCode, v); + } + return consume; } /** * Handles key events for items in a Folder. */ static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) { + boolean consume = FocusLogic.shouldConsume(keyCode); + if (e.getAction() == KeyEvent.ACTION_UP || !consume) { + return consume; + } + if (DEBUG) { + Log.v(TAG, String.format("Handle FOLDER keyevent=[%s].", + KeyEvent.keyCodeToString(keyCode))); + } + + // Initialize the variables. ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); final CellLayout layout = (CellLayout) parent.getParent(); final ScrollView scrollView = (ScrollView) layout.getParent(); final Folder folder = (Folder) scrollView.getParent(); View title = folder.mFolderName; + Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); + final int countX = layout.getCountX(); + final int countY = layout.getCountY(); + final int iconIndex = findIndexOfView(parent, v); + int pageIndex = workspace.indexOfChild(layout); + int pageCount = workspace.getChildCount(); + int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order index */ + ); - final int action = e.getAction(); - final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - boolean wasHandled = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (handleKeyEvent) { - // Select the previous icon - View newIcon = getIconInDirection(layout, parent, v, -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); - } + // Process the focus. + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, map, iconIndex, + pageIndex, pageCount); + View newIcon = null; + switch (newIconIndex) { + case FocusLogic.NOOP: + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { + newIcon = title; } - wasHandled = true; break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (handleKeyEvent) { - // Select the next icon - View newIcon = getIconInDirection(layout, parent, v, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - title.requestFocus(); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); + case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: + case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: + case FocusLogic.NEXT_PAGE_FIRST_ITEM: + case FocusLogic.CURRENT_PAGE_FIRST_ITEM: + case FocusLogic.CURRENT_PAGE_LAST_ITEM: + if (DEBUG) { + Log.v(TAG, "Page advance handling not supported on folder icons."); } - wasHandled = true; break; - case KeyEvent.KEYCODE_DPAD_UP: - if (handleKeyEvent) { - // Select the closest icon in the previous line - View newIcon = getClosestIconOnLine(layout, parent, v, -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - wasHandled = true; + default: // current page some item. + newIcon = parent.getChildAt(newIconIndex); + break; + } + if (newIcon != null) { + newIcon.requestFocus(); + playSoundEffect(keyCode, v); + } + return consume; + } + + // + // Helper methods. + // + + /** + * Returns the Viewgroup containing page contents for the page at the index specified. + */ + private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) { + ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index); + if (page instanceof CellLayout) { + // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren + page = ((CellLayout) page).getShortcutsAndWidgets(); + } + return page; + } + + /** + * Private helper method to get the CellLayoutChildren given a CellLayout index. + */ + private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex( + ViewGroup container, int i) { + CellLayout parent = (CellLayout) container.getChildAt(i); + return parent.getShortcutsAndWidgets(); + } + + private static int findIndexOfView(ViewGroup parent, View v) { + for (int i = 0; i < parent.getChildCount(); i++) { + if (v != null && v.equals(parent.getChildAt(i))) { + return i; + } + } + return -1; + } + + /** + * Helper method to be used for playing sound effects. + */ + private static void playSoundEffect(int keyCode, View v) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); break; case KeyEvent.KEYCODE_DPAD_DOWN: - if (handleKeyEvent) { - // Select the closest icon in the next line - View newIcon = getClosestIconOnLine(layout, parent, v, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - title.requestFocus(); - } - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - wasHandled = true; + case KeyEvent.KEYCODE_PAGE_DOWN: + case KeyEvent.KEYCODE_MOVE_END: + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); break; + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_PAGE_UP: case KeyEvent.KEYCODE_MOVE_HOME: - if (handleKeyEvent) { - // Select the first icon on this page - View newIcon = getIconInDirection(layout, parent, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); - } - } - wasHandled = true; + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); break; - case KeyEvent.KEYCODE_MOVE_END: - if (handleKeyEvent) { - // Select the last icon on this page - View newIcon = getIconInDirection(layout, parent, - parent.getChildCount(), -1); - if (newIcon != null) { - newIcon.requestFocus(); - v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); - } - } - wasHandled = true; + default: break; - default: break; } - return wasHandled; } } -- cgit v1.2.3 From 31178b8237ccb6af666df60ef60c116c8afdf316 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 24 Feb 2015 14:12:51 -0800 Subject: [key event focus handling] (1)hotseat <-> icon now symmetric, (2)support DEL keycode TL;DR; (1) Key event navigation from and to the hotseat and icons in the workspace is now symmetric. Since there is one more icon in the hotseat, only left N-1 icon navigation was symmetric. (2) KeyEvent.KEYCODE_DEL and KeyEvent.KEYCODE_FORWARD_DEL can now delete icons from the workspace. The focus move to the previous icon where the focus traveled from. Also contains minor styling and indexing issues. Bug: 15408321 Bug: 19381790 Change-Id: I16cbcb2693e92eebb830997d01c0bf674073dd51 --- src/com/android/launcher3/FocusHelper.java | 72 +++++++++++++++++++----------- 1 file changed, 45 insertions(+), 27 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index c02d73cb6..bdfd7b287 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -170,54 +170,68 @@ public class FocusHelper { // Initialize the variables. final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent(); final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent(); + Hotseat hotseat = (Hotseat) hotseatLayout.getParent(); + Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); int pageIndex = workspace.getCurrentPage(); int pageCount = workspace.getChildCount(); - int countX, countY; + int countX = -1; + int countY = -1; int iconIndex = findIndexOfView(hotseatParent, v); final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex); final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets(); ViewGroup parent = null; - int[][] matrix; + int[][] matrix = null; if (keyCode == KeyEvent.KEYCODE_DPAD_UP && orientation == Configuration.ORIENTATION_PORTRAIT) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation); - // TODO: hotseat indexing should be symmetric. + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + hotseat.getAllAppsButtonRank(), true /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX(); countY = iconLayout.getCountY() + hotseatLayout.getCountY(); parent = iconParent; } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && orientation == Configuration.ORIENTATION_LANDSCAPE) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation); - // TODO: hotseat indexing should be symmetric. + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + hotseat.getAllAppsButtonRank(), true /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX() + hotseatLayout.getCountX(); countY = iconLayout.getCountY(); parent = iconParent; - } else { + } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && + orientation == Configuration.ORIENTATION_LANDSCAPE) { + keyCode = KeyEvent.KEYCODE_PAGE_DOWN; + }else { // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the // matrix extended with hotseat. matrix = FocusLogic.createSparseMatrix(hotseatLayout); - parent = hotseatParent; countX = hotseatLayout.getCountX(); countY = hotseatLayout.getCountY(); - + parent = hotseatParent; } // Process the focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, iconIndex, pageIndex, pageCount); - if (iconParent.getChildCount() <= newIconIndex && - newIconIndex < iconParent.getChildCount() + hotseatParent.getChildCount()) { + View newIcon = null; + if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) { + parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + newIcon = parent.getChildAt(0); + // TODO(hyunyoungs): handle cases where the child is not an icon but + // a folder or a widget. + workspace.snapToPage(pageIndex + 1); + } + if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) { newIconIndex -= iconParent.getChildCount(); } if (parent != null) { - View newIcon = parent.getChildAt(newIconIndex); + if (newIcon == null && newIconIndex >=0) { + newIcon = parent.getChildAt(newIconIndex); + } if (newIcon != null) { newIcon.requestFocus(); playSoundEffect(keyCode, v); @@ -242,34 +256,39 @@ public class FocusHelper { // Initialize the variables. ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); - final CellLayout layout = (CellLayout) parent.getParent(); - final Workspace workspace = (Workspace) layout.getParent(); + final CellLayout iconLayout = (CellLayout) parent.getParent(); + final Workspace workspace = (Workspace) iconLayout.getParent(); final ViewGroup launcher = (ViewGroup) workspace.getParent(); final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar); - final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat); - int pageIndex = workspace.indexOfChild(layout); + final Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat); + int pageIndex = workspace.indexOfChild(iconLayout); int pageCount = workspace.getChildCount(); - final int countX = layout.getCountX(); - int countY = layout.getCountY(); + int countX = iconLayout.getCountX(); + int countY = iconLayout.getCountY(); final int iconIndex = findIndexOfView(parent, v); CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0); ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets(); int[][] matrix; - // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_LEFT in landscape) is the only key allowed + // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended // with the hotseat. if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && orientation == Configuration.ORIENTATION_PORTRAIT) { - matrix = FocusLogic.createSparseMatrix(layout, hotseatLayout, orientation); + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); countY = countY + 1; - } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && + } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && orientation == Configuration.ORIENTATION_LANDSCAPE) { - matrix = FocusLogic.createSparseMatrix(layout, hotseatLayout, orientation); - countY = countY + 1; + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); + countX = countX + 1; + } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) { + workspace.removeWorkspaceItem(v); + return consume; } else { - matrix = FocusLogic.createSparseMatrix(layout); + matrix = FocusLogic.createSparseMatrix(iconLayout); } // Process the focus. @@ -294,7 +313,7 @@ public class FocusHelper { case FocusLogic.NEXT_PAGE_FIRST_ITEM: parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); newIcon = parent.getChildAt(0); - workspace.snapToPage(pageIndex - 1); + workspace.snapToPage(pageIndex + 1); break; case FocusLogic.CURRENT_PAGE_FIRST_ITEM: newIcon = parent.getChildAt(0); @@ -344,8 +363,7 @@ public class FocusHelper { final int iconIndex = findIndexOfView(parent, v); int pageIndex = workspace.indexOfChild(layout); int pageCount = workspace.getChildCount(); - int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order index */ - ); + int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order */); // Process the focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, map, iconIndex, -- cgit v1.2.3 From 38531719636eba7c924e3e71c583ebce2c89a1d0 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 3 Mar 2015 19:25:16 -0800 Subject: [key event focus] DPAD navigates to the nearest item on next/previous page b/19381790 b/16351792 TL;DR;; Previously, when RIGHT is handled on the right most column of the current page or when LEFT is handled on the left most column, the next icon of focus is next page 'first' icon or the previous page 'last icon'. With this change, the row information is preserved when trying to locate an icon to give focus in the next/previous page. Next CL: long awaited unit tests that capture corner cases for different orientation/ device configuration. Change-Id: I5278bed45275b3e4cb39fb698df35f90bb45a415 --- src/com/android/launcher3/FocusHelper.java | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index bdfd7b287..ebb319b0b 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -89,6 +89,7 @@ public class FocusHelper { countX = ((CellLayout) parentLayout).getCountX(); countY = ((CellLayout) parentLayout).getCountY(); } else if (v.getParent() instanceof ViewGroup) { + //TODO(hyunyoungs): figure out when this needs to be called. itemContainer = parentLayout = (ViewGroup) v.getParent(); countX = ((PagedViewGridLayout) parentLayout).getCellCountX(); countY = ((PagedViewGridLayout) parentLayout).getCellCountY(); @@ -102,6 +103,7 @@ public class FocusHelper { final int pageCount = container.getChildCount(); ViewGroup newParent = null; View child = null; + // TODO(hyunyoungs): this matrix is not applicable on the last page. int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true); // Process focus. @@ -111,12 +113,22 @@ public class FocusHelper { return consume; } switch (newIconIndex) { + case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: + newParent = getAppsCustomizePage(container, pageIndex -1); + if (newParent != null) { + int row = FocusLogic.findRow(matrix, iconIndex); + container.snapToPage(pageIndex - 1); + // no need to create a new matrix. + child = newParent.getChildAt(matrix[countX-1][row]); + } + break; case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: newParent = getAppsCustomizePage(container, pageIndex - 1); if (newParent != null) { container.snapToPage(pageIndex - 1); child = newParent.getChildAt(0); } + break; case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: newParent = getAppsCustomizePage(container, pageIndex - 1); if (newParent != null) { @@ -131,6 +143,14 @@ public class FocusHelper { child = newParent.getChildAt(0); } break; + case FocusLogic.NEXT_PAGE_LEFT_COLUMN: + newParent = getAppsCustomizePage(container, pageIndex + 1); + if (newParent != null) { + container.snapToPage(pageIndex + 1); + int row = FocusLogic.findRow(matrix, iconIndex); + child = newParent.getChildAt(matrix[0][row]); + } + break; case FocusLogic.CURRENT_PAGE_FIRST_ITEM: child = container.getChildAt(0); break; @@ -256,7 +276,7 @@ public class FocusHelper { // Initialize the variables. ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); - final CellLayout iconLayout = (CellLayout) parent.getParent(); + CellLayout iconLayout = (CellLayout) parent.getParent(); final Workspace workspace = (Workspace) iconLayout.getParent(); final ViewGroup launcher = (ViewGroup) workspace.getParent(); final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar); @@ -301,10 +321,23 @@ public class FocusHelper { newIcon = tabs; } break; + case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: + int row = FocusLogic.findRow(matrix, iconIndex); + parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + if (parent != null) { + iconLayout = (CellLayout) parent.getParent(); + matrix = FocusLogic.createSparseMatrix(iconLayout, orientation, + iconLayout.getCountX(), row); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, + FocusLogic.PIVOT, pageIndex - 1, pageCount); + newIcon = parent.getChildAt(newIconIndex); + } + break; case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); newIcon = parent.getChildAt(0); workspace.snapToPage(pageIndex - 1); + break; case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); newIcon = parent.getChildAt(parent.getChildCount() - 1); @@ -315,6 +348,17 @@ public class FocusHelper { newIcon = parent.getChildAt(0); workspace.snapToPage(pageIndex + 1); break; + case FocusLogic.NEXT_PAGE_LEFT_COLUMN: + row = FocusLogic.findRow(matrix, iconIndex); + parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + if (parent != null) { + iconLayout = (CellLayout) parent.getParent(); + matrix = FocusLogic.createSparseMatrix(iconLayout, orientation, -1, row); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, + FocusLogic.PIVOT, pageIndex, pageCount); + newIcon = parent.getChildAt(newIconIndex); + } + break; case FocusLogic.CURRENT_PAGE_FIRST_ITEM: newIcon = parent.getChildAt(0); break; -- cgit v1.2.3 From c3a609f950a713d995f1968574d8ed7b4449f415 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 26 Feb 2015 17:43:50 -0800 Subject: Refactoring folder content > Refactoring the CellLayout in folder with a custom view so that it can be replaced easily with a scrollable paged view. > Moving some methods from the folder to this new view which assume a single page layout for the folder > Changing folder from LinearLayout to FrameLayout to properly handle focus traversal in case of multi-page folders Change-Id: I073c00b995488f9f5d8123b00357e094ca2cec7c --- src/com/android/launcher3/FocusHelper.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index bdfd7b287..3ca16d476 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -22,7 +22,6 @@ import android.view.KeyEvent; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; -import android.widget.ScrollView; import com.android.launcher3.util.FocusLogic; @@ -354,8 +353,7 @@ public class FocusHelper { // Initialize the variables. ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); final CellLayout layout = (CellLayout) parent.getParent(); - final ScrollView scrollView = (ScrollView) layout.getParent(); - final Folder folder = (Folder) scrollView.getParent(); + final Folder folder = (Folder) layout.getParent().getParent(); View title = folder.mFolderName; Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); final int countX = layout.getCountX(); -- cgit v1.2.3 From ac721f8d5f869aa8a11cd247fe3ad5a7b3dd47cd Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Wed, 4 Mar 2015 16:33:56 -0800 Subject: Fix the broken build from recent focus navigation handling code (compilation error). Change-Id: I9beb63a88f8c7c247f397d0495501dbc0f637456 --- src/com/android/launcher3/FocusHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index ebb319b0b..c16e45b31 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -326,7 +326,7 @@ public class FocusHelper { parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); if (parent != null) { iconLayout = (CellLayout) parent.getParent(); - matrix = FocusLogic.createSparseMatrix(iconLayout, orientation, + matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, FocusLogic.PIVOT, pageIndex - 1, pageCount); @@ -353,7 +353,7 @@ public class FocusHelper { parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); if (parent != null) { iconLayout = (CellLayout) parent.getParent(); - matrix = FocusLogic.createSparseMatrix(iconLayout, orientation, -1, row); + matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, FocusLogic.PIVOT, pageIndex, pageCount); newIcon = parent.getChildAt(newIconIndex); -- cgit v1.2.3 From 290800b5b7d575fd709f244f54a5fa5b63b58876 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 5 Mar 2015 11:33:33 -0800 Subject: Adding a scrollable folder content implementation > Size is restricted to 3x3 for now > Drag-drop across page s not implemented yet > A-Z sorting is not implemented yet Change-Id: I84328caa6ad910d1edeeac6f3a7fb61b7292ea7e --- src/com/android/launcher3/FocusHelper.java | 45 ++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 737f6cca7..b090a7c3f 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -23,6 +23,7 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; +import com.android.launcher3.FocusHelper.PagedViewKeyListener; import com.android.launcher3.util.FocusLogic; /** @@ -64,10 +65,33 @@ public class FocusHelper { // Key code handling methods. // + /** + * A keyboard listener for scrollable folders + */ + public static class PagedFolderKeyEventListener extends PagedViewKeyListener { + + private final Folder mFolder; + + public PagedFolderKeyEventListener(Folder folder) { + mFolder = folder; + } + + @Override + public void handleNoopKey(int keyCode, View v) { + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { + mFolder.mFolderName.requestFocus(); + playSoundEffect(keyCode, v); + } + } + } + /** * Handles key events in the all apps screen. */ - static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) { + public static class PagedViewKeyListener implements View.OnKeyListener { + + @Override + public boolean onKey(View v, int keyCode, KeyEvent e) { boolean consume = FocusLogic.shouldConsume(keyCode); if (e.getAction() == KeyEvent.ACTION_UP) { return consume; @@ -87,15 +111,14 @@ public class FocusHelper { parentLayout = (ViewGroup) itemContainer.getParent(); countX = ((CellLayout) parentLayout).getCountX(); countY = ((CellLayout) parentLayout).getCountY(); - } else if (v.getParent() instanceof ViewGroup) { - //TODO(hyunyoungs): figure out when this needs to be called. - itemContainer = parentLayout = (ViewGroup) v.getParent(); - countX = ((PagedViewGridLayout) parentLayout).getCellCountX(); - countY = ((PagedViewGridLayout) parentLayout).getCellCountY(); } else { - throw new IllegalStateException( - "Parent of the focused item inside all apps screen is not a supported type."); + if (LauncherAppState.isDogfoodBuild()) { + throw new IllegalStateException("Parent of the focused item is not supported."); + } else { + return false; + } } + final int iconIndex = itemContainer.indexOfChild(v); final PagedView container = (PagedView) parentLayout.getParent(); final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); @@ -109,6 +132,7 @@ public class FocusHelper { int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, iconIndex, pageIndex, pageCount); if (newIconIndex == FocusLogic.NOOP) { + handleNoopKey(keyCode, v); return consume; } switch (newIconIndex) { @@ -163,10 +187,15 @@ public class FocusHelper { if (child != null) { child.requestFocus(); playSoundEffect(keyCode, v); + } else { + handleNoopKey(keyCode, v); } return consume; } + public void handleNoopKey(int keyCode, View v) { } + } + /** * Handles key events in the workspace hot seat (bottom of the screen). *

Currently we don't special case for the phone UI in different orientations, even though -- cgit v1.2.3 From 18bfaafd3da45dce7b5f73eaa1665f228353338c Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 17 Mar 2015 11:32:21 -0700 Subject: key event focus logic should support large tablets TL;DR;; On smaller tablets, landscape = vertical hotseat bar, and portrait = horizontal hotseat bar. However, in larger tablets, hotseat bar is always horizontal. This is now correctly handled using DeviceProfile.isVerticalBar method. b/19732584 Change-Id: I1035c89b4685be12dbc863f8a1465047a5fec6a6 --- src/com/android/launcher3/FocusHelper.java | 43 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index b090a7c3f..fc6895201 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -207,12 +207,13 @@ public class FocusHelper { if (e.getAction() == KeyEvent.ACTION_UP || !consume) { return consume; } - int orientation = v.getResources().getConfiguration().orientation; + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile profile = app.getDynamicGrid().getDeviceProfile(); if (DEBUG) { Log.v(TAG, String.format( - "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, orientation=%d", - KeyEvent.keyCodeToString(keyCode), orientation)); + "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s", + KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout())); } // Initialize the variables. @@ -226,6 +227,8 @@ public class FocusHelper { int countX = -1; int countY = -1; int iconIndex = findIndexOfView(hotseatParent, v); + int iconRank = ((CellLayout.LayoutParams) hotseatLayout.getShortcutsAndWidgets() + .getChildAt(iconIndex).getLayoutParams()).cellX; final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex); final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets(); @@ -234,23 +237,25 @@ public class FocusHelper { int[][] matrix = null; if (keyCode == KeyEvent.KEYCODE_DPAD_UP && - orientation == Configuration.ORIENTATION_PORTRAIT) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, - hotseat.getAllAppsButtonRank(), true /* include all apps icon */); + !profile.isVerticalBarLayout()) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, + true /* hotseat horizontal */, hotseat.getAllAppsButtonRank(), + iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX(); countY = iconLayout.getCountY() + hotseatLayout.getCountY(); parent = iconParent; } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && - orientation == Configuration.ORIENTATION_LANDSCAPE) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, - hotseat.getAllAppsButtonRank(), true /* include all apps icon */); + profile.isVerticalBarLayout()) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, + false /* hotseat horizontal */, hotseat.getAllAppsButtonRank(), + iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX() + hotseatLayout.getCountX(); countY = iconLayout.getCountY(); parent = iconParent; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && - orientation == Configuration.ORIENTATION_LANDSCAPE) { + profile.isVerticalBarLayout()) { keyCode = KeyEvent.KEYCODE_PAGE_DOWN; }else { // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the @@ -296,10 +301,13 @@ public class FocusHelper { if (e.getAction() == KeyEvent.ACTION_UP || !consume) { return consume; } - int orientation = v.getResources().getConfiguration().orientation; + + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile profile = app.getDynamicGrid().getDeviceProfile(); + if (DEBUG) { - Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] orientation=%d", - KeyEvent.keyCodeToString(keyCode), orientation)); + Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s", + KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout())); } // Initialize the variables. @@ -322,14 +330,13 @@ public class FocusHelper { // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended // with the hotseat. - if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && - orientation == Configuration.ORIENTATION_PORTRAIT) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */, hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); countY = countY + 1; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && - orientation == Configuration.ORIENTATION_LANDSCAPE) { - matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, orientation, + profile.isVerticalBarLayout()) { + matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */, hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); countX = countX + 1; } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) { -- cgit v1.2.3 From 091440a9cb9d4f42406631004aa484cbb79214ca Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Wed, 18 Mar 2015 14:16:05 -0700 Subject: Reducing method count by eliminating synthetic accessors Elimates 304 methods based on dex analysis The java compiler generates sythetic accessor methods for all private fields, methods and contructors accessed from inner classes. By marking them package-private and @Thunk instead, sythentic accessor methods are no longer needeed. These annotated elements should be treated as private. Change-Id: Id0dc2c92733474250d8ff12fa793d3a8adeb1f26 --- src/com/android/launcher3/FocusHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index fc6895201..327fac460 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -25,6 +25,7 @@ import android.view.ViewGroup; import com.android.launcher3.FocusHelper.PagedViewKeyListener; import com.android.launcher3.util.FocusLogic; +import com.android.launcher3.util.Thunk; /** * A keyboard listener we set on all the workspace icons. @@ -480,7 +481,7 @@ public class FocusHelper { /** * Returns the Viewgroup containing page contents for the page at the index specified. */ - private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) { + @Thunk static ViewGroup getAppsCustomizePage(ViewGroup container, int index) { ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index); if (page instanceof CellLayout) { // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren @@ -510,7 +511,7 @@ public class FocusHelper { /** * Helper method to be used for playing sound effects. */ - private static void playSoundEffect(int keyCode, View v) { + @Thunk static void playSoundEffect(int keyCode, View v) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); -- cgit v1.2.3 From ada50984dc149c1f4337f965fbb59bdeaac8d09f Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 10 Apr 2015 14:35:23 -0700 Subject: Focus handling - RTL support - Support LEFT and RIGHT keys to work across workspaces when in RTL mode. - Folder icons navigate correctly on DPAD_LEFT/RIGHT events - Folder navigation across pages also works correctly - Deleted dead code inside FocusHelper b/20120358 Change-Id: I7f851cb7ed31f666a91b2f856458d7966ea5f712 --- src/com/android/launcher3/FocusHelper.java | 291 ++++++++++++----------------- 1 file changed, 122 insertions(+), 169 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 327fac460..8791c896a 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -37,16 +37,6 @@ class IconKeyEventListener implements View.OnKeyListener { } } -/** - * A keyboard listener we set on all the workspace icons. - */ -class FolderKeyEventListener implements View.OnKeyListener { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - return FocusHelper.handleFolderKeyEvent(v, keyCode, event); - } -} - /** * A keyboard listener we set on all the hotseat buttons. */ @@ -91,110 +81,120 @@ public class FocusHelper { */ public static class PagedViewKeyListener implements View.OnKeyListener { - @Override - public boolean onKey(View v, int keyCode, KeyEvent e) { - boolean consume = FocusLogic.shouldConsume(keyCode); - if (e.getAction() == KeyEvent.ACTION_UP) { - return consume; - } - if (DEBUG) { - Log.v(TAG, String.format("Handle ALL APPS keyevent=[%s].", - KeyEvent.keyCodeToString(keyCode))); - } + @Override + public boolean onKey(View v, int keyCode, KeyEvent e) { + boolean consume = FocusLogic.shouldConsume(keyCode); + if (e.getAction() == KeyEvent.ACTION_UP) { + return consume; + } + if (DEBUG) { + Log.v(TAG, String.format("Handle ALL APPS and Folders keyevent=[%s].", + KeyEvent.keyCodeToString(keyCode))); + } - // Initialize variables. - ViewGroup parentLayout; - ViewGroup itemContainer; - int countX; - int countY; - if (v.getParent() instanceof ShortcutAndWidgetContainer) { - itemContainer = (ViewGroup) v.getParent(); - parentLayout = (ViewGroup) itemContainer.getParent(); - countX = ((CellLayout) parentLayout).getCountX(); - countY = ((CellLayout) parentLayout).getCountY(); - } else { - if (LauncherAppState.isDogfoodBuild()) { - throw new IllegalStateException("Parent of the focused item is not supported."); + // Initialize variables. + ViewGroup parentLayout; + ViewGroup itemContainer; + int countX; + int countY; + if (v.getParent() instanceof ShortcutAndWidgetContainer) { + itemContainer = (ViewGroup) v.getParent(); + parentLayout = (ViewGroup) itemContainer.getParent(); + countX = ((CellLayout) parentLayout).getCountX(); + countY = ((CellLayout) parentLayout).getCountY(); } else { - return false; + if (LauncherAppState.isDogfoodBuild()) { + throw new IllegalStateException("Parent of the focused item is not supported."); + } else { + return false; + } } - } - - final int iconIndex = itemContainer.indexOfChild(v); - final PagedView container = (PagedView) parentLayout.getParent(); - final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); - final int pageCount = container.getChildCount(); - ViewGroup newParent = null; - View child = null; - // TODO(hyunyoungs): this matrix is not applicable on the last page. - int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true); - // Process focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); - if (newIconIndex == FocusLogic.NOOP) { - handleNoopKey(keyCode, v); + final int iconIndex = itemContainer.indexOfChild(v); + final PagedView container = (PagedView) parentLayout.getParent(); + final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); + final int pageCount = container.getChildCount(); + ViewGroup newParent = null; + View child = null; + // TODO(hyunyoungs): this matrix is not applicable on the last page. + int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true); + + // Process focus. + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, + iconIndex, pageIndex, pageCount); + if (newIconIndex == FocusLogic.NOOP) { + handleNoopKey(keyCode, v); + return consume; + } + switch (newIconIndex) { + case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: + case FocusLogic.NEXT_PAGE_RIGHT_COLUMN: + int newPageIndex = pageIndex - 1; + if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) { + newPageIndex = pageIndex + 1; + } + newParent = getAppsCustomizePage(container, newPageIndex); + if (newParent != null) { + int row = FocusLogic.findRow(matrix, iconIndex); + container.snapToPage(newPageIndex); + // no need to create a new matrix. + child = newParent.getChildAt(matrix[countX-1][row]); + } + break; + case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex - 1); + if (newParent != null) { + container.snapToPage(pageIndex - 1); + child = newParent.getChildAt(0); + } + break; + case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex - 1); + if (newParent != null) { + container.snapToPage(pageIndex - 1); + child = newParent.getChildAt(newParent.getChildCount() - 1); + } + break; + case FocusLogic.NEXT_PAGE_FIRST_ITEM: + newParent = getAppsCustomizePage(container, pageIndex + 1); + if (newParent != null) { + container.snapToPage(pageIndex + 1); + child = newParent.getChildAt(0); + } + break; + case FocusLogic.NEXT_PAGE_LEFT_COLUMN: + case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN: + newPageIndex = pageIndex + 1; + if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) { + newPageIndex = pageIndex -1; + } + newParent = getAppsCustomizePage(container, newPageIndex); + if (newParent != null) { + container.snapToPage(newPageIndex); + int row = FocusLogic.findRow(matrix, iconIndex); + child = newParent.getChildAt(matrix[0][row]); + } + break; + case FocusLogic.CURRENT_PAGE_FIRST_ITEM: + child = container.getChildAt(0); + break; + case FocusLogic.CURRENT_PAGE_LAST_ITEM: + child = itemContainer.getChildAt(itemContainer.getChildCount() - 1); + break; + default: // Go to some item on the current page. + child = itemContainer.getChildAt(newIconIndex); + break; + } + if (child != null) { + child.requestFocus(); + playSoundEffect(keyCode, v); + } else { + handleNoopKey(keyCode, v); + } return consume; } - switch (newIconIndex) { - case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: - newParent = getAppsCustomizePage(container, pageIndex -1); - if (newParent != null) { - int row = FocusLogic.findRow(matrix, iconIndex); - container.snapToPage(pageIndex - 1); - // no need to create a new matrix. - child = newParent.getChildAt(matrix[countX-1][row]); - } - break; - case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex - 1); - if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(0); - } - break; - case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex - 1); - if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(newParent.getChildCount() - 1); - } - break; - case FocusLogic.NEXT_PAGE_FIRST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex + 1); - if (newParent != null) { - container.snapToPage(pageIndex + 1); - child = newParent.getChildAt(0); - } - break; - case FocusLogic.NEXT_PAGE_LEFT_COLUMN: - newParent = getAppsCustomizePage(container, pageIndex + 1); - if (newParent != null) { - container.snapToPage(pageIndex + 1); - int row = FocusLogic.findRow(matrix, iconIndex); - child = newParent.getChildAt(matrix[0][row]); - } - break; - case FocusLogic.CURRENT_PAGE_FIRST_ITEM: - child = container.getChildAt(0); - break; - case FocusLogic.CURRENT_PAGE_LAST_ITEM: - child = itemContainer.getChildAt(itemContainer.getChildCount() - 1); - break; - default: // Go to some item on the current page. - child = itemContainer.getChildAt(newIconIndex); - break; - } - if (child != null) { - child.requestFocus(); - playSoundEffect(keyCode, v); - } else { - handleNoopKey(keyCode, v); - } - return consume; - } - public void handleNoopKey(int keyCode, View v) { } + public void handleNoopKey(int keyCode, View v) { } } /** @@ -209,8 +209,7 @@ public class FocusHelper { return consume; } - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile profile = app.getDynamicGrid().getDeviceProfile(); + DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); if (DEBUG) { Log.v(TAG, String.format( "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s", @@ -358,14 +357,19 @@ public class FocusHelper { } break; case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: + case FocusLogic.NEXT_PAGE_RIGHT_COLUMN: + int newPageIndex = pageIndex - 1; + if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) { + newPageIndex = pageIndex + 1; + } int row = FocusLogic.findRow(matrix, iconIndex); - parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); + parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); if (parent != null) { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, pageIndex - 1, pageCount); + FocusLogic.PIVOT, newPageIndex, pageCount); newIcon = parent.getChildAt(newIconIndex); } break; @@ -385,13 +389,18 @@ public class FocusHelper { workspace.snapToPage(pageIndex + 1); break; case FocusLogic.NEXT_PAGE_LEFT_COLUMN: + case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN: + newPageIndex = pageIndex + 1; + if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) { + newPageIndex = pageIndex - 1; + } row = FocusLogic.findRow(matrix, iconIndex); - parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); + parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); if (parent != null) { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, pageIndex, pageCount); + FocusLogic.PIVOT, newPageIndex, pageCount); newIcon = parent.getChildAt(newIconIndex); } break; @@ -418,62 +427,6 @@ public class FocusHelper { return consume; } - /** - * Handles key events for items in a Folder. - */ - static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) { - boolean consume = FocusLogic.shouldConsume(keyCode); - if (e.getAction() == KeyEvent.ACTION_UP || !consume) { - return consume; - } - if (DEBUG) { - Log.v(TAG, String.format("Handle FOLDER keyevent=[%s].", - KeyEvent.keyCodeToString(keyCode))); - } - - // Initialize the variables. - ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); - final CellLayout layout = (CellLayout) parent.getParent(); - final Folder folder = (Folder) layout.getParent().getParent(); - View title = folder.mFolderName; - Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); - final int countX = layout.getCountX(); - final int countY = layout.getCountY(); - final int iconIndex = findIndexOfView(parent, v); - int pageIndex = workspace.indexOfChild(layout); - int pageCount = workspace.getChildCount(); - int[][] map = FocusLogic.createFullMatrix(countX, countY, true /* incremental order */); - - // Process the focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, map, iconIndex, - pageIndex, pageCount); - View newIcon = null; - switch (newIconIndex) { - case FocusLogic.NOOP: - if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { - newIcon = title; - } - break; - case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: - case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: - case FocusLogic.NEXT_PAGE_FIRST_ITEM: - case FocusLogic.CURRENT_PAGE_FIRST_ITEM: - case FocusLogic.CURRENT_PAGE_LAST_ITEM: - if (DEBUG) { - Log.v(TAG, "Page advance handling not supported on folder icons."); - } - break; - default: // current page some item. - newIcon = parent.getChildAt(newIconIndex); - break; - } - if (newIcon != null) { - newIcon.requestFocus(); - playSoundEffect(keyCode, v); - } - return consume; - } - // // Helper methods. // -- cgit v1.2.3 From b76cd628e657fd050ccf3f4dc31b2e8bc36356e5 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 16 Apr 2015 14:34:09 -0700 Subject: Focus handling null pointer exception during monkey tests. - Also fix a bug where the focus is not navigating to the next page when there isn't an icon within +45 and -45 range of the origin. b/20294717 Change-Id: I16dac5c6a0463fbc9f56a447abedad18abadde98 --- src/com/android/launcher3/FocusHelper.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 8791c896a..32ed98c17 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -222,7 +222,7 @@ public class FocusHelper { Hotseat hotseat = (Hotseat) hotseatLayout.getParent(); Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace); - int pageIndex = workspace.getCurrentPage(); + int pageIndex = workspace.getNextPage(); int pageCount = workspace.getChildCount(); int countX = -1; int countY = -1; @@ -231,6 +231,12 @@ public class FocusHelper { .getChildAt(iconIndex).getLayoutParams()).cellX; final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex); + if (iconLayout == null) { + // This check is to guard against cases where key strokes rushes in when workspace + // child creation/deletion is still in flux. (e.g., during drop or fling + // animation.) + return consume; + } final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets(); ViewGroup parent = null; @@ -364,6 +370,7 @@ public class FocusHelper { } int row = FocusLogic.findRow(matrix, iconIndex); parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); + workspace.snapToPage(newPageIndex); if (parent != null) { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, @@ -394,6 +401,7 @@ public class FocusHelper { if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) { newPageIndex = pageIndex - 1; } + workspace.snapToPage(newPageIndex); row = FocusLogic.findRow(matrix, iconIndex); parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); if (parent != null) { -- cgit v1.2.3 From fc3c1edf7bbc3f7cb23e79520731d13ccc2da046 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 9 Apr 2015 18:48:21 -0700 Subject: Fixing folder focus logic > Folder items no longer remain in a linear order when a folder gets rearranged, and se we need to use createSparseMatrix instead of createFullArray. Also because of this we need to use getChildAt(x, y) instead of getChildAt(index) > Removing traces of AppsCustomizePage (all apps) from FocusHelper Change-Id: I9007f6b95cb823e27ef4a43ce725fda8ef1b7cf8 --- src/com/android/launcher3/FocusHelper.java | 155 +++++++++++------------------ 1 file changed, 56 insertions(+), 99 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 32ed98c17..c77d41657 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -16,14 +16,12 @@ package com.android.launcher3; -import android.content.res.Configuration; import android.util.Log; import android.view.KeyEvent; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; -import com.android.launcher3.FocusHelper.PagedViewKeyListener; import com.android.launcher3.util.FocusLogic; import com.android.launcher3.util.Thunk; @@ -52,14 +50,10 @@ public class FocusHelper { private static final String TAG = "FocusHelper"; private static final boolean DEBUG = false; - // - // Key code handling methods. - // - /** - * A keyboard listener for scrollable folders + * Handles key events in paged folder. */ - public static class PagedFolderKeyEventListener extends PagedViewKeyListener { + public static class PagedFolderKeyEventListener implements View.OnKeyListener { private final Folder mFolder; @@ -67,20 +61,6 @@ public class FocusHelper { mFolder = folder; } - @Override - public void handleNoopKey(int keyCode, View v) { - if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { - mFolder.mFolderName.requestFocus(); - playSoundEffect(keyCode, v); - } - } - } - - /** - * Handles key events in the all apps screen. - */ - public static class PagedViewKeyListener implements View.OnKeyListener { - @Override public boolean onKey(View v, int keyCode, KeyEvent e) { boolean consume = FocusLogic.shouldConsume(keyCode); @@ -88,21 +68,12 @@ public class FocusHelper { return consume; } if (DEBUG) { - Log.v(TAG, String.format("Handle ALL APPS and Folders keyevent=[%s].", + Log.v(TAG, String.format("Handle ALL Folders keyevent=[%s].", KeyEvent.keyCodeToString(keyCode))); } - // Initialize variables. - ViewGroup parentLayout; - ViewGroup itemContainer; - int countX; - int countY; - if (v.getParent() instanceof ShortcutAndWidgetContainer) { - itemContainer = (ViewGroup) v.getParent(); - parentLayout = (ViewGroup) itemContainer.getParent(); - countX = ((CellLayout) parentLayout).getCountX(); - countY = ((CellLayout) parentLayout).getCountY(); - } else { + + if (!(v.getParent() instanceof ShortcutAndWidgetContainer)) { if (LauncherAppState.isDogfoodBuild()) { throw new IllegalStateException("Parent of the focused item is not supported."); } else { @@ -110,15 +81,19 @@ public class FocusHelper { } } + // Initialize variables. + final ShortcutAndWidgetContainer itemContainer = (ShortcutAndWidgetContainer) v.getParent(); + final CellLayout cellLayout = (CellLayout) itemContainer.getParent(); + final int countX = cellLayout.getCountX(); + final int countY = cellLayout.getCountY(); + final int iconIndex = itemContainer.indexOfChild(v); - final PagedView container = (PagedView) parentLayout.getParent(); - final int pageIndex = container.indexToPage(container.indexOfChild(parentLayout)); - final int pageCount = container.getChildCount(); - ViewGroup newParent = null; - View child = null; - // TODO(hyunyoungs): this matrix is not applicable on the last page. - int[][] matrix = FocusLogic.createFullMatrix(countX, countY, true); + final FolderPagedView pagedView = (FolderPagedView) cellLayout.getParent(); + final int pageIndex = pagedView.indexOfChild(cellLayout); + final int pageCount = pagedView.getPageCount(); + + int[][] matrix = FocusLogic.createSparseMatrix(cellLayout); // Process focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, iconIndex, pageIndex, pageCount); @@ -126,60 +101,55 @@ public class FocusHelper { handleNoopKey(keyCode, v); return consume; } + ShortcutAndWidgetContainer newParent = null; + View child = null; + switch (newIconIndex) { case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN: - case FocusLogic.NEXT_PAGE_RIGHT_COLUMN: - int newPageIndex = pageIndex - 1; - if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) { - newPageIndex = pageIndex + 1; - } - newParent = getAppsCustomizePage(container, newPageIndex); + case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN: + newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1); if (newParent != null) { - int row = FocusLogic.findRow(matrix, iconIndex); - container.snapToPage(newPageIndex); - // no need to create a new matrix. - child = newParent.getChildAt(matrix[countX-1][row]); + int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY; + pagedView.snapToPage(pageIndex - 1); + child = newParent.getChildAt( + ((newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) + ^ newParent.invertLayoutHorizontally()) ? 0 : countX - 1, row); } break; case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex - 1); + newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1); if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(0); + pagedView.snapToPage(pageIndex - 1); + child = newParent.getChildAt(0, 0); } break; case FocusLogic.PREVIOUS_PAGE_LAST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex - 1); + newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1); if (newParent != null) { - container.snapToPage(pageIndex - 1); - child = newParent.getChildAt(newParent.getChildCount() - 1); + pagedView.snapToPage(pageIndex - 1); + child = newParent.getChildAt(countX - 1, countY - 1); } break; case FocusLogic.NEXT_PAGE_FIRST_ITEM: - newParent = getAppsCustomizePage(container, pageIndex + 1); + newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1); if (newParent != null) { - container.snapToPage(pageIndex + 1); - child = newParent.getChildAt(0); + pagedView.snapToPage(pageIndex + 1); + child = newParent.getChildAt(0, 0); } break; case FocusLogic.NEXT_PAGE_LEFT_COLUMN: - case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN: - newPageIndex = pageIndex + 1; - if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) { - newPageIndex = pageIndex -1; - } - newParent = getAppsCustomizePage(container, newPageIndex); + case FocusLogic.NEXT_PAGE_RIGHT_COLUMN: + newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1); if (newParent != null) { - container.snapToPage(newPageIndex); - int row = FocusLogic.findRow(matrix, iconIndex); - child = newParent.getChildAt(matrix[0][row]); + pagedView.snapToPage(pageIndex + 1); + child = FocusLogic.getAdjacentChildInNextPage(newParent, v, newIconIndex); } break; case FocusLogic.CURRENT_PAGE_FIRST_ITEM: - child = container.getChildAt(0); + child = cellLayout.getChildAt(0, 0); break; case FocusLogic.CURRENT_PAGE_LAST_ITEM: - child = itemContainer.getChildAt(itemContainer.getChildCount() - 1); + child = pagedView.getLastItem(); break; default: // Go to some item on the current page. child = itemContainer.getChildAt(newIconIndex); @@ -194,7 +164,12 @@ public class FocusHelper { return consume; } - public void handleNoopKey(int keyCode, View v) { } + public void handleNoopKey(int keyCode, View v) { + if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { + mFolder.mFolderName.requestFocus(); + playSoundEffect(keyCode, v); + } + } } /** @@ -226,7 +201,7 @@ public class FocusHelper { int pageCount = workspace.getChildCount(); int countX = -1; int countY = -1; - int iconIndex = findIndexOfView(hotseatParent, v); + int iconIndex = hotseatParent.indexOfChild(v); int iconRank = ((CellLayout.LayoutParams) hotseatLayout.getShortcutsAndWidgets() .getChildAt(iconIndex).getLayoutParams()).cellX; @@ -323,11 +298,12 @@ public class FocusHelper { final ViewGroup launcher = (ViewGroup) workspace.getParent(); final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar); final Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat); - int pageIndex = workspace.indexOfChild(iconLayout); - int pageCount = workspace.getChildCount(); + + final int iconIndex = parent.indexOfChild(v); + final int pageIndex = workspace.indexOfChild(iconLayout); + final int pageCount = workspace.getChildCount(); int countX = iconLayout.getCountX(); int countY = iconLayout.getCountY(); - final int iconIndex = findIndexOfView(parent, v); CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0); ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets(); @@ -368,10 +344,11 @@ public class FocusHelper { if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) { newPageIndex = pageIndex + 1; } - int row = FocusLogic.findRow(matrix, iconIndex); + int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY; parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); workspace.snapToPage(newPageIndex); if (parent != null) { + workspace.snapToPage(newPageIndex); iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); @@ -402,9 +379,10 @@ public class FocusHelper { newPageIndex = pageIndex - 1; } workspace.snapToPage(newPageIndex); - row = FocusLogic.findRow(matrix, iconIndex); + row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY; parent = getCellLayoutChildrenForIndex(workspace, newPageIndex); if (parent != null) { + workspace.snapToPage(newPageIndex); iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, @@ -439,18 +417,6 @@ public class FocusHelper { // Helper methods. // - /** - * Returns the Viewgroup containing page contents for the page at the index specified. - */ - @Thunk static ViewGroup getAppsCustomizePage(ViewGroup container, int index) { - ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index); - if (page instanceof CellLayout) { - // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren - page = ((CellLayout) page).getShortcutsAndWidgets(); - } - return page; - } - /** * Private helper method to get the CellLayoutChildren given a CellLayout index. */ @@ -460,15 +426,6 @@ public class FocusHelper { return parent.getShortcutsAndWidgets(); } - private static int findIndexOfView(ViewGroup parent, View v) { - for (int i = 0; i < parent.getChildCount(); i++) { - if (v != null && v.equals(parent.getChildAt(i))) { - return i; - } - } - return -1; - } - /** * Helper method to be used for playing sound effects. */ -- cgit v1.2.3 From c393b0765df8d2d34b3b996b71700a705b7d0106 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 20 May 2015 15:03:13 -0700 Subject: Fixing issue where the prediction bar apps are not focused. - Also fixes issue where all apps is not accessible by keyboard when there are no other apps in the hotseat. Bug: 21334471 --- src/com/android/launcher3/FocusHelper.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index c77d41657..678ed0f82 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -314,12 +314,14 @@ public class FocusHelper { // with the hotseat. if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */, - hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); + hotseat.getAllAppsButtonRank(), + !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); countY = countY + 1; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */, - hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */); + hotseat.getAllAppsButtonRank(), + !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); countX = countX + 1; } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) { workspace.removeWorkspaceItem(v); -- cgit v1.2.3 From 2e6da1539bc7286336b3c24d96ab76434939ce4d Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Wed, 6 May 2015 11:42:25 -0700 Subject: Refactoring DeviceProfile -> Pulling out the parts of device profile which can (and need to be) initialized and accessed without access to an Activity context, ie. the invariant bits. -> The invariant bits are stored in InvariantDeviceProfile which is initialized statically from LauncherAppState. -> The DeviceProfile contains the Activity context-dependent bits, and we will create one of these for each Activity instance, and this instance is accessed through the Launcher activity. -> It's possible that we can continue to refactor this such that all appropriate dimensions can be computed without an Activity context (by only specifying orientation). This would be an extension of this CL and allow us to know exactly how launcher will look in both orientations from any context. Sets the stage for some improvements around b/19514688 Change-Id: Ia7daccf14d8ca2b9cb340b8780b684769e9f1892 --- src/com/android/launcher3/FocusHelper.java | 35 ++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 678ed0f82..fe50e3a4e 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -92,11 +92,13 @@ public class FocusHelper { final int pageIndex = pagedView.indexOfChild(cellLayout); final int pageCount = pagedView.getPageCount(); + Launcher launcher = (Launcher) v.getContext(); int[][] matrix = FocusLogic.createSparseMatrix(cellLayout); // Process focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, + launcher.getDeviceProfile().isLayoutRtl); if (newIconIndex == FocusLogic.NOOP) { handleNoopKey(keyCode, v); return consume; @@ -184,7 +186,8 @@ public class FocusHelper { return consume; } - DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + DeviceProfile profile = ((Launcher) v.getContext()).getDeviceProfile(); + if (DEBUG) { Log.v(TAG, String.format( "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s", @@ -248,8 +251,8 @@ public class FocusHelper { } // Process the focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); View newIcon = null; if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) { @@ -283,8 +286,8 @@ public class FocusHelper { return consume; } - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile profile = app.getDynamicGrid().getDeviceProfile(); + Launcher launcher = (Launcher) v.getContext(); + DeviceProfile profile = launcher.getDeviceProfile(); if (DEBUG) { Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s", @@ -295,9 +298,9 @@ public class FocusHelper { ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); CellLayout iconLayout = (CellLayout) parent.getParent(); final Workspace workspace = (Workspace) iconLayout.getParent(); - final ViewGroup launcher = (ViewGroup) workspace.getParent(); - final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar); - final Hotseat hotseat = (Hotseat) launcher.findViewById(R.id.hotseat); + final ViewGroup dragLayer = (ViewGroup) workspace.getParent(); + final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.search_drop_target_bar); + final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat); final int iconIndex = parent.indexOfChild(v); final int pageIndex = workspace.indexOfChild(iconLayout); @@ -331,8 +334,8 @@ public class FocusHelper { } // Process the focus. - int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, countY, matrix, - iconIndex, pageIndex, pageCount); + int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, + countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); View newIcon = null; switch (newIconIndex) { case FocusLogic.NOOP: @@ -354,8 +357,8 @@ public class FocusHelper { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); - newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, newPageIndex, pageCount); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); newIcon = parent.getChildAt(newIconIndex); } break; @@ -387,8 +390,8 @@ public class FocusHelper { workspace.snapToPage(newPageIndex); iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); - newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, matrix, - FocusLogic.PIVOT, newPageIndex, pageCount); + newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); newIcon = parent.getChildAt(newIconIndex); } break; -- cgit v1.2.3 From c6205603efe1f2987caf96504c87d720a25b5a94 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 21 May 2015 20:46:33 -0700 Subject: Creating landscape and portrait device profiles at app initialization Change-Id: Ide9d007adc36b348e19b05cdf49e87f8b02db60e --- src/com/android/launcher3/FocusHelper.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index fe50e3a4e..46e4902f9 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -92,13 +92,12 @@ public class FocusHelper { final int pageIndex = pagedView.indexOfChild(cellLayout); final int pageCount = pagedView.getPageCount(); - Launcher launcher = (Launcher) v.getContext(); + final boolean isLayoutRtl = Utilities.isRtl(v.getResources()); int[][] matrix = FocusLogic.createSparseMatrix(cellLayout); // Process focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, - countY, matrix, iconIndex, pageIndex, pageCount, - launcher.getDeviceProfile().isLayoutRtl); + countY, matrix, iconIndex, pageIndex, pageCount, isLayoutRtl); if (newIconIndex == FocusLogic.NOOP) { handleNoopKey(keyCode, v); return consume; @@ -252,7 +251,7 @@ public class FocusHelper { // Process the focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, - countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); + countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources())); View newIcon = null; if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) { @@ -335,7 +334,7 @@ public class FocusHelper { // Process the focus. int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX, - countY, matrix, iconIndex, pageIndex, pageCount, profile.isLayoutRtl); + countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources())); View newIcon = null; switch (newIconIndex) { case FocusLogic.NOOP: @@ -358,7 +357,8 @@ public class FocusHelper { matrix = FocusLogic.createSparseMatrix(iconLayout, iconLayout.getCountX(), row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, - matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, + Utilities.isRtl(v.getResources())); newIcon = parent.getChildAt(newIconIndex); } break; @@ -391,7 +391,8 @@ public class FocusHelper { iconLayout = (CellLayout) parent.getParent(); matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row); newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY, - matrix, FocusLogic.PIVOT, newPageIndex, pageCount, profile.isLayoutRtl); + matrix, FocusLogic.PIVOT, newPageIndex, pageCount, + Utilities.isRtl(v.getResources())); newIcon = parent.getChildAt(newIconIndex); } break; -- cgit v1.2.3 From 316490e636aad788fcfbfc2e04dd4f0e145bdd00 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 2 Jun 2015 09:38:28 -0700 Subject: Removing some synthetic method creation > Make package-private and @Thunk all private methods and constructors accessed from inner classes. Change-Id: Ie5913860a0c33e48e9bf68f9b5b1699f64c2f174 --- src/com/android/launcher3/FocusHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 46e4902f9..70bb01af0 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -426,7 +426,7 @@ public class FocusHelper { /** * Private helper method to get the CellLayoutChildren given a CellLayout index. */ - private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex( + @Thunk static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex( ViewGroup container, int i) { CellLayout parent = (CellLayout) container.getChildAt(i); return parent.getShortcutsAndWidgets(); -- cgit v1.2.3 From 4f3e9383eb422c87e2689548653b89f34f5516a5 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 5 Jun 2015 00:13:25 -0700 Subject: Code cleanup > Removing obsolete logging > Removing unused methods > Removing resource leak warning due to non-static handler class in launcher Change-Id: Ic38cc8aea82899b0b5ee3235f04e5964e49245fb --- src/com/android/launcher3/FocusHelper.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/com/android/launcher3/FocusHelper.java') diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index 70bb01af0..57aec3280 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -222,8 +222,8 @@ public class FocusHelper { if (keyCode == KeyEvent.KEYCODE_DPAD_UP && !profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, - true /* hotseat horizontal */, hotseat.getAllAppsButtonRank(), - iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */); + true /* hotseat horizontal */, profile.inv.hotseatAllAppsRank, + iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX(); countY = iconLayout.getCountY() + hotseatLayout.getCountY(); @@ -231,8 +231,8 @@ public class FocusHelper { } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, - false /* hotseat horizontal */, hotseat.getAllAppsButtonRank(), - iconRank == hotseat.getAllAppsButtonRank() /* include all apps icon */); + false /* hotseat horizontal */, profile.inv.hotseatAllAppsRank, + iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */); iconIndex += iconParent.getChildCount(); countX = iconLayout.getCountX() + hotseatLayout.getCountX(); countY = iconLayout.getCountY(); @@ -316,13 +316,13 @@ public class FocusHelper { // with the hotseat. if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */, - hotseat.getAllAppsButtonRank(), + profile.inv.hotseatAllAppsRank, !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); countY = countY + 1; } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && profile.isVerticalBarLayout()) { matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */, - hotseat.getAllAppsButtonRank(), + profile.inv.hotseatAllAppsRank, !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */); countX = countX + 1; } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) { -- cgit v1.2.3