Merge "Fix build breakage"
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 61dc6e4..2018e76 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,6 +18,8 @@
 
 #include <stdio.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
@@ -34,6 +36,8 @@
 
 // ----------------------------------------------------------------------------
 
+#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+
 namespace android {
 
 static const char* const OutOfResourcesException =
@@ -55,6 +59,28 @@
     return android_atomic_inc(&globalCounter);
 }
 
+// Check whether the current EGL context is protected.
+static bool isProtectedContext() {
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLContext ctx = eglGetCurrentContext();
+
+    if (dpy == EGL_NO_DISPLAY) {
+        ALOGE("isProtectedSurface: invalid current EGLDisplay");
+        return false;
+    }
+
+    if (ctx == EGL_NO_CONTEXT) {
+        ALOGE("isProtectedSurface: invalid current EGLContext");
+        return false;
+    }
+
+    EGLint isProtected = EGL_FALSE;
+    // TODO: Change the enum value below when an extension is ratified.
+    eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+
+    return isProtected;
+}
+
 // ----------------------------------------------------------------------------
 
 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -263,6 +289,11 @@
             getpid(),
             createProcessUniqueId()));
 
+    // If the current context is protected, inform the producer.
+    if (isProtectedContext()) {
+        consumer->setConsumerUsageBits(GRALLOC_USAGE_PROTECTED);
+    }
+
     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
     SurfaceTexture_setProducer(env, thiz, producer);
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index aedc2c5..4aa4d42 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -195,6 +195,10 @@
     <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
     <integer name="recents_svelte_level">0</integer>
 
+    <!-- In multi-window, determines whether the stack where recents lives should grow from
+         the smallest position when being launched. -->
+    <bool name="recents_grow_in_multiwindow">true</bool>
+
     <!-- Recents: The relative range of visible tasks from the current scroll position
          while the stack is focused. -->
     <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 99028a6c..001d1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -32,7 +32,7 @@
     /**
      * Docks the top-most task and opens recents.
      */
-    boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds);
+    boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds);
 
     /**
      * Called during a drag-from-navbar-in gesture.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index b36b95a..37085c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents;
 
+import android.graphics.Rect;
+
 /**
  * Due to the fact that RecentsActivity is per-user, we need to establish an
  * interface (this) for the system user to callback to the secondary users in
@@ -29,6 +31,8 @@
     void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
     void toggleRecents();
     void onConfigurationChanged();
+    void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+            in Rect initialBounds);
     void onDraggingInRecents(float distanceFromTop);
     void onDraggingInRecentsEnded(float velocity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index 6b49195..cb8f0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -26,4 +26,7 @@
 
     void updateRecentsVisibility(boolean visible);
     void startScreenPinning();
+    void sendRecentsDrawnEvent();
+    void sendDockingTopTaskEvent(int dragMode);
+    void sendLaunchRecentsEvent();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 2baefd5..b8310f2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -36,8 +37,11 @@
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 
@@ -366,17 +370,38 @@
     }
 
     @Override
-    public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
+    public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds) {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
         if (!isUserSetup()) {
             return false;
         }
 
-        if (mImpl.dockTopTask(draggingInRecents, stackCreateMode,initialBounds)) {
-            if (draggingInRecents) {
-                mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser();
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
+        boolean screenPinningActive = ssp.isScreenPinningActive();
+        boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
+        if (topTask != null && !isTopTaskHome && !screenPinningActive) {
+            if (sSystemServicesProxy.isSystemUser(currentUser)) {
+                mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
+            } else {
+                if (mSystemUserCallbacks != null) {
+                    IRecentsNonSystemUserCallbacks callbacks =
+                            mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+                    if (callbacks != null) {
+                        try {
+                            callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
+                                    initialBounds);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Callback failed", e);
+                        }
+                    } else {
+                        Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+                    }
+                }
             }
+            mDraggingInRecentsCurrentUser = currentUser;
             return true;
         }
         return false;
@@ -516,6 +541,54 @@
         }
     }
 
+    public final void onBusEvent(final RecentsDrawnEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendRecentsDrawnEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final DockingTopTaskEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public final void onBusEvent(final RecentsActivityStartingEvent event) {
+        int processUser = sSystemServicesProxy.getProcessUser();
+        if (!sSystemServicesProxy.isSystemUser(processUser)) {
+            postToSystemUser(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mCallbacksToSystemUser.sendLaunchRecentsEvent();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Callback failed", e);
+                    }
+                }
+            });
+        }
+    }
+
     /**
      * Attempts to register with the system user.
      */
