Merge "[RenderScript] Fix potential leak in RS JNI" into nyc-dev
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 16e1c5c..da4a038 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1940,6 +1940,15 @@
          * </ul>
          */
         public void onHardwareVideoUnavailable(int reason) { }
+
+        @Override
+        void release() {
+            if (mHardwareSession != null) {
+                mHardwareSession.release();
+                mHardwareSession = null;
+            }
+            super.release();
+        }
     }
 
     /** @hide */
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 470989d..648c79e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -23,7 +23,6 @@
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
 import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -464,8 +463,7 @@
      * Set mode based on explicit user action.
      */
     void setViewMode(@ViewMode int mode) {
-        checkState(mState.stack.root != null);
-        LocalPreferences.setViewMode(this, mState.stack.root, mode);
+        LocalPreferences.setViewMode(this, getCurrentRoot(), mode);
         mState.derivedMode = mode;
 
         // view icon needs to be updated, but we *could* do it
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
index 43a1be1..9238928 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java
@@ -40,4 +40,15 @@
     public static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9;
     /** The user tapped on the status bar to open quick settings, from shade. */
     public static final int SYSUI_TAP_TO_OPEN_QS = 10;
+
+    /** Secondary user tries binding to the system sysui service */
+    public static final int SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE = 1;
+    /** Secondary user is bound to the system sysui service */
+    public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND = 2;
+    /** Secondary user loses connection after system sysui has died */
+    public static final int SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND = 3;
+    /** System sysui registers secondary user's callbacks */
+    public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER = 4;
+    /** System sysui unregisters secondary user's callbacks (after death) */
+    public static final int SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER = 5;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
index a584cf6..1601675 100644
--- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
+++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
@@ -51,3 +51,13 @@
 # SearchPanelView.java
 # ---------------------------
 36050 sysui_searchpanel_touch (type|1),(x|1),(y|1)
+
+# ---------------------------
+# Recents.java, RecentsSystemUser.java
+# ---------------------------
+## type: 1: USER_BIND_SERVICE        Secondary user tries binding to the system sysui service
+##       2: USER_SYSTEM_BOUND        Secondary user is bound to the system sysui service
+##       3: USER_SYSTEM_UNBOUND      Secondary user loses connection after system sysui has died
+##       4: SYSTEM_REGISTER_USER     System sysui registers user's callbacks
+##       5: SYSTEM_UNREGISTER_USER   System sysui unregisters user's callbacks (after death)
+36060 sysui_recents_connection (type|1),(user|1)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index e4fd31d..f5ae351 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -31,10 +31,13 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
 
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
@@ -83,20 +86,23 @@
     private int mDraggingInRecentsCurrentUser;
 
     // Only For system user, this is the callbacks instance we return to each secondary user
-    private RecentsSystemUser mSystemUserCallbacks;
+    private RecentsSystemUser mSystemToUserCallbacks;
 
     // Only for secondary users, this is the callbacks instance provided by the system user to make
     // calls back
-    private IRecentsSystemUserCallbacks mCallbacksToSystemUser;
+    private IRecentsSystemUserCallbacks mUserToSystemCallbacks;
 
     // The set of runnables to run after binding to the system user's service.
     private final ArrayList<Runnable> mOnConnectRunnables = new ArrayList<>();
 
     // Only for secondary users, this is the death handler for the binder from the system user
-    private final IBinder.DeathRecipient mCallbacksToSystemUserDeathRcpt = new IBinder.DeathRecipient() {
+    private final IBinder.DeathRecipient mUserToSystemCallbacksDeathRcpt = new IBinder.DeathRecipient() {
         @Override
         public void binderDied() {
-            mCallbacksToSystemUser = null;
+            mUserToSystemCallbacks = null;
+            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_UNBOUND,
+                    sSystemServicesProxy.getProcessUser());
 
             // Retry after a fixed duration
             mHandler.postDelayed(new Runnable() {
@@ -109,16 +115,19 @@
     };
 
     // Only for secondary users, this is the service connection we use to connect to the system user
-    private final ServiceConnection mServiceConnectionToSystemUser = new ServiceConnection() {
+    private final ServiceConnection mUserToSystemServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (service != null) {
-                mCallbacksToSystemUser = IRecentsSystemUserCallbacks.Stub.asInterface(
+                mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface(
                         service);
+                EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                        EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND,
+                        sSystemServicesProxy.getProcessUser());
 
                 // Listen for system user's death, so that we can reconnect later
                 try {
-                    service.linkToDeath(mCallbacksToSystemUserDeathRcpt, 0);
+                    service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Lost connection to (System) SystemUI", e);
                 }
@@ -142,7 +151,7 @@
      * Returns the callbacks interface that non-system users can call.
      */
     public IBinder getSystemUserCallbacks() {
-        return mSystemUserCallbacks;
+        return mSystemToUserCallbacks;
     }
 
     public static RecentsTaskLoader getTaskLoader() {
@@ -190,7 +199,7 @@
         if (sSystemServicesProxy.isSystemUser(processUser)) {
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
-            mSystemUserCallbacks = new RecentsSystemUser(mContext, mImpl);
+            mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
         } else {
             // For the secondary user, bind to the primary user's service to get a persistent
             // interface to register its implementation and to later update its state
@@ -224,9 +233,9 @@
             mImpl.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
                     true /* animate */, false /* reloadTasks */);
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.showRecents(triggeredFromAltTab, false /* draggingInRecents */,
@@ -260,9 +269,9 @@
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
@@ -295,9 +304,9 @@
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.toggleRecents();
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.toggleRecents();
@@ -326,9 +335,9 @@
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.preloadRecents();
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.preloadRecents();
@@ -354,9 +363,9 @@
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.cancelPreloadingRecents();
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.cancelPreloadingRecents();
@@ -387,9 +396,9 @@
             if (sSystemServicesProxy.isSystemUser(currentUser)) {
                 mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
             } else {
-                if (mSystemUserCallbacks != null) {
+                if (mSystemToUserCallbacks != null) {
                     IRecentsNonSystemUserCallbacks callbacks =
-                            mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                            mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                     if (callbacks != null) {
                         try {
                             callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
@@ -413,9 +422,9 @@
         if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
             mImpl.onDraggingInRecents(distanceFromTop);
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
                                 mDraggingInRecentsCurrentUser);
                 if (callbacks != null) {
                     try {
@@ -436,9 +445,9 @@
         if (sSystemServicesProxy.isSystemUser(mDraggingInRecentsCurrentUser)) {
             mImpl.onDraggingInRecentsEnded(velocity);
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(
                                 mDraggingInRecentsCurrentUser);
                 if (callbacks != null) {
                     try {
@@ -484,9 +493,9 @@
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.onConfigurationChanged();
         } else {
-            if (mSystemUserCallbacks != null) {
+            if (mSystemToUserCallbacks != null) {
                 IRecentsNonSystemUserCallbacks callbacks =
-                        mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                        mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                 if (callbacks != null) {
                     try {
                         callbacks.onConfigurationChanged();
@@ -512,7 +521,7 @@
                 @Override
                 public void run() {
                     try {
-                        mCallbacksToSystemUser.updateRecentsVisibility(event.visible);
+                        mUserToSystemCallbacks.updateRecentsVisibility(event.visible);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -533,7 +542,7 @@
                 @Override
                 public void run() {
                     try {
-                        mCallbacksToSystemUser.startScreenPinning();
+                        mUserToSystemCallbacks.startScreenPinning();
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -549,7 +558,7 @@
                 @Override
                 public void run() {
                     try {
-                        mCallbacksToSystemUser.sendRecentsDrawnEvent();
+                        mUserToSystemCallbacks.sendRecentsDrawnEvent();
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -565,7 +574,7 @@
                 @Override
                 public void run() {
                     try {
-                        mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+                        mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -581,7 +590,7 @@
                 @Override
                 public void run() {
                     try {
-                        mCallbacksToSystemUser.sendLaunchRecentsEvent();
+                        mUserToSystemCallbacks.sendLaunchRecentsEvent();
                     } catch (RemoteException e) {
                         Log.e(TAG, "Callback failed", e);
                     }
@@ -599,7 +608,7 @@
             @Override
             public void run() {
                 try {
-                    mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+                    mUserToSystemCallbacks.registerNonSystemUserCallbacks(
                             new RecentsImplProxy(mImpl), processUser);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to register", e);
@@ -614,11 +623,14 @@
      */
     private void postToSystemUser(final Runnable onConnectRunnable) {
         mOnConnectRunnables.add(onConnectRunnable);
-        if (mCallbacksToSystemUser == null) {
+        if (mUserToSystemCallbacks == null) {
             Intent systemUserServiceIntent = new Intent();
             systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class);
             boolean bound = mContext.bindServiceAsUser(systemUserServiceIntent,
-                    mServiceConnectionToSystemUser, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+                    mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);
+            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                    EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE,
+                    sSystemServicesProxy.getProcessUser());
             if (!bound) {
                 // Retry after a fixed duration
                 mHandler.postDelayed(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9d4f425..c2a6108 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -230,7 +230,7 @@
      * Dismisses the history view back into the stack view.
      */
     boolean dismissHistory() {
-        if (mRecentsView.isHistoryVisible()) {
+        if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
             EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
             return true;
         }
@@ -447,7 +447,7 @@
 
         // Reset some states
         mIgnoreAltTabRelease = false;
-        if (mRecentsView.isHistoryVisible()) {
+        if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
             EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
         }
 
@@ -503,13 +503,16 @@
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, mRecentsView.isHistoryVisible());
+        }
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
-        if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
+        if (RecentsDebugFlags.Static.EnableHistory &&
+                savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
             EventBus.getDefault().send(new ShowHistoryEvent());
         }
     }
@@ -603,7 +606,7 @@
     /**** EventBus events ****/
 
     public final void onBusEvent(ToggleRecentsEvent event) {
-        if (!dismissHistory()) {
+        if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
             RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
             if (launchState.launchedFromHome) {
                 dismissRecentsToHome(true /* animateTaskViews */);
@@ -614,7 +617,7 @@
     }
 
     public final void onBusEvent(IterateRecentsEvent event) {
-        if (!dismissHistory()) {
+        if (!RecentsDebugFlags.Static.EnableHistory || !dismissHistory()) {
             final RecentsDebugFlags debugFlags = Recents.getDebugFlags();
 
             // Start dozing after the recents button is clicked
@@ -651,7 +654,7 @@
             }
         } else if (event.triggeredFromHomeKey) {
             // Otherwise, dismiss Recents to Home
-            if (mRecentsView.isHistoryVisible()) {
+            if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
                 // If the history view is visible, then just cross-fade home
                 ActivityOptions opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
                                 R.anim.recents_to_launcher_enter,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 711d834..cd64323 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -37,6 +37,8 @@
         public static final boolean DisableBackgroundCache = false;
         // Enables the task affiliations
         public static final boolean EnableAffiliatedTaskGroups = true;
+        // Enables the history
+        public static final boolean EnableHistory = false;
         // Overrides the Tuner flags and enables the fast toggle and timeout
         public static final boolean EnableFastToggleTimeoutOverride = true;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index e0efaa5..8de964b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -406,9 +406,9 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
         MutableBoolean topTaskHome = new MutableBoolean(true);
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-        sInstanceLoadPlan = loader.createLoadPlan(mContext);
         if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
+            RecentsTaskLoader loader = Recents.getTaskLoader();
+            sInstanceLoadPlan = loader.createLoadPlan(mContext);
             sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
             loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
             TaskStack stack = sInstanceLoadPlan.getTaskStack();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index ae0051c..f8000b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -19,9 +19,12 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.systemui.EventLogConstants;
+import com.android.systemui.EventLogTags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
 import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -46,7 +49,8 @@
     }
 
     @Override
-    public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks, int userId) {
+    public void registerNonSystemUserCallbacks(final IBinder nonSystemUserCallbacks,
+            final int userId) {
         try {
             final IRecentsNonSystemUserCallbacks callback =
                     IRecentsNonSystemUserCallbacks.Stub.asInterface(nonSystemUserCallbacks);
@@ -54,9 +58,14 @@
                 @Override
                 public void binderDied() {
                     mNonSystemUserRecents.removeAt(mNonSystemUserRecents.indexOfValue(callback));
+                    EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                            EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_UNREGISTER_USER,
+                            userId);
                 }
             }, 0);
             mNonSystemUserRecents.put(userId, callback);
+            EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION,
+                    EventLogConstants.SYSUI_RECENTS_CONNECTION_SYSTEM_REGISTER_USER, userId);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register NonSystemUserCallbacks", e);
         }
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 c4db485..2e45627 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -143,21 +143,24 @@
         final float cornerRadius = context.getResources().getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
         LayoutInflater inflater = LayoutInflater.from(context);
-        mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
-        mHistoryButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                EventBus.getDefault().send(new ToggleHistoryEvent());
-            }
-        });
-        addView(mHistoryButton);
-        mHistoryButton.setClipToOutline(true);
-        mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
-            }
-        });
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this,
+                    false);
+            mHistoryButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    EventBus.getDefault().send(new ToggleHistoryEvent());
+                }
+            });
+            addView(mHistoryButton);
+            mHistoryButton.setClipToOutline(true);
+            mHistoryButton.setOutlineProvider(new ViewOutlineProvider() {
+                @Override
+                public void getOutline(View view, Outline outline) {
+                    outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
+                }
+            });
+        }
         mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
 
@@ -331,7 +334,9 @@
         mTaskStackView.setVisibility(View.INVISIBLE);
         mEmptyView.setVisibility(View.VISIBLE);
         mEmptyView.bringToFront();
-        mHistoryButton.bringToFront();
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            mHistoryButton.bringToFront();
+        }
     }
 
     /**
@@ -347,7 +352,9 @@
         if (mSearchBar != null) {
             mSearchBar.bringToFront();
         }
-        mHistoryButton.bringToFront();
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            mHistoryButton.bringToFront();
+        }
     }
 
     @Override
@@ -397,21 +404,23 @@
                     MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
         }
 
-        // Measure the history view
-        if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
-            measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-        }
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            // Measure the history view
+            if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+                measureChild(mHistoryView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            }
 
-        // Measure the history button within the constraints of the space above the stack
-        Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
-        measureChild(mHistoryButton,
-                MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
-                MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
-        if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
-            measureChild(mHistoryClearAllButton,
+            // Measure the history button within the constraints of the space above the stack
+            Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+            measureChild(mHistoryButton,
                     MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
                     MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+            if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+                measureChild(mHistoryClearAllButton,
+                    MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.AT_MOST),
+                    MeasureSpec.makeMeasureSpec(historyButtonRect.height(), MeasureSpec.AT_MOST));
+            }
         }
 
         setMeasuredDimension(width, height);
@@ -443,36 +452,39 @@
             mEmptyView.layout(left, top, right, bottom);
         }
 
-        // Layout the history view
-        if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
-            mHistoryView.layout(left, top, right, bottom);
-        }
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            // Layout the history view
+            if (mHistoryView != null && mHistoryView.getVisibility() != GONE) {
+                mHistoryView.layout(left, top, right, bottom);
+            }
 
-        // Layout the history button such that its drawable is start-aligned with the stack,
-        // vertically centered in the available space above the stack
-        Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
-        int historyLeft = isLayoutRtl()
-                ? historyButtonRect.right + mHistoryButton.getPaddingStart()
-                        - mHistoryButton.getMeasuredWidth()
-                : historyButtonRect.left - mHistoryButton.getPaddingStart();
-        int historyTop = historyButtonRect.top +
-                (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
-        mHistoryButton.layout(historyLeft, historyTop,
-                historyLeft + mHistoryButton.getMeasuredWidth(),
-                historyTop + mHistoryButton.getMeasuredHeight());
+            // Layout the history button such that its drawable is start-aligned with the stack,
+            // vertically centered in the available space above the stack
+            Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
+            int historyLeft = isLayoutRtl()
+                    ? historyButtonRect.right + mHistoryButton.getPaddingStart()
+                    - mHistoryButton.getMeasuredWidth()
+                    : historyButtonRect.left - mHistoryButton.getPaddingStart();
+            int historyTop = historyButtonRect.top +
+                    (historyButtonRect.height() - mHistoryButton.getMeasuredHeight()) / 2;
+            mHistoryButton.layout(historyLeft, historyTop,
+                    historyLeft + mHistoryButton.getMeasuredWidth(),
+                    historyTop + mHistoryButton.getMeasuredHeight());
 
-        // Layout the history clear all button such that it is end-aligned with the stack,
-        // vertically centered in the available space above the stack
-        if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
-            int clearAllLeft = isLayoutRtl()
-                    ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
-                    : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
-                            - mHistoryClearAllButton.getMeasuredWidth();
-            int clearAllTop = historyButtonRect.top +
-                    (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) / 2;
-            mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
-                    clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
-                    clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+            // Layout the history clear all button such that it is end-aligned with the stack,
+            // vertically centered in the available space above the stack
+            if (mHistoryClearAllButton != null && mHistoryClearAllButton.getVisibility() != GONE) {
+                int clearAllLeft = isLayoutRtl()
+                        ? historyButtonRect.left - mHistoryClearAllButton.getPaddingStart()
+                        : historyButtonRect.right + mHistoryClearAllButton.getPaddingStart()
+                        - mHistoryClearAllButton.getMeasuredWidth();
+                int clearAllTop = historyButtonRect.top +
+                        (historyButtonRect.height() - mHistoryClearAllButton.getMeasuredHeight()) /
+                                2;
+                mHistoryClearAllButton.layout(clearAllLeft, clearAllTop,
+                        clearAllLeft + mHistoryClearAllButton.getMeasuredWidth(),
+                        clearAllTop + mHistoryClearAllButton.getMeasuredHeight());
+            }
         }
 
         if (mAwaitingFirstLayout) {
@@ -540,9 +552,11 @@
     }
 
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
-        // Hide the history button
         int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
-        hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+        if (RecentsDebugFlags.Static.EnableHistory) {
+            // Hide the history button
+            hideHistoryButton(taskViewExitToHomeDuration, false /* translate */);
+        }
         animateBackgroundScrim(0f, taskViewExitToHomeDuration);
     }
 
@@ -675,11 +689,17 @@
             // Reset the view state
             mAwaitingFirstLayout = true;
             mLastTaskLaunchedWasFreeform = false;
-            hideHistoryButton(0, false /* translate */);
+            if (RecentsDebugFlags.Static.EnableHistory) {
+                hideHistoryButton(0, false /* translate */);
+            }
         }
     }
 
     public final void onBusEvent(ToggleHistoryEvent event) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         if (mHistoryView != null && mHistoryView.isVisible()) {
             EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
         } else {
@@ -688,6 +708,10 @@
     }
 
     public final void onBusEvent(ShowHistoryEvent event) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         if (mHistoryView == null) {
             LayoutInflater inflater = LayoutInflater.from(getContext());
             mHistoryView = (RecentsHistoryView) inflater.inflate(R.layout.recents_history, this,
@@ -746,6 +770,10 @@
     }
 
     public final void onBusEvent(HideHistoryEvent event) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         // Animate the empty view in parallel with the history view (the task view animations are
         // handled in TaskStackView)
         Rect stackRect = mTaskStackView.mLayoutAlgorithm.mStackRect;
@@ -765,10 +793,18 @@
     }
 
     public final void onBusEvent(ShowHistoryButtonEvent event) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         showHistoryButton(150, event.translate);
     }
 
     public final void onBusEvent(HideHistoryButtonEvent event) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         hideHistoryButton(100, true /* translate */);
     }
 
@@ -776,6 +812,10 @@
      * Shows the history button.
      */
     private void showHistoryButton(final int duration, final boolean translate) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
         if (mHistoryButton.getVisibility() == View.INVISIBLE) {
             mHistoryButton.setVisibility(View.VISIBLE);
@@ -808,6 +848,10 @@
      * Hides the history button.
      */
     private void hideHistoryButton(int duration, boolean translate) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         final ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
         hideHistoryButton(duration, translate, postAnimationTrigger);
         postAnimationTrigger.flushLastDecrementRunnables();
@@ -818,6 +862,10 @@
      */
     private void hideHistoryButton(int duration, boolean translate,
             final ReferenceCountedTrigger postAnimationTrigger) {
+        if (!RecentsDebugFlags.Static.EnableHistory) {
+            return;
+        }
+
         if (mHistoryButton.getVisibility() == View.VISIBLE) {
             if (translate) {
                 mHistoryButton.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index 890b445..2cd0c19 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -467,12 +467,13 @@
 
         // Setup the end listener to return all the hidden views to the view pool after the
         // focus animation
-        AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
+        ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger();
+        postAnimTrigger.addLastDecrementRunnable(new Runnable() {
             @Override
-            public void onAnimationEnd(Animator animation) {
+            public void run() {
                 mStackView.bindVisibleTaskViews(newScroll);
             }
-        };
+        });
 
         List<TaskView> taskViews = mStackView.getTaskViews();
         int taskViewCount = taskViews.size();
@@ -513,7 +514,8 @@
             AnimationProps anim = new AnimationProps()
                     .setDuration(AnimationProps.BOUNDS, duration)
                     .setInterpolator(AnimationProps.BOUNDS, interpolator)
-                    .setListener(endListener);
+                    .setListener(postAnimTrigger.decrementOnAnimationEnd());
+            postAnimTrigger.increment();
             mStackView.updateTaskViewToTransform(tv, toTransform, anim);
         }
         return willScroll;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 79c21f3..33315c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -107,7 +107,7 @@
                     mPanel.setPanelScrimMinFraction((float) expandedHeight
                             / mPanel.getMaxPanelHeight());
                     mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
-                    mPanel.clearNotificattonEffects();
+                    mPanel.clearNotificationEffects();
                     return true;
                 }
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 88a7843..1a0acbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -89,13 +89,13 @@
     private KeyguardAffordanceHelper mAfforanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
-    private QSContainer mQsContainer;
+    protected QSContainer mQsContainer;
     private KeyguardStatusView mKeyguardStatusView;
     private TextView mClockView;
     private View mReserveNotificationSpace;
     private View mQsNavbarScrim;
     private NotificationsQuickSettingsContainer mNotificationContainerParent;
-    private NotificationStackScrollLayout mNotificationStackScroller;
+    protected NotificationStackScrollLayout mNotificationStackScroller;
     private boolean mAnimateNextTopPaddingChange;
 
     private int mTrackingPointer;
@@ -126,9 +126,9 @@
     private float mInitialTouchY;
     private float mLastTouchX;
     private float mLastTouchY;
-    private float mQsExpansionHeight;
-    private int mQsMinExpansionHeight;
-    private int mQsMaxExpansionHeight;
+    protected float mQsExpansionHeight;
+    protected int mQsMinExpansionHeight;
+    protected int mQsMaxExpansionHeight;
     private int mQsPeekHeight;
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
@@ -1072,8 +1072,8 @@
 
     private void setKeyguardBottomAreaVisibility(int statusBarState,
             boolean goingToFullShade) {
+        mKeyguardBottomArea.animate().cancel();
         if (goingToFullShade) {
-            mKeyguardBottomArea.animate().cancel();
             mKeyguardBottomArea.animate()
                     .alpha(0f)
                     .setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
@@ -1083,13 +1083,11 @@
                     .start();
         } else if (statusBarState == StatusBarState.KEYGUARD
                 || statusBarState == StatusBarState.SHADE_LOCKED) {
-            mKeyguardBottomArea.animate().cancel();
             if (!mDozing) {
                 mKeyguardBottomArea.setVisibility(View.VISIBLE);
             }
             mKeyguardBottomArea.setAlpha(1f);
         } else {
-            mKeyguardBottomArea.animate().cancel();
             mKeyguardBottomArea.setVisibility(View.GONE);
             mKeyguardBottomArea.setAlpha(1f);
         }
@@ -1196,7 +1194,7 @@
         }
     }
 
-    private void updateQsExpansion() {
+    protected void updateQsExpansion() {
         mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
     }
 
@@ -1238,7 +1236,7 @@
         }
     }
 
-    private void requestScrollerTopPaddingUpdate(boolean animate) {
+    protected void requestScrollerTopPaddingUpdate(boolean animate) {
         mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
                 mAnimateNextTopPaddingChange || animate,
                 mKeyguardShowing
@@ -1520,16 +1518,12 @@
         updateQsExpansion();
     }
 
-    private float getHeaderTranslation() {
+    protected float getHeaderTranslation() {
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
             return 0;
         }
         if (mNotificationStackScroller.getNotGoneChildCount() == 0) {
-            if (mExpandedHeight / HEADER_RUBBERBAND_FACTOR >= mQsMinExpansionHeight) {
-                return 0;
-            } else {
-                return mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight;
-            }
+            return Math.min(0, mExpandedHeight / HEADER_RUBBERBAND_FACTOR - mQsMinExpansionHeight);
         }
         float stackTranslation = mNotificationStackScroller.getStackTranslation();
         float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
@@ -2191,7 +2185,7 @@
      *
      * @param x the x-coordinate the touch event
      */
-    private void updateVerticalPanelPosition(float x) {
+    protected void updateVerticalPanelPosition(float x) {
         if (mNotificationStackScroller.getWidth() * 1.75f > getWidth()) {
             resetVerticalPanelPosition();
             return;
@@ -2216,7 +2210,7 @@
         mQsContainer.setTranslationX(translation);
     }
 
-    private void updateStackHeight(float stackHeight) {
+    protected void updateStackHeight(float stackHeight) {
         mNotificationStackScroller.setStackHeight(stackHeight);
         updateKeyguardBottomAreaAlpha();
     }
@@ -2225,7 +2219,7 @@
         mBar.panelScrimMinFractionChanged(minFraction);
     }
 
-    public void clearNotificattonEffects() {
+    public void clearNotificationEffects() {
         mStatusBar.clearNotificationEffects();
     }
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c6613f5..8d75f60 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -346,8 +346,7 @@
                 String packageName = component.getPackageName();
                 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                         Uri.fromParts("package", packageName, null));
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
-                        Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                 intent.setSourceBounds(sourceBounds);
                 mContext.startActivityAsUser(intent, opts, user);
             } finally {