Implement divider UX interactions

- Update visuals to spec
- Divider lifts when touching
- Implement basic version of snap points and animations
- Implement touch conflict behavior: If touched around 48x48dp
area around the handle, the divider handles all these touches.
If touched outside of the black background divider, touch goes
directly to underlying window. If touch on the black background
divider, touch is considered slippery and thus the window in
which the touch trace moves gets the touches.

Change-Id: I0307c191ae032672c4b73d439c23cf9833d3fce6
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bfb0d10..28756f5 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -45,8 +45,12 @@
     <!-- 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>
+    <!-- Width of the window of the divider bar used to resize docked stacks. -->
+    <dimen name="docked_stack_divider_thickness">48dp</dimen>
+
+    <!-- How much the content in the divider is inset from the window bounds when resting. Used to
+         calculate the bounds of the stacks-->
+    <dimen name="docked_stack_divider_insets">18dp</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 5c65366..cda7faa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1481,6 +1481,7 @@
   <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="docked_stack_divider_insets" />
   <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" />
@@ -1724,7 +1725,6 @@
   <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/packages/SystemUI/res/drawable/docked_divider_handle.xml b/packages/SystemUI/res/drawable/docked_divider_handle.xml
new file mode 100644
index 0000000..ea32548
--- /dev/null
+++ b/packages/SystemUI/res/drawable/docked_divider_handle.xml
@@ -0,0 +1,22 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2 (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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shape="rectangle">
+    <size android:height="@dimen/docked_divider_handle_height"
+        android:width="@dimen/docked_divider_handle_width" />
+    <corners radius="1dp" />
+    <solid android:color="@color/docked_divider_handle" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 2f840ca..5f42856 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -14,8 +14,22 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="@*android:dimen/docked_stack_divider_thickness"
+<com.android.systemui.stackdivider.DividerView
+        xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_height="match_parent"
-        android:background="@android:color/black"
-        />
+        android:layout_width="match_parent">
+
+    <View
+        style="@style/DockedDividerBackground"
+        android:id="@+id/docked_divider_background"
+        android:background="@color/docked_divider_background"/>
+
+    <ImageButton
+        style="@style/DockedDividerHandle"
+        android:id="@+id/docked_divider_handle"
+        android:layout_height="48dp"
+        android:layout_width="48dp"
+        android:background="@null"
+        android:src="@drawable/docked_divider_handle"/>
+
+</com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 6ef1ada..456391d 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,4 +22,7 @@
     <!-- Standard notification width + gravity -->
     <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
     <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
+
+    <dimen name="docked_divider_handle_width">2dp</dimen>
+    <dimen name="docked_divider_handle_height">24dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 8919198..dd396d9 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -18,4 +18,15 @@
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
         <item name="android:layout_width">360dp</item>
     </style>
+
+    <style name="DockedDividerBackground">
+        <item name="android:layout_width">12dp</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:layout_gravity">center_horizontal</item>
+    </style>
+
+    <style name="DockedDividerHandle">
+        <item name="android:layout_gravity">center_vertical</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f40f0d9..26a0577 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -143,4 +143,7 @@
 
     <color name="fab_ripple">#1fffffff</color><!-- 12% white -->
     <color name="fab_shape">#ff009688</color><!-- Teal 500 -->
+
+    <color name="docked_divider_background">#ff000000</color>
+    <color name="docked_divider_handle">#ffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7f2c851..73f63a9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -578,7 +578,10 @@
     <!-- TODO: Remove this -->
     <dimen name="qs_header_neg_padding">-8dp</dimen>
 
-    <!-- Distance from the edge of the screen when scrubbing the docked stack divider is considered
-         a dismissal -->
-    <dimen name="docked_stack_divider_dismiss_distance">100dp</dimen>
+    <!-- How high we lift the divider when touching -->
+    <dimen name="docked_stack_divider_lift_elevation">6dp</dimen>
+
+    <dimen name="docked_divider_handle_width">24dp</dimen>
+    <dimen name="docked_divider_handle_height">2dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9e942f0..4462a03 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -304,4 +304,14 @@
         <item name="android:background">@drawable/btn_borderless_rect</item>
     </style>
 
+    <style name="DockedDividerBackground">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">12dp</item>
+        <item name="android:layout_gravity">center_vertical</item>
+    </style>
+
+    <style name="DockedDividerHandle">
+        <item name="android:layout_gravity">center_horizontal</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index f8a80f0..949efc5 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -27,7 +27,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.systemui.stackdivider.DockedStackDivider;
+import com.android.systemui.stackdivider.Divider;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -53,7 +53,7 @@
             com.android.systemui.power.PowerUI.class,
             com.android.systemui.media.RingtonePlayer.class,
             com.android.systemui.keyboard.KeyboardUI.class,
-            DockedStackDivider.class
+            Divider.class
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
new file mode 100644
index 0000000..dd894ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.content.res.Configuration;
+import android.view.LayoutInflater;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+/**
+ * Controls the docked stack divider.
+ */
+public class Divider extends SystemUI {
+    private static final String TAG = "Divider";
+    private int mDividerWindowWidth;
+    private DividerWindowManager mWindowManager;
+
+    @Override
+    public void start() {
+        mWindowManager = new DividerWindowManager(mContext);
+        mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+        update(mContext.getResources().getConfiguration());
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        update(newConfig);
+    }
+
+    private void addDivider(Configuration configuration) {
+        DividerView view = (DividerView)
+                LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
+        final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
+        final int width = landscape ? mDividerWindowWidth : MATCH_PARENT;
+        final int height = landscape ? MATCH_PARENT : mDividerWindowWidth;
+        mWindowManager.add(view, width, height);
+        view.setWindowManager(mWindowManager);
+    }
+
+    private void removeDivider() {
+        mWindowManager.remove();
+    }
+
+    private void update(Configuration configuration) {
+        removeDivider();
+        addDivider(configuration);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
new file mode 100644
index 0000000..5f983c5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.DisplayInfo;
+
+import com.android.systemui.statusbar.FlingAnimationUtils;
+
+import java.util.ArrayList;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+
+/**
+ * Calculates the snap targets and the snap position given a position and a velocity. All positions
+ * here are to be interpreted as the left/top edge of the divider rectangle.
+ */
+public class DividerSnapAlgorithm {
+
+    private final Context mContext;
+    private final FlingAnimationUtils mFlingAnimationUtils;
+    private final int mDividerSize;
+    private final ArrayList<SnapTarget> mTargets;
+
+    /** The first target which is still splitting the screen */
+    private final SnapTarget mFirstSplitTarget;
+
+    /** The last target which is still splitting the screen */
+    private final SnapTarget mLastSplitTarget;
+
+    private final SnapTarget mDismissStartTarget;
+    private final SnapTarget mDismissEndTarget;
+
+    public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
+            int dividerSize, boolean isHorizontalDivision) {
+        mContext = ctx;
+        mFlingAnimationUtils = flingAnimationUtils;
+        mDividerSize = dividerSize;
+        mTargets = calculateTargets(isHorizontalDivision);
+        mFirstSplitTarget = mTargets.get(1);
+        mLastSplitTarget = mTargets.get(mTargets.size() - 2);
+        mDismissStartTarget = mTargets.get(0);
+        mDismissEndTarget = mTargets.get(mTargets.size() - 1);
+    }
+
+    public SnapTarget calculateSnapTarget(int position, float velocity) {
+        if (Math.abs(velocity) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+            return snap(position);
+        }
+        if (position < mFirstSplitTarget.position && velocity < 0) {
+            return mDismissStartTarget;
+        }
+        if (position > mLastSplitTarget.position && velocity > 0) {
+            return mDismissEndTarget;
+        }
+        if (velocity < 0) {
+            return mFirstSplitTarget;
+        } else {
+            return mLastSplitTarget;
+        }
+    }
+
+    private SnapTarget snap(int position) {
+        int minIndex = -1;
+        int minDistance = Integer.MAX_VALUE;
+        int size = mTargets.size();
+        for (int i = 0; i < size; i++) {
+            int distance = Math.abs(position - mTargets.get(i).position);
+            if (distance < minDistance) {
+                minIndex = i;
+                minDistance = distance;
+            }
+        }
+        return mTargets.get(minIndex);
+    }
+
+    private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
+        ArrayList<SnapTarget> targets = new ArrayList<>();
+        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+        int dividerMax = isHorizontalDivision
+                ? info.heightPixels
+                : info.widthPixels;
+
+        // TODO: Better calculation
+        targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+        targets.add(new SnapTarget((int) (0.35f * dividerMax) - mDividerSize / 2,
+                SnapTarget.FLAG_NONE));
+        targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
+        targets.add(new SnapTarget((int) (0.65f * dividerMax) - mDividerSize / 2,
+                SnapTarget.FLAG_NONE));
+        targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+        return targets;
+    }
+
+    /**
+     * Represents a snap target for the divider.
+     */
+    public static class SnapTarget {
+        public static final int FLAG_NONE = 0;
+
+        /** If the divider reaches this value, the left/top task should be dismissed. */
+        public static final int FLAG_DISMISS_START = 1;
+
+        /** If the divider reaches this value, the right/bottom task should be dismissed */
+        public static final int FLAG_DISMISS_END = 2;
+
+        public final int position;
+        public final int flag;
+
+        public SnapTarget(int position, int flag) {
+            this.position = position;
+            this.flag = flag;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
new file mode 100644
index 0000000..14d8fef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewTreeObserver.InternalInsetsInfo;
+import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+
+/**
+ * Docked stack divider.
+ */
+public class DividerView extends FrameLayout implements OnTouchListener,
+        OnComputeInternalInsetsListener {
+
+    private static final String TAG = "DividerView";
+
+    private ImageButton mHandle;
+    private View mBackground;
+    private int mStartX;
+    private int mStartY;
+    private int mStartPosition;
+    private int mDockSide;
+    private final int[] mTempInt2 = new int[2];
+
+    private int mDividerInsets;
+    private int mDisplayWidth;
+    private int mDisplayHeight;
+    private int mDividerWindowWidth;
+    private int mDividerSize;
+    private int mTouchElevation;
+
+    private final Rect mTmpRect = new Rect();
+    private final Rect mLastResizeRect = new Rect();
+    private final WindowManagerProxy mWindowManagerProxy = new WindowManagerProxy();
+    private Interpolator mFastOutSlowInInterpolator;
+    private final Interpolator mTouchResponseInterpolator =
+            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+    private DividerWindowManager mWindowManager;
+    private VelocityTracker mVelocityTracker;
+    private FlingAnimationUtils mFlingAnimationUtils;
+
+    public DividerView(Context context) {
+        super(context);
+    }
+
+    public DividerView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mHandle = (ImageButton) findViewById(R.id.docked_divider_handle);
+        mBackground = findViewById(R.id.docked_divider_background);
+        mHandle.setOnTouchListener(this);
+        mDividerWindowWidth = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+        mDividerInsets = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_insets);
+        mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
+        mTouchElevation = getResources().getDimensionPixelSize(
+                R.dimen.docked_stack_divider_lift_elevation);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+        mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
+        updateDisplayInfo();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+    }
+
+    public void setWindowManager(DividerWindowManager windowManager) {
+        mWindowManager = windowManager;
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        convertToScreenCoordinates(event);
+        final int action = event.getAction() & MotionEvent.ACTION_MASK;
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mVelocityTracker = VelocityTracker.obtain();
+                mVelocityTracker.addMovement(event);
+                mStartX = (int) event.getX();
+                mStartY = (int) event.getY();
+                getLocationOnScreen(mTempInt2);
+                mDockSide = mWindowManagerProxy.getDockSide();
+                if (isHorizontalDivision()) {
+                    mStartPosition = mTempInt2[1] + mDividerInsets;
+                } else {
+                    mStartPosition = mTempInt2[0] + mDividerInsets;
+                }
+                if (mDockSide != WindowManager.DOCKED_INVALID) {
+                    mWindowManagerProxy.setResizing(true);
+                    mWindowManager.setSlippery(false);
+                    liftBackground();
+                    return true;
+                } else {
+                    return false;
+                }
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(event);
+                int x = (int) event.getX();
+                int y = (int) event.getY();
+                if (mDockSide != WindowManager.DOCKED_INVALID) {
+                    resizeStack(calculatePosition(x, y));
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mVelocityTracker.addMovement(event);
+
+                x = (int) event.getRawX();
+                y = (int) event.getRawY();
+
+                mVelocityTracker.computeCurrentVelocity(1000);
+                fling(x, y, mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
+
+                mWindowManager.setSlippery(true);
+                releaseBackground();
+                break;
+        }
+        return true;
+    }
+
+    private void convertToScreenCoordinates(MotionEvent event) {
+        event.setLocation(event.getRawX(), event.getRawY());
+    }
+
+    private void fling(int x, int y, float xVelocity, float yVelocity) {
+        int position = calculatePosition(x, y);
+        float velocity = isHorizontalDivision() ? yVelocity : xVelocity;
+        final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
+                mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
+
+        ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
+        anim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                resizeStack((Integer) animation.getAnimatedValue());
+            }
+        });
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                commitSnapFlags(snapTarget);
+                mWindowManagerProxy.setResizing(false);
+                mDockSide = WindowManager.DOCKED_INVALID;
+            }
+        });
+        mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
+        anim.start();
+    }
+
+    private void commitSnapFlags(SnapTarget target) {
+        if (target.flag == SnapTarget.FLAG_NONE) {
+            return;
+        }
+        boolean dismissOrMaximize;
+        if (target.flag == SnapTarget.FLAG_DISMISS_START) {
+            dismissOrMaximize = mDockSide == WindowManager.DOCKED_LEFT
+                    || mDockSide == WindowManager.DOCKED_TOP;
+        } else {
+            dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
+                    || mDockSide == WindowManager.DOCKED_BOTTOM;
+        }
+        if (dismissOrMaximize) {
+            mWindowManagerProxy.dismissDockedStack();
+        } else {
+            mWindowManagerProxy.maximizeDockedStack();
+        }
+    }
+
+    private void liftBackground() {
+        if (isHorizontalDivision()) {
+            mBackground.animate().scaleY(1.5f);
+        } else {
+            mBackground.animate().scaleX(1.5f);
+        }
+        mBackground.animate()
+                .setInterpolator(mTouchResponseInterpolator)
+                .setDuration(150)
+                .translationZ(mTouchElevation);
+
+        // Lift handle as well so it doesn't get behind the background, even though it doesn't
+        // cast shadow.
+        mHandle.animate()
+                .setInterpolator(mTouchResponseInterpolator)
+                .setDuration(150)
+                .translationZ(mTouchElevation);
+    }
+
+    private void releaseBackground() {
+        mBackground.animate()
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .setDuration(200)
+                .translationZ(0)
+                .scaleX(1f)
+                .scaleY(1f);
+        mHandle.animate()
+                .setInterpolator(mFastOutSlowInInterpolator)
+                .setDuration(200)
+                .translationZ(0);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateDisplayInfo();
+    }
+
+    private void updateDisplayInfo() {
+        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+        mDisplayWidth = info.widthPixels;
+        mDisplayHeight = info.heightPixels;
+    }
+
+    private int calculatePosition(int touchX, int touchY) {
+        return isHorizontalDivision() ? calculateYPosition(touchY) : calculateXPosition(touchX);
+    }
+
+    private boolean isHorizontalDivision() {
+        return mDockSide == WindowManager.DOCKED_TOP
+                || mDockSide == WindowManager.DOCKED_BOTTOM;
+    }
+
+    private int calculateXPosition(int touchX) {
+        return mStartPosition + touchX - mStartX;
+    }
+
+    private int calculateYPosition(int touchY) {
+        return mStartPosition + touchY - mStartY;
+    }
+
+    private void resizeStack(int position) {
+        mTmpRect.set(0, 0, mDisplayWidth, mDisplayHeight);
+        switch (mDockSide) {
+            case WindowManager.DOCKED_LEFT:
+                mTmpRect.right = position;
+                break;
+            case WindowManager.DOCKED_TOP:
+                mTmpRect.bottom = position;
+                break;
+            case WindowManager.DOCKED_RIGHT:
+                mTmpRect.left = position + mDividerWindowWidth - 2 * mDividerInsets;
+                break;
+            case WindowManager.DOCKED_BOTTOM:
+                mTmpRect.top = position + mDividerWindowWidth - 2 * mDividerInsets;
+                break;
+        }
+        if (mTmpRect.equals(mLastResizeRect)) {
+            return;
+        }
+        mLastResizeRect.set(mTmpRect);
+        mWindowManagerProxy.resizeDockedStack(mTmpRect);
+    }
+
+    @Override
+    public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
+        inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+        inoutInfo.touchableRegion.set(mHandle.getLeft(), mHandle.getTop(), mHandle.getRight(),
+                mHandle.getBottom());
+        inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
+                mBackground.getRight(), mBackground.getBottom(), Op.UNION);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
new file mode 100644
index 0000000..2251874
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.View;
+import android.view.WindowManager;
+
+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_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+/**
+ * Manages the window parameters of the docked stack divider.
+ */
+public class DividerWindowManager {
+
+    private static final String WINDOW_TITLE = "DockedStackDivider";
+
+    private final WindowManager mWindowManager;
+    private WindowManager.LayoutParams mLp;
+    private View mView;
+
+    public DividerWindowManager(Context ctx) {
+        mWindowManager = ctx.getSystemService(WindowManager.class);
+    }
+
+    public void add(View view, int width, int height) {
+        mLp = new WindowManager.LayoutParams(
+                width, height, TYPE_DOCK_DIVIDER,
+                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
+                        | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
+                PixelFormat.TRANSLUCENT);
+        mLp.setTitle(WINDOW_TITLE);
+        mWindowManager.addView(view, mLp);
+        mView = view;
+    }
+
+    public void remove() {
+        if (mView != null) {
+            mWindowManager.removeView(mView);
+        }
+        mView = null;
+    }
+
+    public void setSlippery(boolean slippery) {
+        boolean changed = false;
+        if (slippery && (mLp.flags & FLAG_SLIPPERY) == 0) {
+            mLp.flags |= FLAG_SLIPPERY;
+            changed = true;
+        } else if (!slippery && (mLp.flags & FLAG_SLIPPERY) != 0) {
+            mLp.flags &= ~FLAG_SLIPPERY;
+            changed = true;
+        }
+        if (changed) {
+            mWindowManager.updateViewLayout(mView, mLp);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DockedStackDivider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DockedStackDivider.java
deleted file mode 100644
index 646ee47..0000000
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DockedStackDivider.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.stackdivider;
-
-import android.app.ActivityManagerNative;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-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_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-
-/**
- * Controls showing and hiding of a docked stack divider on the display.
- */
-public class DockedStackDivider extends SystemUI implements View.OnTouchListener {
-    private static final String TAG = "DockedStackDivider";
-    private int mDividerWidth;
-    private int mSideMargin;
-    private int mDisplayWidth;
-    private int mDisplayHeight;
-    private int mDisplayOrientation;
-    private View mView;
-    private final Rect mTmpRect = new Rect();
-    private final Rect mTmpRectBackground = new Rect();
-    private final Rect mLastResizeRect = new Rect();
-
-    @GuardedBy("mResizeRect")
-    private final Rect mResizeRect = new Rect();
-
-    private int mStartX;
-    private int mStartY;
-    private int mStartPosition;
-    private int mDockSide;
-    private WindowManager mWindowManager;
-    private final int[] mTempInt2 = new int[2];
-    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
-
-    private final Runnable mResizeRunnable = new Runnable() {
-        @Override
-        public void run() {
-            synchronized (mResizeRect) {
-                mTmpRectBackground.set(mResizeRect);
-            }
-            try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID,
-                        mTmpRectBackground, true);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to resize stack: " + e);
-            }
-        }
-    };
-
-    @Override
-    public void start() {
-        mWindowManager = mContext.getSystemService(WindowManager.class);
-        updateDisplayInfo();
-        mDividerWidth = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_divider_thickness);
-        mSideMargin = mContext.getResources().getDimensionPixelSize(
-                R.dimen.docked_stack_divider_dismiss_distance);
-        update(mContext.getResources().getConfiguration());
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        updateDisplayInfo();
-        update(newConfig);
-    }
-
-    private void addDivider(Configuration configuration) {
-        View view = LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
-        view.setOnTouchListener(this);
-        final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
-        final int width = landscape ? mDividerWidth : MATCH_PARENT;
-        final int height = landscape ? MATCH_PARENT : mDividerWidth;
-        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-                width, height, TYPE_DOCK_DIVIDER,
-                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
-                        | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        params.setTitle(TAG);
-        mWindowManager.addView(view, params);
-        mView = view;
-    }
-
-    private void removeDivider() {
-        if (mView == null) return;
-        mView.setOnTouchListener(null);
-        mWindowManager.removeView(mView);
-        mView = null;
-    }
-
-
-    private void updateDisplayInfo() {
-        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
-        mDisplayWidth = info.widthPixels;
-        mDisplayHeight = info.heightPixels;
-        mDisplayOrientation = mContext.getResources().getConfiguration().orientation;
-    }
-
-    private void update(Configuration configuration) {
-        removeDivider();
-        addDivider(configuration);
-    }
-
-    int getWidth() {
-        return mDividerWidth;
-    }
-
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        final int action = event.getAction() & MotionEvent.ACTION_MASK;
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                // We use raw values, because getX/Y() would give us results relative to the
-                // dock divider bounds.
-                mStartX = (int) event.getRawX();
-                mStartY = (int) event.getRawY();
-                mView.getLocationOnScreen(mTempInt2);
-                if (mDisplayOrientation == ORIENTATION_LANDSCAPE) {
-                    mStartPosition = mTempInt2[0];
-                } else {
-                    mStartPosition = mTempInt2[1];
-                }
-                mDockSide = getDockSide();
-                if (mDockSide != WindowManager.DOCKED_INVALID) {
-                    setResizing(true);
-                    return true;
-                } else {
-                    return false;
-                }
-            case MotionEvent.ACTION_MOVE:
-                int x = (int) event.getRawX();
-                int y = (int) event.getRawY();
-                if (mDockSide != WindowManager.DOCKED_INVALID) {
-                    resizeStack(x, y);
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                x = (int) event.getRawX();
-                y = (int) event.getRawY();
-                // At most one of these will be executed, the other one will exit early.
-                maybeDismissTaskStack(x, y);
-                maybeMaximizeTaskStack(x, y);
-                mDockSide = WindowManager.DOCKED_INVALID;
-                setResizing(false);
-                break;
-        }
-        return true;
-    }
-
-    private void setResizing(boolean resizing) {
-        try {
-            WindowManagerGlobal.getWindowManagerService().setDockedStackResizing(resizing);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error calling setDockedStackResizing: " + e);
-        }
-    }
-
-    private int getDockSide() {
-        try {
-            return WindowManagerGlobal.getWindowManagerService().getDockedStackSide();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to get dock side: " + e);
-        }
-        return WindowManager.DOCKED_INVALID;
-    }
-
-    private void maybeMaximizeTaskStack(int x, int y) {
-        final int distance = distanceFromFullScreen(mDockSide, x, y);
-        if (distance == -1) {
-            Log.wtf(TAG, "maybeMaximizeTaskStack: Unknown dock side=" + mDockSide);
-            return;
-        }
-        if (distance <= mSideMargin) {
-            try {
-                ActivityManagerNative.getDefault().resizeStack(
-                        DOCKED_STACK_ID, null, true);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to resize stack: " + e);
-            }
-        }
-    }
-
-    private void maybeDismissTaskStack(int x, int y) {
-        final int distance = distanceFromDockSide(mDockSide, x, y);
-        if (distance == -1) {
-            Log.wtf(TAG, "maybeDismissTaskStack: Unknown dock side=" + mDockSide);
-            return;
-        }
-        if (distance <= mSideMargin) {
-            try {
-                ActivityManagerNative.getDefault().removeStack(DOCKED_STACK_ID);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to remove stack: " + e);
-            }
-        }
-    }
-
-    private int distanceFromFullScreen(int dockSide, int x, int y) {
-        switch (dockSide) {
-            case WindowManager.DOCKED_LEFT:
-                return mDisplayWidth - x;
-            case WindowManager.DOCKED_TOP:
-                return mDisplayHeight - y;
-            case WindowManager.DOCKED_RIGHT:
-                return x;
-            case WindowManager.DOCKED_BOTTOM:
-                return y;
-        }
-        return -1;
-    }
-
-    private int distanceFromDockSide(int dockSide, int x, int y) {
-        switch (dockSide) {
-            case WindowManager.DOCKED_LEFT:
-                return x;
-            case WindowManager.DOCKED_TOP:
-                return y;
-            case WindowManager.DOCKED_RIGHT:
-                return mDisplayWidth - x;
-            case WindowManager.DOCKED_BOTTOM:
-                return mDisplayHeight - y;
-        }
-        return -1;
-    }
-
-    private void resizeStack(int x, int y) {
-        int deltaX = x - mStartX;
-        int deltaY = y - mStartY;
-        mTmpRect.set(0, 0, mDisplayWidth, mDisplayHeight);
-        switch (mDockSide) {
-            case WindowManager.DOCKED_LEFT:
-                mTmpRect.right = mStartPosition + deltaX;
-                break;
-            case WindowManager.DOCKED_TOP:
-                mTmpRect.bottom = mStartPosition + deltaY;
-                break;
-            case WindowManager.DOCKED_RIGHT:
-                mTmpRect.left = mStartPosition + deltaX + getWidth();
-                break;
-            case WindowManager.DOCKED_BOTTOM:
-                mTmpRect.top = mStartPosition + deltaY + getWidth();
-                break;
-        }
-        if (mTmpRect.equals(mLastResizeRect)) {
-            return;
-        }
-        mLastResizeRect.set(mTmpRect);
-        synchronized (mResizeRect) {
-            mResizeRect.set(mTmpRect);
-        }
-        mExecutor.execute(mResizeRunnable);
-
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
new file mode 100644
index 0000000..94809bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.app.ActivityManagerNative;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.view.WindowManager.DOCKED_INVALID;
+
+/**
+ * Proxy to simplify calls into window manager/activity manager
+ */
+public class WindowManagerProxy {
+
+    private static final String TAG = "WindowManagerProxy";
+
+    @GuardedBy("mResizeRect")
+    private final Rect mResizeRect = new Rect();
+    private final Rect mTmpRect = new Rect();
+    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+    private final Runnable mResizeRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mResizeRect) {
+                mTmpRect.set(mResizeRect);
+            }
+            try {
+                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID,
+                        mTmpRect, true);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to resize stack: " + e);
+            }
+        }
+    };
+
+    public void resizeDockedStack(Rect rect) {
+        synchronized (mResizeRect) {
+            mResizeRect.set(rect);
+        }
+        mExecutor.execute(mResizeRunnable);
+    }
+
+    public void dismissDockedStack() {
+        try {
+            ActivityManagerNative.getDefault().removeStack(DOCKED_STACK_ID);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to remove stack: " + e);
+        }
+    }
+
+    public void maximizeDockedStack() {
+        try {
+            ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to resize stack: " + e);
+        }
+    }
+
+    public void setResizing(boolean resizing) {
+        try {
+            WindowManagerGlobal.getWindowManagerService().setDockedStackResizing(resizing);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error calling setDockedStackResizing: " + e);
+        }
+    }
+
+    public int getDockSide() {
+        try {
+            return WindowManagerGlobal.getWindowManagerService().getDockedStackSide();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get dock side: " + e);
+        }
+        return DOCKED_INVALID;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8d48dd8..6bdff1e 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -32,23 +32,26 @@
     private static final String TAG = "DockedStackDividerController";
 
     private final DisplayContent mDisplayContent;
-    private final int mDividerWidth;
+    private final int mDividerWindowWidth;
+    private final int mDividerInsets;
     private boolean mResizing;
     private WindowState mWindow;
     private final Rect mTmpRect = new Rect();
 
     DockedStackDividerController(Context context, DisplayContent displayContent) {
         mDisplayContent = displayContent;
-        mDividerWidth = context.getResources().getDimensionPixelSize(
+        mDividerWindowWidth = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
+        mDividerInsets = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_insets);
     }
 
     boolean isResizing() {
         return mResizing;
     }
 
-    int getWidthAdjustment() {
-        return mDividerWidth;
+    int getContentWidth() {
+        return mDividerWindowWidth - 2 * mDividerInsets;
     }
 
     void setResizing(boolean resizing) {
@@ -82,22 +85,21 @@
         stack.getBounds(mTmpRect);
         switch (side) {
             case DOCKED_LEFT:
-                frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
+                frame.set(mTmpRect.right - mDividerInsets, frame.top,
+                        mTmpRect.right + frame.width() - mDividerInsets, frame.bottom);
                 break;
             case DOCKED_TOP:
-                frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
-                        mTmpRect.bottom + frame.height());
+                frame.set(frame.left, mTmpRect.bottom - mDividerInsets,
+                        mTmpRect.right, mTmpRect.bottom + frame.height() - mDividerInsets);
                 break;
             case DOCKED_RIGHT:
-                frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
+                frame.set(mTmpRect.left - frame.width() + mDividerInsets, frame.top,
+                        mTmpRect.left + mDividerInsets, frame.bottom);
                 break;
             case DOCKED_BOTTOM:
-                frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
+                frame.set(frame.left, mTmpRect.top - frame.height() + mDividerInsets,
+                        frame.right, mTmpRect.top + mDividerInsets);
                 break;
         }
     }
-
-    public boolean hasWindow() {
-        return mWindow != null;
-    }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index f999402..3c3123f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -193,20 +193,6 @@
         inputWindowHandle.frameTop = frame.top;
         inputWindowHandle.frameRight = frame.right;
         inputWindowHandle.frameBottom = frame.bottom;
-        if (child.mAttrs.type == TYPE_DOCK_DIVIDER) {
-            // We need to determine if the divider is horizontal or vertical and adjust its handle
-            // frame accordingly.
-            int adjustment = displayContent.mDividerControllerLocked.getWidthAdjustment();
-            if (inputWindowHandle.frameRight - inputWindowHandle.frameLeft >
-                    inputWindowHandle.frameTop - inputWindowHandle.frameBottom) {
-                // Horizontal divider.
-                inputWindowHandle.frameTop -= adjustment;
-                inputWindowHandle.frameBottom += adjustment;
-            } else {
-                inputWindowHandle.frameLeft -= adjustment;
-                inputWindowHandle.frameRight += adjustment;
-            }
-        }
 
         if (child.mGlobalScale != 1) {
             // If we are scaling the window, input coordinates need
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index affbf10..7c02b43 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -386,7 +386,7 @@
             final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode
                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
             getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
-                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment(),
+                    mDisplayContent.mDividerControllerLocked.getContentWidth(),
                     dockedOnTopOrLeft);
         }
 
@@ -433,7 +433,7 @@
         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP
                 || dockedSide == DOCKED_LEFT;
         getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
-                mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), dockedOnTopOrLeft);
+                mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
 
     }
 
@@ -504,7 +504,7 @@
             final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode
                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
             getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
-                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), dockedOnTopOrLeft);
+                    mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
         }
 
         final int count = mService.mStackIdToStack.size();