Fixing some bugs in Recents keyboard behaviour.

- Ensuring that we don't allow meta-tab to trigger Recents (since meta is a system key now)
- Adding dpad keys support to traverse stack
- Adding workaround for cases where tasks wouldn't be focused depending on how you launch Recents

Change-Id: I4101ced7e47e0d1659d5fa236214be5697c00560
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 95edd1c..4c52b24 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -147,7 +147,9 @@
                 }
             } else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) {
                 // Try and start the enter animation (or restart it on configuration changed)
-                mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenOverlayView));
+                ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null);
+                mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(
+                        mFullScreenOverlayView, t));
                 // Call our callback
                 onEnterAnimationTriggered();
             }
@@ -392,7 +394,9 @@
 
     void onConfigurationChange() {
         // Try and start the enter animation (or restart it on configuration changed)
-        mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenOverlayView));
+        ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
+        mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(
+                mFullScreenOverlayView, t));
         // Call our callback
         onEnterAnimationTriggered();
     }
@@ -536,6 +540,12 @@
             final boolean backward = event.isShiftPressed();
             mRecentsView.focusNextTask(!backward);
             return true;
+        } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+            mRecentsView.focusNextTask(true);
+            return true;
+        } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+            mRecentsView.focusNextTask(false);
+            return true;
         }
         // Pass through the debug trigger
         mDebugTrigger.onKeyEvent(keyCode);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index e7eac67..b5b9cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -186,6 +186,10 @@
 
     /** Requests all task stacks to start their enter-recents animation */
     public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
+        // Handle the case when there are no views by incrementing and decrementing after all
+        // animations are started.
+        ctx.postAnimationTrigger.increment();
+
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -194,6 +198,10 @@
                 stackView.startEnterRecentsAnimation(ctx);
             }
         }
+
+        // Handle the case when there are no views by incrementing and decrementing after all
+        // animations are started.
+        ctx.postAnimationTrigger.decrement();
     }
 
     /** Requests all task stacks to start their exit-recents animation */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 29eaa9e..2c05daa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -747,9 +747,6 @@
             // Mark that we have completely the first layout
             mAwaitingFirstLayout = false;
 
-            // Start dozing
-            mUIDozeTrigger.startDozing();
-
             // Prepare the first view for its enter animation
             int offsetTopAlign = -mStackAlgorithm.mTaskRect.top;
             int offscreenY = mStackAlgorithm.mRect.bottom -
@@ -770,7 +767,11 @@
 
             // Update the focused task index to be the next item to the top task
             if (mConfig.launchedWithAltTab) {
+                // When alt-tabbing, we focus the next previous task
                 focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
+            } else {
+                // Normally we just focus the front task
+                focusTask(Math.max(0, mStack.getTaskCount() - 1), false);
             }
         }
     }
@@ -799,6 +800,15 @@
                     mStack.indexOfTask(tv.getTask()), getStackScroll());
             tv.startEnterRecentsAnimation(ctx);
         }
+
+        // Add a runnable to the post animation ref counter to clear all the views
+        ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                // Start dozing
+                mUIDozeTrigger.startDozing();
+            }
+        });
     }
 
     /** Requests this task stacks to start it's exit-recents animation. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index b1fc700..c6bacbd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
@@ -296,7 +298,7 @@
     }
 
     /** Animates this task view as it enters recents */
-    public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
+    public void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
         TaskViewTransform transform = ctx.transform;
 
         if (mConfig.launchedFromAppWithScreenshot) {
@@ -308,6 +310,8 @@
                         // Animate the task bar of the first task view
                         mBarView.startEnterRecentsAnimation(0, mEnableThumbnailClip);
                         setVisibility(View.VISIBLE);
+                        // Decrement the post animation trigger
+                        ctx.postAnimationTrigger.decrement();
                     }
                 });
             } else {
@@ -321,9 +325,17 @@
                         .setInterpolator(mConfig.linearOutSlowInInterpolator)
                         .setDuration(475)
                         .withLayer()
-                        .withEndAction(mEnableThumbnailClip)
+                        .withEndAction(new Runnable() {
+                            @Override
+                            public void run() {
+                                mEnableThumbnailClip.run();
+                                // Decrement the post animation trigger
+                                ctx.postAnimationTrigger.decrement();
+                            }
+                        })
                         .start();
             }
+            ctx.postAnimationTrigger.increment();
 
         } else if (mConfig.launchedFromAppWithThumbnail) {
             if (ctx.isFrontMost) {
@@ -335,7 +347,15 @@
                 anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
                 anim.setDuration(mConfig.taskBarEnterAnimDuration);
                 anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        // Decrement the post animation trigger
+                        ctx.postAnimationTrigger.decrement();
+                    }
+                });
                 anim.start();
+                ctx.postAnimationTrigger.increment();
             } else {
                 mEnableThumbnailClip.run();
             }
@@ -355,8 +375,16 @@
                     .setInterpolator(mConfig.quintOutInterpolator)
                     .setDuration(mConfig.taskViewEnterFromHomeDuration)
                     .withLayer()
-                    .withEndAction(mEnableThumbnailClip)
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mEnableThumbnailClip.run();
+                            // Decrement the post animation trigger
+                            ctx.postAnimationTrigger.decrement();
+                        }
+                    })
                     .start();
+            ctx.postAnimationTrigger.increment();
         }
     }
 
@@ -518,7 +546,12 @@
      */
     public void setFocusedTask() {
         mIsFocused = true;
+        // Workaround, we don't always want it focusable in touch mode, but we want the first task
+        // to be focused after the enter-recents animation, which can be triggered from either touch
+        // or keyboard
+        setFocusableInTouchMode(true);
         requestFocus();
+        setFocusableInTouchMode(false);
         invalidate();
         mCb.onTaskFocused(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index 13407aa..fa97d2c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -38,9 +38,13 @@
         int stackViewCount;
         // Whether this is the front most task view
         boolean isFrontMost;
+        // A trigger to run some logic when all the animations complete.  This works around the fact
+        // that it is difficult to coordinate ViewPropertyAnimators
+        ReferenceCountedTrigger postAnimationTrigger;
 
-        public TaskViewEnterContext(FullscreenTransitionOverlayView fss) {
+        public TaskViewEnterContext(FullscreenTransitionOverlayView fss, ReferenceCountedTrigger t) {
             fullScreenshot = fss;
+            postAnimationTrigger = t;
         }
     }