Fixing AllAppsCustomize Keyboard Accessibility / NPE (issue 5483485)

Change-Id: I841823e28bf419028afea2a57352c4ad45c7c4a0
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index 4718b31..5ed20a7 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -1200,6 +1200,11 @@
         return getChildAt(getChildCount() - index - 1);
     }
 
+    @Override
+    protected int indexToPage(int index) {
+        return getChildCount() - index - 1;
+    }
+
     // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
     @Override
     protected void screenScrolled(int screenCenter) {
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
index 404b088..593712a 100644
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -224,6 +224,7 @@
                         }
                         mAppsCustomizePane.loadAssociatedPages(
                                 mAppsCustomizePane.getCurrentPage());
+                        mAppsCustomizePane.requestFocus();
                     }
                 });
                 AnimatorSet animSet = new AnimatorSet();
diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java
index 967b02f..1a7416a 100644
--- a/src/com/android/launcher2/FocusHelper.java
+++ b/src/com/android/launcher2/FocusHelper.java
@@ -125,18 +125,30 @@
     }
 
     /**
+     * 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 PagedViewCellLayout) {
+            // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
+            page = (ViewGroup) page.getChildAt(0);
+        }
+        return page;
+    }
+
+    /**
      * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
      */
     static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
             KeyEvent e) {
 
         final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
-        final ViewGroup container = (ViewGroup) parent.getParent();
+        final PagedView container = (PagedView) parent.getParent();
         final TabHost tabHost = findTabHostParent(container);
         final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
         final int widgetIndex = parent.indexOfChild(w);
         final int widgetCount = parent.getChildCount();
-        final int pageIndex = container.indexOfChild(parent);
+        final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent));
         final int pageCount = container.getChildCount();
         final int cellCountX = parent.getCellCountX();
         final int cellCountY = parent.getCellCountY();
@@ -145,7 +157,7 @@
 
         final int action = e.getAction();
         final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        PagedViewGridLayout newParent = null;
+        ViewGroup newParent = null;
         // Now that we load items in the bg asynchronously, we can't just focus
         // child siblings willy-nilly
         View child = null;
@@ -158,10 +170,11 @@
                         parent.getChildAt(widgetIndex - 1).requestFocus();
                     } else {
                         if (pageIndex > 0) {
-                            newParent = (PagedViewGridLayout)
-                                    container.getChildAt(pageIndex - 1);
-                            child = newParent.getChildAt(newParent.getChildCount() - 1);
-                            if (child != null) child.requestFocus();
+                            newParent = getAppsCustomizePage(container, pageIndex - 1);
+                            if (newParent != null) {
+                                child = newParent.getChildAt(newParent.getChildCount() - 1);
+                                if (child != null) child.requestFocus();
+                            }
                         }
                     }
                 }
@@ -174,10 +187,11 @@
                         parent.getChildAt(widgetIndex + 1).requestFocus();
                     } else {
                         if (pageIndex < (pageCount - 1)) {
-                            newParent = (PagedViewGridLayout)
-                                    container.getChildAt(pageIndex + 1);
-                            child = newParent.getChildAt(0);
-                            if (child != null) child.requestFocus();
+                            newParent = getAppsCustomizePage(container, pageIndex + 1);
+                            if (newParent != null) {
+                                child = newParent.getChildAt(0);
+                                if (child != null) child.requestFocus();
+                            }
                         }
                     }
                 }
@@ -221,8 +235,10 @@
                     // Select the first item on the previous page, or the first item on this page
                     // if there is no previous page
                     if (pageIndex > 0) {
-                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex - 1);
-                        child = newParent.getChildAt(0);
+                        newParent = getAppsCustomizePage(container, pageIndex - 1);
+                        if (newParent != null) {
+                            child = newParent.getChildAt(0);
+                        }
                     } else {
                         child = parent.getChildAt(0);
                     }
@@ -235,8 +251,10 @@
                     // Select the first item on the next page, or the last item on this page
                     // if there is no next page
                     if (pageIndex < (pageCount - 1)) {
-                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex + 1);
-                        child = newParent.getChildAt(0);
+                        newParent = getAppsCustomizePage(container, pageIndex + 1);
+                        if (newParent != null) {
+                            child = newParent.getChildAt(0);
+                        }
                     } else {
                         child = parent.getChildAt(widgetCount - 1);
                     }
