Showing docked stack divider window.

When there is docked stack, we want to show a "handle" through which the
user will resize the docked stack. We add it from the system process,
because we want to avoid IPC calls.

Change-Id: If15fd2a0fcb7077446d1ba6c533acb3028a42039
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45bc1df..92e473d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -226,6 +226,7 @@
             @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
+            @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"),
         })
         public int type;
 
@@ -565,6 +566,13 @@
         public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
 
         /**
+         * Window for displaying a handle used for resizing docked stacks. This window is owned
+         * by the system process.
+         * @hide
+         */
+        public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/res/res/layout/docked_stack_divider.xml b/core/res/res/layout/docked_stack_divider.xml
new file mode 100644
index 0000000..aa6e68d
--- /dev/null
+++ b/core/res/res/layout/docked_stack_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="@dimen/docked_stack_divider_thickness"
+        android:layout_height="match_parent"
+        android:background="@android:color/black"
+        />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8635a4f..2621bc9c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -45,6 +45,9 @@
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
     <dimen name="status_bar_edge_ignore">5dp</dimen>
 
+    <!-- Width of a divider bar used to resize docked stacks. -->
+    <dimen name="docked_stack_divider_thickness">24dp</dimen>
+
     <!-- Min width for a tablet device -->
     <dimen name="min_xlarge_screen_width">800dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4edc847..5dc9ca9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1477,6 +1477,7 @@
   <java-symbol type="bool" name="config_showNavigationBar" />
   <java-symbol type="bool" name="config_supportAutoRotation" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
+  <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
@@ -1719,6 +1720,7 @@
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
+  <java-symbol type="layout" name="docked_stack_divider" />
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 91c3d48..ff2a2ee 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -967,8 +967,8 @@
 
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
-                PackageManager.GET_SERVICES 
-                  | PackageManager.GET_META_DATA 
+                PackageManager.GET_SERVICES
+                  | PackageManager.GET_META_DATA
                   | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 mCurrentUserId);
 
@@ -3217,7 +3217,8 @@
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
-                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
+                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+                case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
                     return AccessibilityWindowInfo.TYPE_SYSTEM;
                 }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 04d382d..3974205 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2003,6 +2003,7 @@
             case TYPE_SYSTEM_DIALOG:
             case TYPE_VOLUME_OVERLAY:
             case TYPE_PRIVATE_PRESENTATION:
+            case TYPE_DOCK_DIVIDER:
                 break;
         }
 
@@ -2134,54 +2135,56 @@
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
             return 13;
+        case TYPE_DOCK_DIVIDER:
+            return 14;
         case TYPE_KEYGUARD_SCRIM:
             // the safety window that shows behind keyguard while keyguard is starting
-            return 14;
-        case TYPE_STATUS_BAR_SUB_PANEL:
             return 15;
-        case TYPE_STATUS_BAR:
+        case TYPE_STATUS_BAR_SUB_PANEL:
             return 16;
-        case TYPE_STATUS_BAR_PANEL:
+        case TYPE_STATUS_BAR:
             return 17;
-        case TYPE_KEYGUARD_DIALOG:
+        case TYPE_STATUS_BAR_PANEL:
             return 18;
+        case TYPE_KEYGUARD_DIALOG:
+            return 19;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 19;
+            return 20;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 20;
+            return 21;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 21;
+            return 22;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 22;
+            return 23;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 23;
+            return 24;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 24;
+            return 25;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 25;
+            return 26;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 26;
+            return 27;
         case TYPE_ACCESSIBILITY_OVERLAY:
             // overlay put by accessibility services to intercept user interaction
-            return 27;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 28;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 29;
+        case TYPE_BOOT_PROGRESS:
+            return 30;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 30;
+            return 31;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
@@ -2271,6 +2274,7 @@
             case TYPE_WALLPAPER:
             case TYPE_DREAM:
             case TYPE_KEYGUARD_SCRIM:
+            case TYPE_DOCK_DIVIDER:
                 return false;
             default:
                 // Hide only windows below the keyguard host window.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index cb0dba8..4392ab4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
 
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
@@ -111,6 +112,8 @@
     /** Remove this display when animation on it has completed. */
     boolean mDeferredRemoval;
 
+    final DockedStackDividerController mDividerControllerLocked;
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -122,6 +125,7 @@
         display.getMetrics(mDisplayMetrics);
         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         mService = service;
