am 71113e43: Merge "Reset the task stack instead of the view when Recents is hidden. (Bug. 18436876, Bug. 18394126, Bug. 18432310)" into lmp-mr1-dev

* commit '71113e43e768d973b3721f8fac9f9654ed159911':
  Reset the task stack instead of the view when Recents is hidden. (Bug. 18436876, Bug. 18394126, Bug. 18432310)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 38ce467..29f291d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -170,7 +170,8 @@
     /** Hides the recents */
     public void onHideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
         if (mBootCompleted) {
-            if (isRecentsTopMost(getTopMostTask(), null)) {
+            ActivityManager.RunningTaskInfo topTask = getTopMostTask();
+            if (topTask != null && isRecentsTopMost(topTask, null)) {
                 // Notify recents to hide itself
                 Intent intent = new Intent(ACTION_HIDE_RECENTS_ACTIVITY);
                 intent.setPackage(mContext.getPackageName());
@@ -217,6 +218,8 @@
         if (stack.getTaskCount() == 0) return;
 
         ActivityManager.RunningTaskInfo runningTask = getTopMostTask();
+        // Return early if there is no running task (can't determine affiliated tasks in this case)
+        if (runningTask == null) return;
         // Return early if the running task is in the home stack (optimization)
         if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
 
@@ -369,8 +372,8 @@
         // If Recents is the front most activity, then we should just communicate with it directly
         // to launch the first task or dismiss itself
         ActivityManager.RunningTaskInfo topTask = getTopMostTask();
-        AtomicBoolean isTopTaskHome = new AtomicBoolean();
-        if (isRecentsTopMost(topTask, isTopTaskHome)) {
+        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
+        if (topTask != null && isRecentsTopMost(topTask, isTopTaskHome)) {
             // Notify recents to toggle itself
             Intent intent = new Intent(ACTION_TOGGLE_RECENTS_ACTIVITY);
             intent.setPackage(mContext.getPackageName());
@@ -389,8 +392,8 @@
     void startRecentsActivity() {
         // Check if the top task is in the home stack, and start the recents activity
         ActivityManager.RunningTaskInfo topTask = getTopMostTask();
-        AtomicBoolean isTopTaskHome = new AtomicBoolean();
-        if (!isRecentsTopMost(topTask, isTopTaskHome)) {
+        AtomicBoolean isTopTaskHome = new AtomicBoolean(true);
+        if (topTask == null || !isRecentsTopMost(topTask, isTopTaskHome)) {
             startRecentsActivity(topTask, isTopTaskHome.get());
         }
     }
@@ -504,7 +507,7 @@
         TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
                 mDummyStackView.computeStackVisibilityReport();
         boolean hasRecentTasks = stack.getTaskCount() > 0;
-        boolean useThumbnailTransition = !isTopTaskHome && hasRecentTasks;
+        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
 
         if (useThumbnailTransition) {
             // Ensure that we load the running task's icon
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 a37b9e6..255d642 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -61,6 +61,14 @@
         }
     }
 
+    /** Resets this FilteredTaskList. */
+    void reset() {
+        mTasks.clear();
+        mFilteredTasks.clear();
+        mTaskIndices.clear();
+        mFilter = null;
+    }
+
     /** Removes the task filter and returns the previous touch state */
     void removeFilter() {
         mFilter = null;
@@ -190,6 +198,14 @@
         mCb = cb;
     }
 
+    /** Resets this TaskStack. */
+    public void reset() {
+        mCb = null;
+        mTaskList.reset();
+        mGroups.clear();
+        mAffinitiesGroups.clear();
+    }
+
     /** Adds a new task */
     public void addTask(Task t) {
         mTaskList.add(t);
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 77a050a..46a5d8d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -65,7 +65,6 @@
     ArrayList<TaskStack> mStacks;
     View mSearchBar;
     RecentsViewCallbacks mCb;
-    boolean mAlreadyLaunchingTask;
 
     public RecentsView(Context context) {
         super(context);
@@ -121,7 +120,10 @@
 
         // Update the stack views that we are keeping
         for (int i = 0; i < numTaskStacksToKeep; i++) {
-            stackViews.get(i).setStack(stacks.get(i));
+            TaskStackView tsv = stackViews.get(i);
+            // If onRecentsHidden is not triggered, we need to the stack view again here
+            tsv.reset();
+            tsv.setStack(stacks.get(i));
         }
 
         // Add remaining/recreate stack views
@@ -144,8 +146,6 @@
             }
         }
 
-        // Reset the launched state
-        mAlreadyLaunchingTask = false;
         // Trigger a new layout
         requestLayout();
     }
@@ -402,11 +402,6 @@
         if (mCb != null) {
             mCb.onTaskViewClicked();
         }
-        // Skip if we are already launching tasks
-        if (mAlreadyLaunchingTask) {
-            return;
-        }
-        mAlreadyLaunchingTask = true;
 
         // Upfront the processing of the thumbnail
         TaskViewTransform transform = new TaskViewTransform();
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 5732879..2623db3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -132,21 +132,13 @@
 
     /** Sets the task stack */
     void setStack(TaskStack stack) {
-        // Unset the old stack
-        if (mStack != null) {
-            mStack.setCallbacks(null);
-
-            // Return all existing views to the pool
-            reset();
-            // Layout again with the new stack
-            requestLayout();
-        }
-
         // Set the new stack
         mStack = stack;
         if (mStack != null) {
             mStack.setCallbacks(this);
         }
+        // Layout again with the new stack
+        requestLayout();
     }
 
     /** Sets the debug overlay */
@@ -178,6 +170,7 @@
         }
 
         // Reset the stack state
+        mStack.reset();
         mStackViewsDirty = true;
         mStackViewsClipDirty = true;
         mAwaitingFirstLayout = true;
@@ -239,11 +232,6 @@
                                        float stackScroll,
                                        int[] visibleRangeOut,
                                        boolean boundTranslationsToRect) {
-        // XXX: We should be intelligent about where to look for the visible stack range using the
-        //      current stack scroll.
-        // XXX: We should log extra cases like the ones below where we don't expect to hit very often
-        // XXX: Print out approximately how many indices we have to go through to find the first visible transform
-
         int taskTransformCount = taskTransforms.size();
         int taskCount = tasks.size();
         int frontMostVisibleIndex = -1;
@@ -295,20 +283,6 @@
         return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1;
     }
 
-    /**
-     * Gets the stack transforms of a list of tasks, and returns the visible range of tasks. This
-     * call is less optimal than calling updateStackTransforms directly.
-     */
-    private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
-                                                            float stackScroll,
-                                                            int[] visibleRangeOut,
-                                                            boolean boundTranslationsToRect) {
-        ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
-        updateStackTransforms(taskTransforms, tasks, stackScroll, visibleRangeOut,
-                boundTranslationsToRect);
-        return taskTransforms;
-    }
-
     /** Synchronizes the views with the model */
     boolean synchronizeStackViewsWithModel() {
         if (mStackViewsDirty) {
@@ -440,8 +414,6 @@
     /** Updates the min and max virtual scroll bounds */
     void updateMinMaxScroll(boolean boundScrollToNewMinMax, boolean launchedWithAltTab,
             boolean launchedFromHome) {
-        if (mStack == null) return;
-
         // Compute the min and max scroll values
         mLayoutAlgorithm.computeMinMaxScroll(mStack.getTasks(), launchedWithAltTab, launchedFromHome);
 
@@ -498,7 +470,7 @@
     }
 
     /**
-     * Ensures that there is a task focused, if nothign is focused, then we will use the task
+     * Ensures that there is a task focused, if nothing is focused, then we will use the task
      * at the center of the visible stack.
      */
     public boolean ensureFocusedTask() {
@@ -545,8 +517,11 @@
 
     /** Dismisses the focused task. */
     public void dismissFocusedTask() {
-        // Return early if there is no focused task index
-        if (mFocusedTaskIndex < 0) return;
+        // Return early if the focused task index is invalid
+        if (mFocusedTaskIndex < 0 || mFocusedTaskIndex >= mStack.getTaskCount()) {
+            mFocusedTaskIndex = -1;
+            return;
+        }
 
         Task t = mStack.getTasks().get(mFocusedTaskIndex);
         TaskView tv = getChildViewForTask(t);
@@ -567,8 +542,6 @@
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        if (mStack == null) return;
-
         int childCount = getChildCount();
         if (childCount > 0) {
             TaskView backMostTask = (TaskView) getChildAt(0);
@@ -599,8 +572,6 @@
 
     @Override
     public void computeScroll() {
-        if (mStack == null) return;
-
         mStackScroller.computeScroll();
         // Synchronize the views
         synchronizeStackViewsWithModel();
@@ -643,11 +614,6 @@
      */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mStack == null) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
@@ -660,10 +626,9 @@
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately to load all the views
         if (mAwaitingFirstLayout) {
-            if (mStackScroller.setStackScrollToInitialState()) {
-                requestSynchronizeStackViewsWithModel();
-                synchronizeStackViewsWithModel();
-            }
+            mStackScroller.setStackScrollToInitialState();
+            requestSynchronizeStackViewsWithModel();
+            synchronizeStackViewsWithModel();
         }
 
         // Measure each of the TaskViews
@@ -694,11 +659,6 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mStack == null) {
-            super.onLayout(changed, left, top, right, bottom);
-            return;
-        }
-
         // Layout each of the children
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -856,7 +816,7 @@
 
     /** Final callback after Recents is finally hidden. */
     void onRecentsHidden() {
-        setStack(null);
+        reset();
     }
 
     public boolean isTransformedTouchPointInView(float x, float y, View child) {
@@ -1030,8 +990,6 @@
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) {
-        if (mStack == null) return;
-
         // It is possible for a view to be returned to the view pool before it is laid out,
         // which means that we will need to relayout the view when it is first used next.
         boolean requiresRelayout = tv.getWidth() <= 0 && !isNewView;
@@ -1170,8 +1128,6 @@
 
     @Override
     public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
-        if (mStack == null) return;
-
         // Compute which components need to be removed
         HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved(
                 mStack.getTaskKeys(), packageName, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 5767e18..26fbbf4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -274,6 +274,7 @@
 
     /** Returns the scroll to such task top = 1f; */
     float getStackScrollForTask(Task t) {
+        if (!mTaskProgressMap.containsKey(t.key)) return 0f;
         return mTaskProgressMap.get(t.key);
     }
 
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 d42fa15..de5974f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -350,7 +350,7 @@
             public void run() {
                 enableFocusAnimations();
             }
-        }, (startDelay / 2));
+        }, startDelay);
     }
 
     public void fadeInActionButton(int delay, int duration) {
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 1e5d9fc..464d007 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -69,6 +69,7 @@
     RippleDrawable mBackground;
     GradientDrawable mBackgroundColorDrawable;
     AnimatorSet mFocusAnimator;
+    String mDismissContentDescription;
 
     // Static highlight that we draw at the top of each view
     static Paint sHighlightPaint;
@@ -105,6 +106,8 @@
         Resources res = context.getResources();
         mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
         mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
+        mDismissContentDescription =
+                res.getString(R.string.accessibility_recents_item_will_be_dismissed);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
@@ -127,14 +130,6 @@
 
     @Override
     protected void onFinishInflate() {
-        // Set the outline provider
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
-            }
-        });
-
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
@@ -217,9 +212,8 @@
                 mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
-        mDismissButton.setContentDescription(
-                getContext().getString(R.string.accessibility_recents_item_will_be_dismissed,
-                        t.activityLabel));
+        mDismissButton.setContentDescription(String.format(mDismissContentDescription,
+                t.activityLabel));
     }
 
     /** Unbinds the bar view from the task */
@@ -307,7 +301,7 @@
             int currentColor = mBackgroundColor;
             int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
-                    lightPrimaryColor, currentColor);
+                    currentColor, lightPrimaryColor);
             backgroundColor.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationStart(Animator animation) {