Fullscreen pages (e.g. Now) are focusable via keyboard.

Change-Id: I962551651aeb9ac7b57bb51b195adc3140db30d8
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index b243da3..44a8ec5 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -45,6 +45,23 @@
     }
 }
 
+/**
+ * A keyboard listener we set on full screen pages (e.g. custom content).
+ */
+class FullscreenKeyEventListener implements View.OnKeyListener {
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
+                || keyCode == KeyEvent.KEYCODE_PAGE_DOWN || keyCode == KeyEvent.KEYCODE_PAGE_UP) {
+            // Handle the key event just like a workspace icon would in these cases. In this case,
+            // it will basically act as if there is a single icon in the top left (so you could
+            // think of the fullscreen page as a focusable fullscreen widget).
+            return FocusHelper.handleIconKeyEvent(v, keyCode, event);
+        }
+        return false;
+    }
+}
+
 public class FocusHelper {
 
     private static final String TAG = "FocusHelper";
@@ -287,18 +304,32 @@
             case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
                 // Go to the previous page but keep the focus on the same hotseat icon.
                 workspace.snapToPage(pageIndex - 1);
+                // If the page we are going to is fullscreen, have it take the focus from hotseat.
+                CellLayout prevPage = (CellLayout) workspace.getPageAt(pageIndex - 1);
+                boolean isPrevPageFullscreen = ((CellLayout.LayoutParams) prevPage
+                        .getShortcutsAndWidgets().getChildAt(0).getLayoutParams()).isFullscreen;
+                if (isPrevPageFullscreen) {
+                    workspace.getPageAt(pageIndex - 1).requestFocus();
+                }
                 break;
             case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
             case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
                 // Go to the next page but keep the focus on the same hotseat icon.
                 workspace.snapToPage(pageIndex + 1);
+                // If the page we are going to is fullscreen, have it take the focus from hotseat.
+                CellLayout nextPage = (CellLayout) workspace.getPageAt(pageIndex + 1);
+                boolean isNextPageFullscreen = ((CellLayout.LayoutParams) nextPage
+                        .getShortcutsAndWidgets().getChildAt(0).getLayoutParams()).isFullscreen;
+                if (isNextPageFullscreen) {
+                    workspace.getPageAt(pageIndex + 1).requestFocus();
+                }
                 break;
         }
         if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
             newIconIndex -= iconParent.getChildCount();
         }
         if (parent != null) {
-            if (newIcon == null && newIconIndex >=0) {
+            if (newIcon == null && newIconIndex >= 0) {
                 newIcon = parent.getChildAt(newIconIndex);
             }
             if (newIcon != null) {
@@ -413,6 +444,7 @@
                 workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex - 1);
                 newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
                 if (newIcon == null) {
+                    // Check the hotseat if no focusable item was found on the workspace.
                     newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
                     workspace.snapToPage(pageIndex - 1);
                 }
@@ -451,12 +483,14 @@
             case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
                 newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
                 if (newIcon == null) {
+                    // Check the hotseat if no focusable item was found on the workspace.
                     newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
                 }
                 break;
             case FocusLogic.CURRENT_PAGE_LAST_ITEM:
                 newIcon = getFirstFocusableIconInReverseReadingOrder(workspaceLayout, isRtl);
                 if (newIcon == null) {
+                    // Check the hotseat if no focusable item was found on the workspace.
                     newIcon = getFirstFocusableIconInReverseReadingOrder(hotseatLayout, isRtl);
                 }
                 break;
@@ -536,9 +570,13 @@
 
     private static View handlePreviousPageLastItem(Workspace workspace, CellLayout hotseatLayout,
             int pageIndex, boolean isRtl) {
+        if (pageIndex - 1 < 0) {
+            return null;
+        }
         CellLayout workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex - 1);
         View newIcon = getFirstFocusableIconInReverseReadingOrder(workspaceLayout, isRtl);
         if (newIcon == null) {
+            // Check the hotseat if no focusable item was found on the workspace.
             newIcon = getFirstFocusableIconInReverseReadingOrder(hotseatLayout,isRtl);
             workspace.snapToPage(pageIndex - 1);
         }
@@ -547,9 +585,13 @@
 
     private static View handleNextPageFirstItem(Workspace workspace, CellLayout hotseatLayout,
             int pageIndex, boolean isRtl) {
+        if (pageIndex + 1 >= workspace.getPageCount()) {
+            return null;
+        }
         CellLayout workspaceLayout = (CellLayout) workspace.getChildAt(pageIndex + 1);
         View newIcon = getFirstFocusableIconInReadingOrder(workspaceLayout, isRtl);
         if (newIcon == null) {
+            // Check the hotseat if no focusable item was found on the workspace.
             newIcon = getFirstFocusableIconInReadingOrder(hotseatLayout, isRtl);
             workspace.snapToPage(pageIndex + 1);
         }