Fixing crash, ensuring that we get the post-animation callback, adding nav bar scrim (Bug. 15157307)

Change-Id: I601ee7eda22a4b5ecb2e6835d55ed6539c5cd503
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
new file mode 100644
index 0000000..6cd1176
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
new file mode 100644
index 0000000..7237f09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
new file mode 100644
index 0000000..8d56a1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
new file mode 100644
index 0000000..aed300b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
new file mode 100644
index 0000000..463fee8
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal|bottom"
+    android:scaleType="fitXY"
+    android:src="@drawable/recents_nav_bar_background" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0184df2..79a1df4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -113,17 +113,20 @@
     <!-- The min animation duration for animating views that are newly visible. -->
     <integer name="recents_filter_animate_new_views_min_duration">125</integer>
     <!-- The min animation duration for animating the task bar in. -->
-    <integer name="recents_animate_task_bar_enter_duration">300</integer>
+    <integer name="recents_animate_task_bar_enter_duration">250</integer>
+    <!-- The animation delay for animating the first task in. This should roughly be the animation
+     duration of the transition in to recents. -->
+    <integer name="recents_animate_task_bar_enter_delay">225</integer>
     <!-- The min animation duration for animating the task bar out. -->
-    <integer name="recents_animate_task_bar_exit_duration">150</integer>
-    <!-- The animation duration for animating in the info pane. -->
-    <integer name="recents_animate_task_view_info_pane_duration">150</integer>
+    <integer name="recents_animate_task_bar_exit_duration">125</integer>
+    <!-- The min animation duration for animating the nav bar scrim in. -->
+    <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
     <!-- The animation duration for animating the removal of a task view. -->
     <integer name="recents_animate_task_view_remove_duration">250</integer>
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
-    <!-- Transposes the search bar layout in landscape -->
-    <bool name="recents_transpose_search_layout_with_orientation">true</bool>
+    <!-- Transposes the recents layout in landscape. -->
+    <bool name="recents_transpose_layout_with_orientation">true</bool>
 
     <!-- Whether to enable KeyguardService or not -->
     <bool name="config_enableKeyguardService">true</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index ca9bb94..bb19415 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -152,6 +152,7 @@
     // Recents service binding
     Messenger mService = null;
     Messenger mMessenger;
+    RecentsMessageHandler mHandler;
     boolean mServiceIsBound = false;
     boolean mToggleRecentsUponServiceBound;
     RecentsServiceConnection mConnection = new RecentsServiceConnection();
@@ -168,7 +169,8 @@
     public AlternateRecentsComponent(Context context) {
         mContext = context;
         mSystemServicesProxy = new SystemServicesProxy(context);
-        mMessenger = new Messenger(new RecentsMessageHandler());
+        mHandler = new RecentsMessageHandler();
+        mMessenger = new Messenger(mHandler);
     }
 
     public void onStart() {
@@ -507,7 +509,7 @@
         if (!useThumbnailTransition) {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.recents_from_launcher_enter,
-                    R.anim.recents_from_launcher_exit);
+                    R.anim.recents_from_launcher_exit, mHandler, this);
             startAlternateRecentsActivity(opts, false);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index df387c1..fa85234 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -26,11 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.util.Pair;
+import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
@@ -67,6 +70,7 @@
     FrameLayout mContainerView;
     RecentsView mRecentsView;
     View mEmptyView;
+    View mNavBarScrimView;
 
     AppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
@@ -99,7 +103,7 @@
                     dismissRecentsIfVisible();
                 }
             } else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) {
-                // Try and start the enter animation
+                // Try and start the enter animation (or restart it on configuration changed)
                 mRecentsView.startOnEnterAnimation();
             }
         }
@@ -129,6 +133,9 @@
             mRecentsView.setBSP(root);
         }
 
+        // Hide the scrim by default when we enter recents
+        mNavBarScrimView.setVisibility(View.INVISIBLE);
+
         // Add the default no-recents layout
         if (stacks.size() == 1 && stacks.get(0).getTaskCount() == 0) {
             mEmptyView.setVisibility(View.VISIBLE);
@@ -269,10 +276,12 @@
         // Create the empty view
         LayoutInflater inflater = LayoutInflater.from(this);
         mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false);
