Ensuring that null thumbnails have an opaque background.

- Preventing multiple object allocations when updating the stack/clip state.
- Removing double animation of nav bar when launching task

Change-Id: Id12009717135db67bc0ce0e05940dd1c8d6fb5b3
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 1d355cd..53a4b10 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -48,7 +48,7 @@
             // For debugging, this defines the number of mock recents packages to create
             public static final int SystemServicesProxyMockPackageCount = 3;
             // For debugging, this defines the number of mock recents tasks to create
-            public static final int SystemServicesProxyMockTaskCount = 75;
+            public static final int SystemServicesProxyMockTaskCount = 100;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index dce8f57..75ff2b9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -605,14 +605,9 @@
     }
 
     @Override
-    public void onTaskLaunching(boolean isTaskInStackBounds) {
+    public void onTaskLaunching() {
         mTaskLaunched = true;
 
-        // Fade out the scrim
-        if (!isTaskInStackBounds && mConfig.hasNavBarScrim()) {
-            onExitAnimationTriggered();
-        }
-
         // Mark recents as no longer visible
         AlternateRecentsComponent.notifyVisibilityChanged(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index a02e1a7b..7762111 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -118,6 +118,7 @@
     TaskResourceLoadQueue mLoadQueue;
     DrawableLruCache mApplicationIconCache;
     BitmapLruCache mThumbnailCache;
+    Bitmap mDefaultThumbnail;
 
     boolean mCancelled;
     boolean mWaitingOnLoadQueue;
@@ -125,10 +126,12 @@
     /** Constructor, creates a new loading thread that loads task resources in the background */
     public TaskResourceLoader(TaskResourceLoadQueue loadQueue,
                               DrawableLruCache applicationIconCache,
-                              BitmapLruCache thumbnailCache) {
+                              BitmapLruCache thumbnailCache,
+                              Bitmap defaultThumbnail) {
         mLoadQueue = loadQueue;
         mApplicationIconCache = applicationIconCache;
         mThumbnailCache = thumbnailCache;
+        mDefaultThumbnail = defaultThumbnail;
         mMainThreadHandler = new Handler();
         mLoadThread = new HandlerThread("Recents-TaskResourceLoader");
         mLoadThread.setPriority(Thread.NORM_PRIORITY - 1);
@@ -238,6 +241,7 @@
                                 loadThumbnail = thumbnail;
                                 mThumbnailCache.put(t.key, thumbnail);
                             } else {
+                                loadThumbnail = mDefaultThumbnail;
                                 Console.logError(mContext,
                                         "Failed to load task top thumbnail for: " +
                                                 t.key.baseIntent.getComponent().getPackageName());
@@ -330,6 +334,7 @@
 
     BitmapDrawable mDefaultApplicationIcon;
     Bitmap mDefaultThumbnail;
+    Bitmap mLoadingThumbnail;
 
     /** Private Constructor */
     private RecentsTaskLoader(Context context) {
@@ -356,18 +361,22 @@
         mLoadQueue = new TaskResourceLoadQueue();
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
-        mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache);
+        mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
+                mDefaultThumbnail);
 
         // Create the default assets
         Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         icon.eraseColor(0x00000000);
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        mDefaultThumbnail.eraseColor(0x00000000);
+        mDefaultThumbnail.eraseColor(0xFFffffff);
+        mLoadingThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        mLoadingThumbnail.eraseColor(0x00000000);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
         if (Console.Enabled) {
             Console.log(Constants.Log.App.TaskDataLoader,
                     "[RecentsTaskLoader|defaultBitmaps]",
-                    "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+                    "icon: " + mDefaultApplicationIcon +
+                    " default thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
         }
     }
 
@@ -394,7 +403,7 @@
 
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> tasks =
-                ssp.getRecentTasks(100, UserHandle.CURRENT.getIdentifier());
+                ssp.getRecentTasks(50, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
         if (Console.Enabled) {
             Console.log(Constants.Log.App.TimeSystemCalls,
@@ -544,7 +553,7 @@
             requiresLoad = true;
         }
         if (thumbnail == null) {
-            thumbnail = mDefaultThumbnail;
+            thumbnail = mLoadingThumbnail;
             requiresLoad = true;
         }
         if (requiresLoad) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
index c861d2c..cadfc56 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,8 +50,8 @@
     FullScreenTransitionViewCallbacks mCb;
 
     ImageView mScreenshotView;
-
     Rect mClipRect = new Rect();
+    Paint mLayerPaint = new Paint();
 
     boolean mIsAnimating;
     AnimatorSet mEnterAnimation;
@@ -159,7 +160,7 @@
         int clipBottom = mConfig.systemInsets.top + (int) (ctx.taskRect.height() / scale);
 
         // Enable the HW Layers on the screenshot view
-        mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
 
         // Compose the animation
         mEnterAnimation = new AnimatorSet();
@@ -173,7 +174,7 @@
                 // Mark that we are no longer animating
                 mIsAnimating = false;
                 // Disable the HW Layers on this view
-                setLayerType(View.LAYER_TYPE_NONE, null);
+                setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
 
                 if (Console.Enabled) {
                     Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
@@ -217,7 +218,7 @@
                     // Mark that we are no longer animating
                     mIsAnimating = false;
                     // Disable the HW Layers on the screenshot view
-                    mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+                    mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
                 }
             });
             mEnterAnimation.setDuration(475);
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 3e6879d..6f6a6c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -54,7 +54,7 @@
 
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
-        public void onTaskLaunching(boolean isTaskInStackBounds);
+        public void onTaskLaunching();
         public void onExitAnimationTriggered();
     }
 
@@ -389,11 +389,7 @@
                                final TaskStack stack, final Task task) {
         // Notify any callbacks of the launching of a new task
         if (mCb != null) {
-            boolean isTaskInStackBounds = false;
-            if (stackView != null && tv != null) {
-                isTaskInStackBounds = stackView.isTaskInStackBounds(tv);
-            }
-            mCb.onTaskLaunching(isTaskInStackBounds);
+            mCb.onTaskLaunching();
         }
 
         final Runnable launchRunnable = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index 82d6220..8192f14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -50,6 +50,7 @@
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
 
+    Paint mLayerPaint = new Paint();
     static Paint sHighlightPaint;
 
     public TaskBarView(Context context) {
@@ -237,11 +238,11 @@
 
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
-        mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
     }
 
     /** Disable the hw layers on this task view */
     void disableHwLayers() {
-        mDismissButton.setLayerType(View.LAYER_TYPE_NONE, null);
+        mDismissButton.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
     }
 }
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 e0a12b7..7d7b368 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -187,12 +187,20 @@
         return null;
     }
 
-    /** Update/get the transform */
+    /** Update/get the transform (creates a new TaskViewTransform) */
     public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
         TaskViewTransform transform = new TaskViewTransform();
+        return getStackTransform(indexInStack, stackScroll, transform);
+    }
 
+    /** Update/get the transform */
+    public TaskViewTransform getStackTransform(int indexInStack, int stackScroll,
+                                               TaskViewTransform transformOut) {
         // Return early if we have an invalid index
-        if (indexInStack < 0) return transform;
+        if (indexInStack < 0) {
+            transformOut.reset();
+            return transformOut;
+        }
 
         // Map the items to an continuous position relative to the specified scroll
         int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
@@ -209,35 +217,35 @@
         float scale = Math.max(minScale, Math.min(1f, minScale + 
             ((boundedT + (numPeekCards + 1)) * scaleInc)));
         float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2;
-        transform.scale = scale;
+        transformOut.scale = scale;
 
         // Set the y translation
         if (boundedT < 0f) {
-            transform.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
+            transformOut.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
                     numPeekCards) * peekHeight - scaleYOffset);
         } else {
-            transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
+            transformOut.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
         // Set the z translation
         int minZ = mConfig.taskViewTranslationZMinPx;
         int incZ = mConfig.taskViewTranslationZIncrementPx;
-        transform.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
+        transformOut.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
 
         // Set the alphas
-        transform.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
+        transformOut.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
 
         // Update the rect and visibility
-        transform.rect.set(mTaskRect);
+        transformOut.rect.set(mTaskRect);
         if (t < -(numPeekCards + 1)) {
-            transform.visible = false;
+            transformOut.visible = false;
         } else {
-            transform.rect.offset(0, transform.translationY);
-            Utilities.scaleRectAboutCenter(transform.rect, transform.scale);
-            transform.visible = Rect.intersects(mRect, transform.rect);
+            transformOut.rect.offset(0, transformOut.translationY);
+            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+            transformOut.visible = Rect.intersects(mRect, transformOut.rect);
         }
-        transform.t = t;
-        return transform;
+        transformOut.t = t;
+        return transformOut;
     }
 
     /**
@@ -250,14 +258,25 @@
                                        boolean boundTranslationsToRect) {
         // XXX: Optimization: Use binary search to find the visible range
 
+        int taskTransformCount = taskTransforms.size();
         int taskCount = tasks.size();
         int firstVisibleIndex = -1;
         int lastVisibleIndex = -1;
-        taskTransforms.clear();
-        taskTransforms.ensureCapacity(taskCount);
+
+        // We can reuse the task transforms where possible to reduce object allocation
+        if (taskTransformCount < taskCount) {
+            // If there are less transforms than tasks, then add as many transforms as necessary
+            for (int i = taskTransformCount; i < taskCount; i++) {
+                taskTransforms.add(new TaskViewTransform());
+            }
+        } else if (taskTransformCount > taskCount) {
+            // If there are more transforms than tasks, then just subset the transform list
+            taskTransforms.subList(0, taskCount);
+        }
+
+        // Update the stack transforms
         for (int i = 0; i < taskCount; i++) {
-            TaskViewTransform transform = getStackTransform(i, stackScroll);
-            taskTransforms.add(transform);
+            TaskViewTransform transform = getStackTransform(i, stackScroll, taskTransforms.get(i));
             if (transform.visible) {
                 if (firstVisibleIndex < 0) {
                     firstVisibleIndex = i;
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 09dc1c8..0b19162 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Outline;
+import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -63,6 +64,7 @@
     Point mLastTouchDown = new Point();
     Path mRoundedRectClipPath = new Path();
     Rect mTmpRect = new Rect();
+    Paint mLayerPaint = new Paint();
 
     TaskThumbnailView mThumbnailView;
     TaskBarView mBarView;
@@ -440,13 +442,13 @@
 
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
-        mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+        mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, mLayerPaint);
         mBarView.enableHwLayers();
     }
 
     /** Disable the hw layers on this task view */
     void disableHwLayers() {
-        mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
+        mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, mLayerPaint);
         mBarView.disableHwLayers();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 6c420e1..1947e30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -28,7 +28,7 @@
     public float dismissAlpha = 1f;
     public boolean visible = false;
     public Rect rect = new Rect();
-    float t;
+    float t = 0f;
 
     public TaskViewTransform() {
         // Do nothing
@@ -45,6 +45,18 @@
         t = o.t;
     }
 
+    /** Resets the current transform */
+    public void reset() {
+        translationY = 0;
+        translationZ = 0;
+        scale = 1f;
+        alpha = 1f;
+        dismissAlpha = 1f;
+        visible = false;
+        rect.setEmpty();
+        t = 0f;
+    }
+
     /** Convenience functions to compare against current property values */
     public boolean hasAlphaChangedFrom(float v) {
         return (Float.compare(alpha, v) != 0);