@@ -525,7 +598,8 @@
             @Override
             public void run() {
                 try {
-                    mCallbacksToSystemUser.registerNonSystemUserCallbacks(mImpl, processUser);
+                    mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+                            new RecentsImplProxy(mImpl), processUser);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to register", e);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 3a3b19d..a11c06d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -59,6 +59,7 @@
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -400,6 +401,17 @@
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
 
         MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
+
+        mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+                new ViewTreeObserver.OnPreDrawListener() {
+
+            @Override
+            public boolean onPreDraw() {
+                mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+                EventBus.getDefault().post(new RecentsDrawnEvent());
+                return true;
+            }
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 5f11bee..b78fd22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -41,9 +41,11 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -62,6 +64,7 @@
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
@@ -72,8 +75,7 @@
  * An implementation of the Recents component for the current user.  For secondary users, this can
  * be called remotely from the system user.
  */
-public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
-        ActivityOptions.OnAnimationFinishedListener {
+public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {
 
     private final static String TAG = "RecentsImpl";
     // The minimum amount of time between each recents button press that we will handle
@@ -532,18 +534,14 @@
         showRelativeAffiliatedTask(false);
     }
 
-    public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
+    public void dockTopTask(int topTaskId, int dragMode,
+            int stackCreateMode, Rect initialBounds) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
-        boolean screenPinningActive = ssp.isScreenPinningActive();
-        boolean isTopTaskHome = SystemServicesProxy.isHomeStack(topTask.stackId);
-        if (topTask != null && !isTopTaskHome && !screenPinningActive) {
-            ssp.moveTaskToDockedStack(topTask.id, stackCreateMode, initialBounds);
-            showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */,
-                    true /* reloadTasks*/);
-            return true;
-        }
-        return false;
+        ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
+        showRecents(false /* triggeredFromAltTab */,
+                dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
+                true /* reloadTasks*/);
+        EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
     }
 
     /**
@@ -918,6 +916,7 @@
             mContext.startActivityAsUser(intent, UserHandle.CURRENT);
         }
         mCanReuseTaskStackViews = true;
+        EventBus.getDefault().send(new RecentsActivityStartingEvent());
     }
 
     /**** OnAnimationFinishedListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
new file mode 100644
index 0000000..86ec98a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.recents;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * A proxy class which directs all methods from {@link IRecentsNonSystemUserCallbacks} to
+ * {@link RecentsImpl} and makes sure they are called from the main thread.
+ */
+public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
+
+    private static final int MSG_PRELOAD_RECENTS = 1;
+    private static final int MSG_CANCEL_PRELOADING_RECENTS = 2;
+    private static final int MSG_SHOW_RECENTS = 3;
+    private static final int MSG_HIDE_RECENTS = 4;
+    private static final int MSG_TOGGLE_RECENTS = 5;
+    private static final int MSG_ON_CONFIGURATION_CHANGED = 6;
+    private static final int MSG_DOCK_TOP_TASK = 7;
+    private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
+    private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
+
+    private RecentsImpl mImpl;
+
+    public RecentsImplProxy(RecentsImpl recentsImpl) {
+        mImpl = recentsImpl;
+    }
+
+    @Override
+    public void preloadRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_PRELOAD_RECENTS);
+    }
+
+    @Override
+    public void cancelPreloadingRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_CANCEL_PRELOADING_RECENTS);
+    }
+
+    @Override
+    public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate,
+            boolean reloadTasks) throws RemoteException {
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = triggeredFromAltTab ? 1 : 0;
+        args.argi2 = draggingInRecents ? 1 : 0;
+        args.argi3 = animate ? 1 : 0;
+        args.argi4 = reloadTasks ? 1 : 0;
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_RECENTS, args));
+    }
+
+    @Override
+    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)
+            throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 :0,
+                triggeredFromHomeKey ? 1 : 0));
+    }
+
+    @Override
+    public void toggleRecents() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_TOGGLE_RECENTS);
+    }
+
+    @Override
+    public void onConfigurationChanged() throws RemoteException {
+        mHandler.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
+    }
+
+    @Override
+    public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+            Rect initialBounds) throws RemoteException {
+        SomeArgs args = SomeArgs.obtain();
+        args.argi1 = topTaskId;
+        args.argi2 = dragMode;
+        args.argi3 = stackCreateMode;
+        args.arg1 = initialBounds;
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args));
+    }
+
+    @Override
+    public void onDraggingInRecents(float distanceFromTop) throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS, distanceFromTop));
+    }
+
+    @Override
+    public void onDraggingInRecentsEnded(float velocity) throws RemoteException {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
+    }
+
+    private final Handler mHandler = new Handler() {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PRELOAD_RECENTS:
+                    mImpl.preloadRecents();
+                    break;
+                case MSG_CANCEL_PRELOADING_RECENTS:
+                    mImpl.cancelPreloadingRecents();
+                    break;
+                case MSG_SHOW_RECENTS:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    mImpl.showRecents(args.argi1 != 0, args.argi2 != 0, args.argi3 != 0,
+                            args.argi4 != 0);
+                    break;
+                case MSG_HIDE_RECENTS:
+                    mImpl.hideRecents(msg.arg1 != 0, msg.arg2 != 0);
+                    break;
+                case MSG_TOGGLE_RECENTS:
+                    mImpl.toggleRecents();
+                    break;
+                case MSG_ON_CONFIGURATION_CHANGED:
+                    mImpl.onConfigurationChanged();
+                    break;
+                case MSG_DOCK_TOP_TASK:
+                    args = (SomeArgs) msg.obj;
+                    mImpl.dockTopTask(args.argi1, args.argi2, args.argi3 = 0,
+                            (Rect) args.arg1);
+                    break;
+                case MSG_ON_DRAGGING_IN_RECENTS:
+                    mImpl.onDraggingInRecents((Float) msg.obj);
+                    break;
+                case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
+                    mImpl.onDraggingInRecentsEnded((Float) msg.obj);
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+            super.handleMessage(msg);
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index fb21500..ae0051c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -22,6 +22,11 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+
 /**
  * An implementation of the system user's Recents interface to be called remotely by secondary
  * users.
@@ -70,4 +75,19 @@
     public void startScreenPinning() {
         mImpl.onStartScreenPinning(mContext);
     }
+
+    @Override
+    public void sendRecentsDrawnEvent() {
+        EventBus.getDefault().post(new RecentsDrawnEvent());
+    }
+
+    @Override
+    public void sendDockingTopTaskEvent(int dragMode) throws RemoteException {
+        EventBus.getDefault().post(new DockingTopTaskEvent(dragMode));
+    }
+
+    @Override
+    public void sendLaunchRecentsEvent() throws RemoteException {
+        EventBus.getDefault().post(new RecentsActivityStartingEvent());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
new file mode 100644
index 0000000..264c2c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fires when the user invoked the gesture to dock the top/left task.
+ */
+public class DockingTopTaskEvent extends EventBus.Event {
+
+    public int dragMode;
+
+    public DockingTopTaskEvent(int dragMode) {
+        this.dragMode = dragMode;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
new file mode 100644
index 0000000..a2ecfe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Called after recents activity is being started, i.e. startActivity has just been called.
+ */
+public class RecentsActivityStartingEvent extends EventBus.Event{
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
new file mode 100644
index 0000000..5483166
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fired when recents was launched and has drawn its first frame.
+ */
+public class RecentsDrawnEvent extends EventBus.Event {
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 08793e8..c0e1e44 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -49,7 +49,12 @@
 import com.android.internal.policy.DockedDividerUtils;
 import com.android.systemui.R;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
 import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 
 import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
 import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
@@ -118,6 +123,10 @@
     private DividerSnapAlgorithm mSnapAlgorithm;
     private final Rect mStableInsets = new Rect();
 
+    private boolean mAnimateAfterRecentsDrawn;
+    private boolean mGrowAfterRecentsDrawn;
+    private boolean mGrowRecents;
+
     public DividerView(Context context) {
         super(context);
     }
@@ -148,6 +157,7 @@
         mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
         mTouchElevation = getResources().getDimensionPixelSize(
                 R.dimen.docked_stack_divider_lift_elevation);
+        mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
@@ -161,6 +171,18 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        EventBus.getDefault().register(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+
+    @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
                 insets.getStableInsetRight(), insets.getStableInsetBottom());
@@ -175,15 +197,18 @@
         return mWindowManagerProxy;
     }
 
-    public boolean startDragging(boolean animate) {
-        mHandle.setTouching(true, animate);
+    public boolean startDragging(boolean animate, boolean touching) {
+        if (touching) {
+            mHandle.setTouching(true, animate);
+        }
         mDockSide = mWindowManagerProxy.getDockSide();
-        mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
-                mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
+        getSnapAlgorithm();
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
             mWindowManager.setSlippery(false);
-            liftBackground();
+            if (touching) {
+                liftBackground();
+            }
             return true;
         } else {
             return false;
@@ -197,10 +222,31 @@
         releaseBackground();
     }
 
+    public void stopDragging(int position, SnapTarget target, long duration,
+            Interpolator interpolator) {
+        mHandle.setTouching(false, true /* animate */);
+        flingTo(position, target, duration, interpolator);
+        mWindowManager.setSlippery(true);
+        releaseBackground();
+    }
+
     public DividerSnapAlgorithm getSnapAlgorithm() {
+        if (mSnapAlgorithm == null) {
+            mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
+                    mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
+        }
         return mSnapAlgorithm;
     }
 
+    public int getCurrentPosition() {
+        getLocationOnScreen(mTempInt2);
+        if (isHorizontalDivision()) {
+            return mTempInt2[1] + mDividerInsets;
+        } else {
+            return mTempInt2[0] + mDividerInsets;
+        }
+    }
+
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         convertToScreenCoordinates(event);
@@ -211,13 +257,8 @@
                 mVelocityTracker.addMovement(event);
                 mStartX = (int) event.getX();
                 mStartY = (int) event.getY();
-                getLocationOnScreen(mTempInt2);
-                boolean result = startDragging(true /* animate */);
-                if (isHorizontalDivision()) {
-                    mStartPosition = mTempInt2[1] + mDividerInsets;
-                } else {
-                    mStartPosition = mTempInt2[0] + mDividerInsets;
-                }
+                boolean result = startDragging(true /* animate */, true /* touching */);
+                mStartPosition = getCurrentPosition();
                 mMoving = false;
                 return result;
             case MotionEvent.ACTION_MOVE:
@@ -265,8 +306,20 @@
         if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
             snapTarget = mSnapAlgorithm.getFirstSplitTarget();
         }
-        final SnapTarget finalTarget = snapTarget;
+        ValueAnimator anim = getFlingAnimator(position, snapTarget);
+        mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
+        anim.start();
+    }
 
+    private void flingTo(int position, SnapTarget target, long duration,
+            Interpolator interpolator) {
+        ValueAnimator anim = getFlingAnimator(position, target);
+        anim.setDuration(duration);
+        anim.setInterpolator(interpolator);
+        anim.start();
+    }
+
+    private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
@@ -274,19 +327,18 @@
                 resizeStack((Integer) animation.getAnimatedValue(),
                         animation.getAnimatedFraction() == 1f
                                 ? TASK_POSITION_SAME
-                                : finalTarget.position, finalTarget);
+                                : snapTarget.position, snapTarget);
             }
         });
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                commitSnapFlags(finalTarget);
+                commitSnapFlags(snapTarget);
                 mWindowManagerProxy.setResizing(false);
                 mDockSide = WindowManager.DOCKED_INVALID;
             }
         });
