Merge "Fixing crash when trying to reset focused task after removing task."
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 34353bc..063bb3e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -284,6 +284,20 @@
     }
 
     /**
+     * Dismisses recents back to the launch target task.
+     */
+    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchPreviousTask()) return true;
+            // If none of the other cases apply, then just go Home
+            dismissRecentsToHome(true);
+        }
+        return false;
+    }
+
+    /**
      * Dismisses recents if we are already visible and the intent is to toggle the recents view.
      */
     boolean dismissRecentsToFocusedTaskOrHome() {
@@ -566,9 +580,8 @@
 
     @Override
     public void onBackPressed() {
-        if (!dismissHistory()) {
-            dismissRecentsToFocusedTaskOrHome();
-        }
+        // Back behaves like the recents button so just trigger a toggle event
+        EventBus.getDefault().send(new ToggleRecentsEvent());
     }
 
     /**** RecentsResizeTaskDialog ****/
@@ -584,7 +597,12 @@
 
     public final void onBusEvent(ToggleRecentsEvent event) {
         if (!dismissHistory()) {
-            dismissRecentsToFocusedTaskOrHome();
+            RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
+            if (launchState.launchedFromHome) {
+                dismissRecentsToHome(true);
+            } else {
+                dismissRecentsToLaunchTargetTaskOrHome();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 381ffc9..530cd2d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -199,8 +199,11 @@
     /** Task stack callbacks */
     public interface TaskStackCallbacks {
         /* Notifies when a task has been removed from the stack */
-        void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-                                       Task newFrontMostTask);
+        void onStackTaskRemoved(TaskStack stack, Task removedTask, int removedTaskIndex,
+                boolean wasFrontMostTask, Task newFrontMostTask);
+
+        /* Notifies when a task has been removed from the history */
+        void onHistoryTaskRemoved(TaskStack stack, Task removedTask);
     }
 
     /**
@@ -382,6 +385,7 @@
     public void removeTask(Task t) {
         if (mStackTaskList.contains(t)) {
             boolean wasFrontMostTask = (getStackFrontMostTask() == t);
+            int removedTaskIndex = indexOfStackTask(t);
             removeTaskImpl(mStackTaskList, t);
             Task newFrontMostTask = getStackFrontMostTask();
             if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
@@ -389,13 +393,14 @@
             }
             if (mCb != null) {
                 // Notify that a task has been removed
-                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
+                mCb.onStackTaskRemoved(this, t, removedTaskIndex, wasFrontMostTask,
+                        newFrontMostTask);
             }
         } else if (mHistoryTaskList.contains(t)) {
             removeTaskImpl(mHistoryTaskList, t);
             if (mCb != null) {
                 // Notify that a task has been removed
-                mCb.onStackTaskRemoved(this, t, false, null);
+                mCb.onHistoryTaskRemoved(this, t);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index a3a9e5a..96b1a41 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -308,12 +308,6 @@
      */
     private static AppTransitionAnimationSpec composeAnimationSpec(TaskView taskView,
             TaskViewTransform transform, boolean addHeaderBitmap) {
-        // Disable any focused state before we draw the header
-        // Upfront the processing of the thumbnail
-        if (taskView.isFocusedTask()) {
-            taskView.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-        }
-
         Bitmap b = null;
         if (addHeaderBitmap) {
             float scale = transform.scale;
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 551f067..0911578 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -213,6 +213,21 @@
         return false;
     }
 
+    /** Launches the task that recents was launched from if possible */
+    public boolean launchPreviousTask() {
+        if (mTaskStackView != null) {
+            TaskStack stack = mTaskStackView.getStack();
+            Task task = stack.getLaunchTarget();
+            if (task != null) {
+                TaskView taskView = mTaskStackView.getChildViewForTask(task);
+                onTaskViewClicked(mTaskStackView, taskView, stack, task, false, null,
+                        INVALID_STACK_ID);
+                return true;
+            }
+        }
+        return false;
+    }
+
     /** Launches a given task. */
     public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
         if (mTaskStackView != null) {
@@ -471,9 +486,6 @@
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
 
             // Remove the task after it is docked
-            if (event.taskView.isFocusedTask()) {
-                mTaskStackView.resetFocusedTask();
-            }
             event.taskView.animate()
                     .alpha(0f)
                     .setDuration(150)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index d9e352d..6dc380c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -658,7 +658,8 @@
         transformOut.rect.set(mTaskRect);
         transformOut.rect.offset(transformOut.translationX, transformOut.translationY);
         Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
-        transformOut.visible = true;
+        transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
+                (frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
         transformOut.clipBottom = 0;
         transformOut.clipRight = 0;
         transformOut.thumbnailScale = 1f;
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 ae6cc46..d45fba2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -280,7 +280,7 @@
     /** Resets this TaskStackView for reuse. */
     void reset() {
         // Reset the focused task
-        resetFocusedTask();
+        resetFocusedTask(getFocusedTask());
 
         // Return all the views to the pool
         List<TaskView> taskViews = getTaskViews();
@@ -426,7 +426,6 @@
             // Return all the invisible children to the pool
             mTmpTaskViewMap.clear();
             List<TaskView> taskViews = getTaskViews();
-            boolean wasLastFocusedTaskAnimated = false;
             int lastFocusedTaskIndex = -1;
             int taskViewCount = taskViews.size();
             for (int i = taskViewCount - 1; i >= 0; i--) {
@@ -437,10 +436,9 @@
                         visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) {
                     mTmpTaskViewMap.put(task, tv);
                 } else {
-                    if (mTouchExplorationEnabled && tv.isFocusedTask()) {
-                        wasLastFocusedTaskAnimated = tv.isFocusAnimated();
+                    if (mTouchExplorationEnabled) {
                         lastFocusedTaskIndex = taskIndex;
-                        resetFocusedTask();
+                        resetFocusedTask(task);
                     }
                     if (DEBUG) {
                         Log.d(TAG, "returning to pool: " + task.key);
@@ -467,6 +465,21 @@
                     if (mLayersDisabled) {
                         tv.disableLayersForOneFrame();
                     }
+                } else {
+                    // Reattach it in the right z order
+                    detachViewFromParent(tv);
+                    int insertIndex = -1;
+                    int taskIndex = mStack.indexOfStackTask(task);
+                    taskViews = getTaskViews();
+                    taskViewCount = taskViews.size();
+                    for (int j = 0; j < taskViewCount; j++) {
+                        Task tvTask = taskViews.get(j).getTask();
+                        if (taskIndex <= mStack.indexOfStackTask(tvTask)) {
+                            insertIndex = j;
+                            break;
+                        }
+                    }
+                    attachViewToParent(tv, insertIndex, tv.getLayoutParams());
                 }
 
                 // Animate the task into place
@@ -474,21 +487,6 @@
                         mStackViewsAnimationDuration, mFastOutSlowInInterpolator,
                         mRequestUpdateClippingListener);
 
-                // Reattach it in the right z order
-                detachViewFromParent(tv);
-                int insertIndex = -1;
-                int taskIndex = mStack.indexOfStackTask(task);
-                taskViews = getTaskViews();
-                taskViewCount = taskViews.size();
-                for (int j = 0; j < taskViewCount; j++) {
-                    Task tvTask = taskViews.get(j).getTask();
-                    if (taskIndex < mStack.indexOfStackTask(tvTask)) {
-                        insertIndex = j;
-                        break;
-                    }
-                }
-                attachViewToParent(tv, insertIndex, tv.getLayoutParams());
-
                 // Update the task views list after adding the new task view
                 updateTaskViewsList();
             }
@@ -538,9 +536,11 @@
             // Update the focus if the previous focused task was returned to the view pool
             if (lastFocusedTaskIndex != -1) {
                 if (lastFocusedTaskIndex < visibleStackRange[1]) {
-                    setFocusedTask(visibleStackRange[1], false, wasLastFocusedTaskAnimated);
+                    setFocusedTask(visibleStackRange[1], false /* animated */,
+                            true /* requestViewFocus */);
                 } else {
-                    setFocusedTask(visibleStackRange[0], false, wasLastFocusedTaskAnimated);
+                    setFocusedTask(visibleStackRange[0], false /* animated */,
+                            true /* requestViewFocus */);
                 }
             }
 
@@ -653,7 +653,7 @@
         if (mFocusedTaskIndex != -1) {
             Task focusedTask = mStack.getStackTasks().get(mFocusedTaskIndex);
             if (focusedTask != newFocusedTask) {
-                resetFocusedTask();
+                resetFocusedTask(focusedTask);
             }
         }
 
@@ -777,10 +777,9 @@
     /**
      * Resets the focused task.
      */
-    void resetFocusedTask() {
-        if (mFocusedTaskIndex != -1) {
-            Task t = mStack.getStackTasks().get(mFocusedTaskIndex);
-            TaskView tv = getChildViewForTask(t);
+    void resetFocusedTask(Task task) {
+        if (task != null) {
+            TaskView tv = getChildViewForTask(task);
             if (tv != null) {
                 tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
             }
@@ -1183,8 +1182,12 @@
     /**** TaskStackCallbacks Implementation ****/
 
     @Override
-    public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
-            Task newFrontMostTask) {
+    public void onStackTaskRemoved(TaskStack stack, Task removedTask, int removedTaskIndex,
+            boolean wasFrontMostTask, Task newFrontMostTask) {
+        if (mFocusedTaskIndex == removedTaskIndex) {
+            resetFocusedTask(removedTask);
+        }
+
         if (!removedTask.isFreeformTask()) {
             // Remove the view associated with this task, we can't rely on updateTransforms
             // to work here because the task is no longer in the list
@@ -1260,6 +1263,11 @@
         }
     }
 
+    @Override
+    public void onHistoryTaskRemoved(TaskStack stack, Task removedTask) {
+        // To be implemented
+    }
+
     /**** ViewPoolConsumer Implementation ****/
 
     @Override
@@ -1282,6 +1290,9 @@
         // Reset the view properties
         tv.resetViewProperties();
 
+        // Reset the focused view state
+        tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
+
         // Reset the clip state of the task view
         tv.setClipViewInStack(false);
     }
@@ -1332,6 +1343,9 @@
         tv.setCallbacks(this);
         tv.setTouchEnabled(true);
         tv.setClipViewInStack(true);
+        if (mFocusedTaskIndex == taskIndex) {
+            tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
+        }
     }
 
     @Override
@@ -1553,11 +1567,6 @@
     private void removeTaskViewFromStack(TaskView tv) {
         Task task = tv.getTask();
 
-        // Reset the previously focused task before it is removed from the stack
-        if (tv.isFocusedTask()) {
-            resetFocusedTask();
-        }
-
         // Announce for accessibility
         tv.announceForAccessibility(getContext().getString(
                 R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel));
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 6fdfe62..1baa1a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -78,8 +78,6 @@
 
     Task mTask;
     boolean mTaskDataLoaded;
-    boolean mIsFocused;
-    boolean mIsFocusAnimated;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
     private AnimatorSet mClipAnimation;
@@ -640,14 +638,12 @@
     public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) {
         if (DEBUG) {
             Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused +
-                    " mIsFocused: " + mIsFocused + " animated: " + animated +
-                    " requestViewFocus: " + requestViewFocus + " isFocused(): " + isFocused() +
+                    " animated: " + animated + " requestViewFocus: " + requestViewFocus +
+                    " isFocused(): " + isFocused() +
                     " isAccessibilityFocused(): " + isAccessibilityFocused());
         }
 
         SystemServicesProxy ssp = Recents.getSystemServices();
-        mIsFocused = isFocused;
-        mIsFocusAnimated = animated;
         mHeaderView.onTaskViewFocusChanged(isFocused, animated);
         if (isFocused) {
             if (requestViewFocus && !isFocused()) {
@@ -663,20 +659,6 @@
         }
     }
 
-    /**
-     * Returns whether we have explicitly been focused.
-     */
-    public boolean isFocusedTask() {
-        return mIsFocused;
-    }
-
-    /**
-     * Returns whether this focused task is animated.
-     */
-    public boolean isFocusAnimated() {
-        return mIsFocusAnimated;
-    }
-
     public void disableLayersForOneFrame() {
         mHeaderView.disableLayersForOneFrame();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 85b4b9b..ec59f31 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -55,6 +55,8 @@
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
+    private static final float FOCUS_TRANSLATION_Z = 4f;
+
     Task mTask;
 
     // Header views
@@ -367,13 +369,14 @@
         Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
 
         if (focused) {
-            // If we are not animating the visible state, just return
-            if (!animateFocusedState) return;
-
-            // Bump up the translation
-            mFocusAnimator = ObjectAnimator.ofFloat(this, "translationZ", 8f);
-            mFocusAnimator.setDuration(200);
-            mFocusAnimator.start();
+            if (animateFocusedState) {
+                // Bump up the translation
+                mFocusAnimator = ObjectAnimator.ofFloat(this, "translationZ", FOCUS_TRANSLATION_Z);
+                mFocusAnimator.setDuration(200);
+                mFocusAnimator.start();
+            } else {
+                setTranslationZ(FOCUS_TRANSLATION_Z);
+            }
         } else {
             if (isRunning) {
                 // Restore the translation