+        mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
     }
 
     int getDisplayId() {
@@ -552,4 +556,14 @@
     public String toString() {
         return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
     }
+
+    TaskStack getDockedStack() {
+        for (int i = mStacks.size() - 1; i >= 0; i--) {
+            TaskStack stack = mStacks.get(i);
+            if (stack.mStackId == DOCKED_STACK_ID) {
+                return stack;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
new file mode 100644
index 0000000..ad207d4
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 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.server.wm;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+/**
+ * Controls showing and hiding of a docked stack divider on the display.
+ */
+public class DockedStackDividerController {
+    private static final String TAG = "DockedStackDivider";
+    private final Context mContext;
+    private final int mDividerWidth;
+    private final DisplayContent mDisplayContent;
+    private View mView;
+    private Rect mTmpRect = new Rect();
+
+    DockedStackDividerController(Context context, DisplayContent displayContent) {
+        mContext = context;
+        mDisplayContent = displayContent;
+        mDividerWidth = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+    }
+
+    private void addDivider() {
+        View view = LayoutInflater.from(mContext).inflate(
+                com.android.internal.R.layout.docked_stack_divider, null);
+        WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
+                FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
+                        | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
+                PixelFormat.OPAQUE);
+        params.setTitle(TAG);
+        manager.addView(view, params, mDisplayContent.getDisplay(), null);
+        mView = view;
+    }
+
+    private void removeDivider() {
+        WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+        manager.removeView(mView, true /* immediate */);
+        mView = null;
+    }
+
+    boolean hasDivider() {
+        return mView != null;
+    }
+
+    void update() {
+        TaskStack stack = mDisplayContent.getDockedStack();
+        if (stack != null && mView == null) {
+            addDivider();
+        } else if (stack == null && mView != null) {
+            removeDivider();
+        }
+    }
+
+    int getWidth() {
+        return mDividerWidth;
+    }
+
+
+    void positionDockedStackedDivider(Rect frame) {
+        TaskStack stack = mDisplayContent.getDockedStack();
+        if (stack == null) {
+            // Unfortunately we might end up with still having a divider, even though the underlying
+            // stack was already removed. This is because we are on AM thread and the removal of the
+            // divider was deferred to WM thread and hasn't happened yet.
+            return;
+        }
+        final @TaskStack.DockSide int side = stack.getDockSide();
+        stack.getBounds(mTmpRect);
+        switch (side) {
+            case TaskStack.DOCKED_LEFT:
+                frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
+                break;
+            case TaskStack.DOCKED_TOP:
+                frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
+                        mTmpRect.bottom + frame.height());
+                break;
+            case TaskStack.DOCKED_RIGHT:
+                frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
+                break;
+            case TaskStack.DOCKED_BOTTOM:
+                frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
+                break;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4541dd6..6ebff42 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
@@ -432,6 +433,10 @@
         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
     }
 
+    boolean inDockedWorkspace() {
+        return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
+    }
+
     @Override
     public boolean isFullscreen() {
         return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1362555..96fcf93 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -352,7 +352,8 @@
             // the docked stack occupies a dedicated region on screen.
             bounds = new Rect();
             displayContent.getLogicalDisplayRect(mTmpRect);
-            getInitialDockedStackBounds(mTmpRect, bounds, mStackId);
+            getInitialDockedStackBounds(mTmpRect, bounds, mStackId,
+                    mDisplayContent.mDividerControllerLocked.getWidth() / 2);
         }
 
         updateDisplayInfo(bounds);
@@ -371,27 +372,29 @@
      * @param displayRect The bounds of the display the docked stack is on.
      * @param outBounds Output bounds that should be used for the stack.
      * @param stackId Id of stack we are calculating the bounds for.
+     * @param adjustment
      */
-    private static void getInitialDockedStackBounds(
-            Rect displayRect, Rect outBounds, int stackId) {
+    private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId,
+            int adjustment) {
         // Docked stack start off occupying half the screen space.
+        final boolean dockedStack = stackId == DOCKED_STACK_ID;
         final boolean splitHorizontally = displayRect.width() > displayRect.height();
         final boolean topOrLeftCreateMode =
                 WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-        final boolean placeTopOrLeft = (stackId == DOCKED_STACK_ID && topOrLeftCreateMode)
-                || (stackId != DOCKED_STACK_ID && !topOrLeftCreateMode);
+        final boolean placeTopOrLeft = (dockedStack && topOrLeftCreateMode)
+                || (!dockedStack && !topOrLeftCreateMode);
         outBounds.set(displayRect);
         if (placeTopOrLeft) {
             if (splitHorizontally) {
-                outBounds.right = displayRect.centerX();
+                outBounds.right = displayRect.centerX() - adjustment;
             } else {
-                outBounds.bottom = displayRect.centerY();
+                outBounds.bottom = displayRect.centerY() - adjustment;
             }
         } else {
             if (splitHorizontally) {
-                outBounds.left = displayRect.centerX();
+                outBounds.left = displayRect.centerX() + adjustment;
             } else {
-                outBounds.top = displayRect.centerY();
+                outBounds.top = displayRect.centerY() + adjustment;
             }
         }
     }
@@ -404,7 +407,8 @@
     private void resizeNonDockedStacks(boolean fullscreen) {
         mDisplayContent.getLogicalDisplayRect(mTmpRect);
         if (!fullscreen) {
-            getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID);
+            getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID,
+                    mDisplayContent.mDividerControllerLocked.getWidth());
         }
 
         final int count = mService.mStackIdToStack.size();
@@ -546,14 +550,14 @@
         final int orientation = mService.mCurConfiguration.orientation;
         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
             // Portrait mode, docked either at the top or the bottom.
-            if (mTmpRect.top - mBounds.top < mTmpRect.bottom - mBounds.bottom) {
+            if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) {
                 return DOCKED_TOP;
             } else {
                 return DOCKED_BOTTOM;
             }
         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             // Landscape mode, docked either on the left or on the right.
-            if (mTmpRect.left - mBounds.left < mTmpRect.right - mBounds.right) {
+            if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) {
                 return DOCKED_LEFT;
             } else {
                 return DOCKED_RIGHT;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 29598ab..d510c4a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -33,6 +34,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -921,6 +923,7 @@
         mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
 
+
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
         initPolicy();
 
@@ -1854,6 +1857,11 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_DOCK_DIVIDER) {
+                if (displayContent.mDividerControllerLocked.hasDivider()) {
+                    Slog.w(TAG, "Attempted to add docked stack divider twice. Aborting.");
+                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                }
             } else if (token.appWindowToken != null) {
                 Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
                 // It is not valid to use an app token with other system types; we will
@@ -4521,7 +4529,10 @@
                     }
                     stack.attachDisplayContent(displayContent);
                     displayContent.attachStack(stack, onTop);
-
+                    if (stack.mStackId == DOCKED_STACK_ID) {
+                        mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER,
+                                displayContent).sendToTarget();
+                    }
                     moveStackWindowsLocked(displayContent);
                     final WindowList windows = displayContent.getWindowList();
                     for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
@@ -4544,6 +4555,11 @@
     void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
         displayContent.detachStack(stack);
         stack.detachDisplay();
+        // We can't directly remove the divider, because only the WM thread can do these operations
+        // and we can be on AM thread.
+        if (stack.mStackId == DOCKED_STACK_ID) {
+            mH.obtainMessage(H.UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget();
+        }
     }
 
     public void detachStack(int stackId) {
@@ -7220,6 +7236,8 @@
         public static final int TAP_DOWN_OUTSIDE_TASK = 40;
         public static final int FINISH_TASK_POSITIONING = 41;
 
+        public static final int UPDATE_DOCKED_STACK_DIVIDER = 42;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7759,6 +7777,13 @@
                     }
                 }
                 break;
+                case UPDATE_DOCKED_STACK_DIVIDER: {
+                    DisplayContent content = (DisplayContent) msg.obj;
+                    synchronized (mWindowMap) {
+                        content.mDividerControllerLocked.update();
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a6478a0..64440d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -23,6 +23,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -707,6 +708,8 @@
             mContentFrame.set(mFrame);
             mVisibleFrame.set(mContentFrame);
             mStableFrame.set(mContentFrame);
+        } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+            mDisplayContent.mDividerControllerLocked.positionDockedStackedDivider(mFrame);
         } else {
             mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
                     Math.max(mContentFrame.top, mFrame.top),