-        mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
-        anim.start();
+        return anim;
     }
 
     private void commitSnapFlags(SnapTarget target) {
@@ -359,6 +411,7 @@
         display.getDisplayInfo(info);
         mDisplayWidth = info.logicalWidth;
         mDisplayHeight = info.logicalHeight;
+        mSnapAlgorithm = null;
     }
 
     private int calculatePosition(int touchX, int touchY) {
@@ -607,4 +660,33 @@
         inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
                 mBackground.getRight(), mBackground.getBottom(), Op.UNION);
     }
+
+    public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
+        if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
+                && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
+            mGrowAfterRecentsDrawn = true;
+            startDragging(false /* animate */, false /* touching */);
+        }
+    }
+
+    public final void onBusEvent(DockingTopTaskEvent dockingEvent) {
+        if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
+            mGrowAfterRecentsDrawn = false;
+            mAnimateAfterRecentsDrawn = true;
+            startDragging(false /* animate */, false /* touching */);
+        }
+    }
+
+    public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+        if (mAnimateAfterRecentsDrawn) {
+            mAnimateAfterRecentsDrawn = false;
+            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+                    TOUCH_RESPONSE_INTERPOLATOR);
+        }
+        if (mGrowAfterRecentsDrawn) {
+            mGrowAfterRecentsDrawn = false;
+            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+                    TOUCH_RESPONSE_INTERPOLATOR);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index abe357a..92288a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -42,16 +42,20 @@
         implements TunerService.Tunable {
 
     private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
+    /**
+     * When dragging from the navigation bar, we drag in recents.
+     */
+    public static final int DRAG_MODE_NONE = -1;
 
     /**
      * When dragging from the navigation bar, we drag in recents.
      */
-    private static final int DRAG_MODE_RECENTS = 0;
+    public static final int DRAG_MODE_RECENTS = 0;
 
     /**
      * When dragging from the navigation bar, we drag the divider.
      */
-    private static final int DRAG_MODE_DIVIDER = 1;
+    public static final int DRAG_MODE_DIVIDER = 1;
 
     private RecentsComponent mRecentsComponent;
     private Divider mDivider;
@@ -207,12 +211,11 @@
                         < mContext.getResources().getDisplayMetrics().widthPixels / 2) {
                     createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
                 }