@@ -265,38 +283,40 @@
     }
 
     /**
-     * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout
-     * index.
-     */
-    private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex(
-            ViewGroup container, int i) {
-        ViewGroup parent = (ViewGroup) container.getChildAt(i);
-        return (PagedViewCellLayoutChildren) parent.getChildAt(0);
-    }
-
-    /**
      * Handles key events in a PageViewCellLayout containing PagedViewIcons.
      */
-    static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) {
-        final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent();
-        final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent();
+    static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
+        ViewGroup parentLayout;
+        ViewGroup itemContainer;
+        int countX;
+        int countY;
+        if (v.getParent() instanceof PagedViewCellLayoutChildren) {
+            itemContainer = (ViewGroup) v.getParent();
+            parentLayout = (ViewGroup) itemContainer.getParent();
+            countX = ((PagedViewCellLayout) parentLayout).getCellCountX();
+            countY = ((PagedViewCellLayout) parentLayout).getCellCountY();
+        } else {
+            itemContainer = parentLayout = (ViewGroup) v.getParent();
+            countX = ((PagedViewGridLayout) parentLayout).getCellCountX();
+            countY = ((PagedViewGridLayout) parentLayout).getCellCountY();
+        }
+
         // Note we have an extra parent because of the
         // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
-        final ViewGroup container = (ViewGroup) parentLayout.getParent();
+        final PagedView container = (PagedView) parentLayout.getParent();
         final TabHost tabHost = findTabHostParent(container);
         final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
-        final int iconIndex = parent.indexOfChild(v);
-        final int widgetCount = parent.getChildCount();
-        final int pageIndex = container.indexOfChild(parentLayout);
+        final int iconIndex = itemContainer.indexOfChild(v);
+        final int itemCount = itemContainer.getChildCount();
+        final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
         final int pageCount = container.getChildCount();
-        final int cellCountX = parentLayout.getCellCountX();
-        final int cellCountY = parentLayout.getCellCountY();
-        final int x = iconIndex % cellCountX;
-        final int y = iconIndex / cellCountX;
+
+        final int x = iconIndex % countX;
+        final int y = iconIndex / countX;
 
         final int action = e.getAction();
         final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        PagedViewCellLayoutChildren newParent = null;
+        ViewGroup newParent = null;
         // Side pages do not always load synchronously, so check before focusing child siblings
         // willy-nilly
         View child = null;
@@ -306,12 +326,12 @@
                 if (handleKeyEvent) {
                     // Select the previous icon or the last icon on the previous page
                     if (iconIndex > 0) {
-                        parent.getChildAt(iconIndex - 1).requestFocus();
+                        itemContainer.getChildAt(iconIndex - 1).requestFocus();
                     } else {
                         if (pageIndex > 0) {
-                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
-                                    pageIndex - 1);
+                            newParent = getAppsCustomizePage(container, pageIndex - 1);
                             if (newParent != null) {
+                                container.snapToPage(pageIndex - 1);
                                 child = newParent.getChildAt(newParent.getChildCount() - 1);
                                 if (child != null) child.requestFocus();
                             }
@@ -323,13 +343,13 @@
             case KeyEvent.KEYCODE_DPAD_RIGHT:
                 if (handleKeyEvent) {
                     // Select the next icon or the first icon on the next page
-                    if (iconIndex < (widgetCount - 1)) {
-                        parent.getChildAt(iconIndex + 1).requestFocus();
+                    if (iconIndex < (itemCount - 1)) {
+                        itemContainer.getChildAt(iconIndex + 1).requestFocus();
                     } else {
                         if (pageIndex < (pageCount - 1)) {
-                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
-                                    pageIndex + 1);
+                            newParent = getAppsCustomizePage(container, pageIndex + 1);
                             if (newParent != null) {
+                                container.snapToPage(pageIndex + 1);
                                 child = newParent.getChildAt(0);
                                 if (child != null) child.requestFocus();
                             }
@@ -342,8 +362,8 @@
                 if (handleKeyEvent) {
                     // Select the closest icon in the previous row, otherwise select the tab bar
                     if (y > 0) {
-                        int newiconIndex = ((y - 1) * cellCountX) + x;
-                        parent.getChildAt(newiconIndex).requestFocus();
+                        int newiconIndex = ((y - 1) * countX) + x;
+                        itemContainer.getChildAt(newiconIndex).requestFocus();
                     } else {
                         tabs.requestFocus();
                     }
@@ -353,9 +373,9 @@
             case KeyEvent.KEYCODE_DPAD_DOWN:
                 if (handleKeyEvent) {
                     // Select the closest icon in the previous row, otherwise do nothing
-                    if (y < (cellCountY - 1)) {
-                        int newiconIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
-                        parent.getChildAt(newiconIndex).requestFocus();
+                    if (y < (countY - 1)) {
+                        int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x);
+                        itemContainer.getChildAt(newiconIndex).requestFocus();
                     }
                 }
                 wasHandled = true;
@@ -374,14 +394,14 @@
                     // Select the first icon on the previous page, or the first icon on this page
                     // if there is no previous page
                     if (pageIndex > 0) {
-                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
-                                pageIndex - 1);
+                        newParent = getAppsCustomizePage(container, pageIndex - 1);
                         if (newParent != null) {
+                            container.snapToPage(pageIndex - 1);
                             child = newParent.getChildAt(0);
                             if (child != null) child.requestFocus();
                         }
                     } else {
-                        parent.getChildAt(0).requestFocus();
+                        itemContainer.getChildAt(0).requestFocus();
                     }
                 }
                 wasHandled = true;
@@ -391,14 +411,14 @@
                     // Select the first icon on the next page, or the last icon on this page
                     // if there is no next page
                     if (pageIndex < (pageCount - 1)) {
-                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
-                                pageIndex + 1);
+                        newParent = getAppsCustomizePage(container, pageIndex + 1);
                         if (newParent != null) {
+                            container.snapToPage(pageIndex + 1);
                             child = newParent.getChildAt(0);
                             if (child != null) child.requestFocus();
                         }
                     } else {
-                        parent.getChildAt(widgetCount - 1).requestFocus();
+                        itemContainer.getChildAt(itemCount - 1).requestFocus();
                     }
                 }
                 wasHandled = true;
@@ -406,14 +426,14 @@
             case KeyEvent.KEYCODE_MOVE_HOME:
                 if (handleKeyEvent) {
                     // Select the first icon on this page
-                    parent.getChildAt(0).requestFocus();
+                    itemContainer.getChildAt(0).requestFocus();
                 }
                 wasHandled = true;
                 break;
             case KeyEvent.KEYCODE_MOVE_END:
                 if (handleKeyEvent) {
                     // Select the last icon on this page
-                    parent.getChildAt(widgetCount - 1).requestFocus();
+                    itemContainer.getChildAt(itemCount - 1).requestFocus();
                 }
                 wasHandled = true;
                 break;
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 8121d3b..7be19bf 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -270,6 +270,10 @@
         return getChildAt(index);
     }
 
+    protected int indexToPage(int index) {
+        return index;
+    }
+
     /**
      * Updates the scroll of the current page immediately to its final scroll position.  We use this
      * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
@@ -714,7 +718,7 @@
 
     @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
-        int page = indexOfChild(child);
+        int page = indexToPage(indexOfChild(child));
         if (page != mCurrentPage || !mScroller.isFinished()) {
             snapToPage(page);
             return true;
@@ -1287,7 +1291,7 @@
     @Override
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
-        int page = indexOfChild(child);
+        int page = indexToPage(indexOfChild(child));
         if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
             snapToPage(page);
         }
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index 3ae978d..3cc7786 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -156,13 +156,13 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+        return FocusHelper.handleAppsCustomizeKeyEvent(this, keyCode, event)
                 || super.onKeyDown(keyCode, event);
     }
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+        return FocusHelper.handleAppsCustomizeKeyEvent(this, keyCode, event)
                 || super.onKeyUp(keyCode, event);
     }
 
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 4d5fd7b..12c98b2 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -167,13 +167,13 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+        return FocusHelper.handleAppsCustomizeKeyEvent(this, keyCode, event)
                 || super.onKeyDown(keyCode, event);
     }
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+        return FocusHelper.handleAppsCustomizeKeyEvent(this, keyCode, event)
                 || super.onKeyUp(keyCode, event);
     }