+        mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false);
 
         mContainerView = new FrameLayout(this);
         mContainerView.addView(mRecentsView);
         mContainerView.addView(mEmptyView);
+        mContainerView.addView(mNavBarScrimView);
         setContentView(mContainerView);
 
         // Update the recent tasks
@@ -282,6 +291,16 @@
         bindSearchBarAppWidget();
         // Add the search bar layout
         addSearchBarAppWidgetView();
+
+        // Update if we are getting a configuration change
+        if (savedInstanceState != null) {
+            onConfigurationChange();
+        }
+    }
+
+    void onConfigurationChange() {
+        // Try and start the enter animation (or restart it on configuration changed)
+        mRecentsView.startOnEnterAnimation();
     }
 
     @Override
@@ -433,8 +452,6 @@
 
     @Override
     public void onBackPressed() {
-        boolean interceptedByInfoPanelClose = false;
-
         // Unfilter any stacks
         if (!mRecentsView.unfilterFilteredStacks()) {
             super.onBackPressed();
@@ -442,8 +459,35 @@
     }
 
     @Override
-    public void onTaskLaunching() {
+    public void onEnterAnimationTriggered() {
+        // Fade in the scrim
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        if (config.hasNavBarScrim()) {
+            mNavBarScrimView.setVisibility(View.VISIBLE);
+            mNavBarScrimView.setAlpha(0f);
+            mNavBarScrimView.animate().alpha(1f)
+                    .setStartDelay(config.taskBarEnterAnimDelay)
+                    .setDuration(config.navBarScrimEnterDuration)
+                    .setInterpolator(config.fastOutSlowInInterpolator)
+                    .withLayer()
+                    .start();
+        }
+    }
+
+    @Override
+    public void onTaskLaunching(boolean isTaskInStackBounds) {
         mTaskLaunched = true;
+
+        // Fade out the scrim
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        if (!isTaskInStackBounds && config.hasNavBarScrim()) {
+            mNavBarScrimView.animate().alpha(0f)
+                    .setStartDelay(0)
+                    .setDuration(config.taskBarExitAnimDuration)
+                    .setInterpolator(config.fastOutSlowInInterpolator)
+                    .withLayer()
+                    .start();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 6391685..0cf6ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -41,7 +41,7 @@
     public Rect displayRect = new Rect();
 
     boolean isLandscape;
-    boolean transposeSearchLayoutWithOrientation;
+    boolean transposeRecentsLayoutWithOrientation;
     int searchBarAppWidgetId = -1;
 
     public float animationPxMovementPerSecond;
@@ -58,7 +58,6 @@
     public float taskStackWidthPaddingPct;
     public int taskStackTopPaddingPx;
 
-    public int taskViewInfoPaneAnimDuration;
     public int taskViewRemoveAnimDuration;
     public int taskViewRemoveAnimTranslationXPx;
     public int taskViewTranslationZMinPx;
@@ -76,8 +75,11 @@
     public int taskBarViewHighlightColor;
 
     public int taskBarEnterAnimDuration;
+    public int taskBarEnterAnimDelay;
     public int taskBarExitAnimDuration;
 
+    public int navBarScrimEnterDuration;
+
     public boolean launchedFromAltTab;
     public boolean launchedWithThumbnailAnimation;
 
@@ -108,8 +110,8 @@
 
         isLandscape = res.getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
-        transposeSearchLayoutWithOrientation =
-                res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
+        transposeRecentsLayoutWithOrientation =
+                res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
         if (Console.Enabled) {
             Console.log(Constants.Log.UI.MeasureAndLayout,
                     "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
@@ -133,8 +135,6 @@
         taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
         taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
 
-        taskViewInfoPaneAnimDuration =
-                res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
         taskViewRemoveAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_view_remove_duration);
         taskViewRemoveAnimTranslationXPx =
@@ -163,9 +163,14 @@
 
         taskBarEnterAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
+        taskBarEnterAnimDelay =
+                res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
         taskBarExitAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
 
+        navBarScrimEnterDuration =
+                res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
+
         fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                         com.android.internal.R.interpolator.fast_out_slow_in);
         fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
@@ -203,11 +208,16 @@
         launchedWithThumbnailAnimation = false;
     }
 
-    /** Returns whether the search bar app widget exists */
+    /** Returns whether the search bar app widget exists. */
     public boolean hasSearchBarAppWidget() {
         return searchBarAppWidgetId >= 0;
     }
 
+    /** Returns whether the nav bar scrim should be visible. */
+    public boolean hasNavBarScrim() {
+        return !transposeRecentsLayoutWithOrientation || !isLandscape;
+    }
+
     /**
      * Returns the task stack bounds in the current orientation. These bounds do not account for
      * the system insets.
@@ -216,7 +226,7 @@
         if (hasSearchBarAppWidget()) {
             Rect searchBarBounds = new Rect();
             getSearchBarBounds(width, height, searchBarBounds);
-            if (isLandscape && transposeSearchLayoutWithOrientation) {
+            if (isLandscape && transposeRecentsLayoutWithOrientation) {
                 // In landscape, the search bar appears on the left, so shift the task rect right
                 taskStackBounds.set(searchBarBounds.width(), 0, width, height);
             } else {
@@ -239,7 +249,7 @@
             return;
         }
 
-        if (isLandscape && transposeSearchLayoutWithOrientation) {
+        if (isLandscape && transposeRecentsLayoutWithOrientation) {
             // In landscape, the search bar appears on the left
             searchBarSpaceBounds.set(0, 0, searchBarSpaceHeightPx, height);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
index 4e620b6..8bcc7f5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
@@ -38,6 +38,7 @@
     PackageCallbacks mCb;
     List<ActivityManager.RecentTaskInfo> mTasks;
     SystemServicesProxy mSsp;
+    boolean mRegistered;
 
     public RecentsPackageMonitor(Context context) {
         mSsp = new SystemServicesProxy(context);
@@ -46,13 +47,19 @@
     /** Registers the broadcast receivers with the specified callbacks. */
     public void register(Context context, PackageCallbacks cb) {
         mCb = cb;
-        register(context, Looper.getMainLooper(), false);
+        if (!mRegistered) {
+            register(context, Looper.getMainLooper(), false);
+            mRegistered = true;
+        }
     }
 
     /** Unregisters the broadcast receivers. */
     @Override
     public void unregister() {
-        super.unregister();
+        if (mRegistered) {
+            super.unregister();
+            mRegistered = false;
+        }
         mTasks.clear();
     }
 
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 6005275..db398b1 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,8 @@
 
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
-        public void onTaskLaunching();
+        public void onTaskLaunching(boolean isTaskInStackBounds);
+        public void onEnterAnimationTriggered();
     }
 
     // The space partitioning root of this container
@@ -160,6 +161,9 @@
 
     /** Requests all task stacks to start their enter-recents animation */
     public void startOnEnterAnimation() {
+        // Notify callbacks that we are starting the enter animation
+        mCb.onEnterAnimationTriggered();
+
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -351,7 +355,11 @@
                                final TaskStack stack, final Task task) {
         // Notify any callbacks of the launching of a new task
         if (mCb != null) {
-            mCb.onTaskLaunching();
+            boolean isTaskInStackBounds = false;
+            if (stackView != null && tv != null) {
+                isTaskInStackBounds = stackView.isTaskInStackBounds(tv);
+            }
+            mCb.onTaskLaunching(isTaskInStackBounds);
         }
 
         final Runnable launchRunnable = new Runnable() {
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 053f122..5830e37 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -430,6 +430,13 @@
         return getScrollAmountOutOfBounds(getStackScroll()) != 0;
     }
 
+    /** Returns whether the task view is in the stack bounds or not */
+    boolean isTaskInStackBounds(TaskView tv) {
+        Rect r = new Rect();
+        tv.getHitRect(r);
+        return r.bottom <= mRect.bottom;
+    }
+
     /** Updates the min and max virtual scroll bounds */
     void updateMinMaxScroll(boolean boundScrollToNewMinMax) {
         // Compute the min and max scroll values
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 ffa181d..632c816 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -234,7 +234,7 @@
         mBarView.setTranslationY(-mBarView.getMeasuredHeight());
         mBarView.animate()
                 .translationY(0)
-                .setStartDelay(200)
+                .setStartDelay(config.taskBarEnterAnimDelay)
                 .setInterpolator(config.fastOutSlowInInterpolator)
                 .setDuration(config.taskBarEnterAnimDuration)
                 .withLayer()