-                boolean docked = mRecentsComponent.dockTopTask(dragMode == DRAG_MODE_RECENTS,
-                        createMode, initialBounds);
+                boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds);
                 if (docked) {
                     mDragMode = dragMode;
                     if (mDragMode == DRAG_MODE_DIVIDER) {
-                        mDivider.getView().startDragging(false /* animate */);
+                        mDivider.getView().startDragging(false /* animate */, true /* touching*/);
                     }
                     mDockWindowTouchSlopExceeded = true;
                     MetricsLogger.action(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 354d704..6fa1f5df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -47,6 +47,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
@@ -112,6 +113,8 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BackDropView;
@@ -1102,9 +1105,22 @@
         @Override
         public boolean onLongClick(View v) {
             if (mRecents != null) {
-                boolean docked = mRecents.dockTopTask(false /* draggingInRecents */,
+                Point realSize = new Point();
+                mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+                        .getRealSize(realSize);
+                Rect initialBounds;
+
+                // Hack level over 9000: Make it one pixel smaller so activity manager doesn't
+                // dismiss it immediately again. Remove once b/26777526 is fixed.
+                if (mContext.getResources().getConfiguration().orientation
+                        == Configuration.ORIENTATION_LANDSCAPE) {
+                    initialBounds = new Rect(0, 0, realSize.x - 1, realSize.y);
+                } else {
+                    initialBounds = new Rect(0, 0, realSize.x, realSize.y - 1);
+                }
+                boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
                         ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
-                        null /* initialBounds */);
+                        initialBounds);
                 if (docked) {
                     MetricsLogger.action(mContext,
                             MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS);