Merge changes Ifd2de38a,I57633d60

* changes:
  Divider tuning
  Fix unneccesary activity relaunches
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 59a1e4a..5b40bc0 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.util.Log;
 
 import java.util.ArrayList;
 
@@ -30,6 +31,9 @@
  */
 public class DividerSnapAlgorithm {
 
+    private static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+    private static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+
     /**
      * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
      */
@@ -46,6 +50,7 @@
     private static final int SNAP_ONLY_1_1 = 2;
 
     private final float mMinFlingVelocityPxPerSecond;
+    private final float mMinDismissVelocityPxPerSecond;
     private final int mDisplayWidth;
     private final int mDisplayHeight;
     private final int mDividerSize;
@@ -64,10 +69,12 @@
     private final SnapTarget mDismissEndTarget;
     private final SnapTarget mMiddleTarget;
 
-    public DividerSnapAlgorithm(Resources res, float minFlingVelocityPxPerSecond,
-            int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
-            Rect insets) {
-        mMinFlingVelocityPxPerSecond = minFlingVelocityPxPerSecond;
+    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
+            boolean isHorizontalDivision, Rect insets) {
+        mMinFlingVelocityPxPerSecond =
+                MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
+        mMinDismissVelocityPxPerSecond =
+                MIN_DISMISS_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
         mDividerSize = dividerSize;
         mDisplayWidth = displayWidth;
         mDisplayHeight = displayHeight;
@@ -85,15 +92,24 @@
     }
 
     public SnapTarget calculateSnapTarget(int position, float velocity) {
-        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
-            return snap(position);
-        }
-        if (position < mFirstSplitTarget.position && velocity < 0) {
+        return calculateSnapTarget(position, velocity, true /* hardDismiss */);
+    }
+
+    /**
+     * @param position the top/left position of the divider
+     * @param velocity current dragging velocity
+     * @param hardDismiss if set, make it a bit harder to get reach the dismiss targets
+     */
+    public SnapTarget calculateSnapTarget(int position, float velocity, boolean hardDismiss) {
+        if (position < mFirstSplitTarget.position && velocity < -mMinDismissVelocityPxPerSecond) {
             return mDismissStartTarget;
         }
-        if (position > mLastSplitTarget.position && velocity > 0) {
+        if (position > mLastSplitTarget.position && velocity > mMinDismissVelocityPxPerSecond) {
             return mDismissEndTarget;
         }
+        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
+            return snap(position, hardDismiss);
+        }
         if (velocity < 0) {
             return mFirstSplitTarget;
         } else {
@@ -102,7 +118,7 @@
     }
 
     public SnapTarget calculateNonDismissingSnapTarget(int position) {
-        SnapTarget target = snap(position);
+        SnapTarget target = snap(position, false /* hardDismiss */);
         if (target == mDismissStartTarget) {
             return mFirstSplitTarget;
         } else if (target == mDismissEndTarget) {
@@ -146,12 +162,16 @@
         return mDismissEndTarget;
     }
 
-    private SnapTarget snap(int position) {
+    private SnapTarget snap(int position, boolean hardDismiss) {
         int minIndex = -1;
-        int minDistance = Integer.MAX_VALUE;
+        float minDistance = Float.MAX_VALUE;
         int size = mTargets.size();
         for (int i = 0; i < size; i++) {
-            int distance = Math.abs(position - mTargets.get(i).position);
+            SnapTarget target = mTargets.get(i);
+            float distance = Math.abs(position - target.position);
+            if (hardDismiss) {
+                distance /= target.distanceMultiplier;
+            }
             if (distance < minDistance) {
                 minIndex = i;
                 minDistance = distance;
@@ -165,7 +185,7 @@
         int dividerMax = isHorizontalDivision
                 ? mDisplayHeight
                 : mDisplayWidth;
-        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f));
         switch (mSnapMode) {
             case SNAP_MODE_16_9:
                 addRatio16_9Targets(isHorizontalDivision);
@@ -177,7 +197,7 @@
                 addMiddleTarget(isHorizontalDivision);
                 break;
         }
-        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
     }
 
     private void addFixedDivisionTargets(boolean isHorizontalDivision) {
@@ -232,9 +252,20 @@
         public final int position;
         public final int flag;
 
+        /**
+         * Multiplier used to calculate distance to snap position. The lower this value, the harder
+         * it's to snap on this target
+         */
+        private final float distanceMultiplier;
+
         public SnapTarget(int position, int flag) {
+            this(position, flag, 1f);
+        }
+
+        public SnapTarget(int position, int flag, float distanceMultiplier) {
             this.position = position;
             this.flag = flag;
+            this.distanceMultiplier = distanceMultiplier;
         }
     }
 }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c1f97a8..4cdfcb4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -229,7 +229,7 @@
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
                   android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|layoutDirection"
                   android:theme="@style/RecentsTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c16703e8..9e83dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -167,8 +167,7 @@
     public boolean startDragging(boolean animate) {
         mHandle.setTouching(true, animate);
         mDockSide = mWindowManagerProxy.getDockSide();
-        mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
-                mFlingAnimationUtils.getMinVelocityPxPerSecond(), mDisplayWidth,
+        mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
                 mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
@@ -180,9 +179,9 @@
         }
     }
 
-    public void stopDragging(int position, float velocity) {
+    public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
         mHandle.setTouching(false, true /* animate */);
-        fling(position, velocity);
+        fling(position, velocity, avoidDismissStart);
         mWindowManager.setSlippery(true);
         releaseBackground();
     }
@@ -225,7 +224,7 @@
                 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
                     int position = calculatePosition(x, y);
                     SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
-                            0 /* velocity */);
+                            0 /* velocity */, false /* hardDismiss */);
                     resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
                 }
                 break;
@@ -239,7 +238,7 @@
                 mVelocityTracker.computeCurrentVelocity(1000);
                 int position = calculatePosition(x, y);
                 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
-                        : mVelocityTracker.getXVelocity());
+                        : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */);
                 mMoving = false;
                 break;
         }
@@ -250,8 +249,12 @@
         event.setLocation(event.getRawX(), event.getRawY());
     }
 
-    private void fling(int position, float velocity) {
-        final SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
+    private void fling(int position, float velocity, boolean avoidDismissStart) {
+        SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
+        if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
+            snapTarget = mSnapAlgorithm.getFirstSplitTarget();
+        }
+        final SnapTarget finalTarget = snapTarget;
 
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
@@ -260,13 +263,13 @@
                 resizeStack((Integer) animation.getAnimatedValue(),
                         animation.getAnimatedFraction() == 1f
                                 ? TASK_POSITION_SAME
-                                : snapTarget.position, snapTarget);
+                                : finalTarget.position, finalTarget);
             }
         });
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                commitSnapFlags(snapTarget);
+                commitSnapFlags(finalTarget);
                 mWindowManagerProxy.setResizing(false);
                 mDockSide = WindowManager.DOCKED_INVALID;
             }
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 8bf4572..ae6a11f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -223,7 +223,7 @@
             if (mDragMode == DRAG_MODE_DIVIDER) {
                 int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
                 SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
-                        .calculateSnapTarget(position, 0f /* velocity */);
+                        .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */);
                 mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecents(event.getRawY());
@@ -242,7 +242,8 @@
                                 : (int) event.getRawY(),
                         mIsVertical
                                 ? mVelocityTracker.getXVelocity()
-                                : mVelocityTracker.getYVelocity());
+                                : mVelocityTracker.getYVelocity(),
+                        true /* avoidDismissStart */);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
             }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e3f4999..10b4ba7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4243,6 +4243,14 @@
 
     private int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
             Configuration oldTaskOverride) {
+
+        // If we went from full-screen to non-full-screen, make sure to use the correct
+        // configuration task diff, so the diff stays as small as possible.
+        if (Configuration.EMPTY.equals(oldTaskOverride)
+                && !Configuration.EMPTY.equals(taskConfig)) {
+            oldTaskOverride = record.task.extractOverrideConfig(record.configuration);
+        }
+
         // Determine what has changed.  May be nothing, if this is a config
         // that has come back from the app after going idle.  In that case
         // we just want to leave the official config object now in the
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index cc86a62..4ce8b2f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1291,24 +1291,7 @@
             if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
                 mLastNonFullscreenBounds = mBounds;
             }
-
-            final Configuration serviceConfig = mService.mConfiguration;
-            mOverrideConfig = new Configuration(Configuration.EMPTY);
-            // TODO(multidisplay): Update Dp to that of display stack is on.
-            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-            mOverrideConfig.screenWidthDp =
-                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
-            mOverrideConfig.screenHeightDp =
-                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
-            mOverrideConfig.smallestScreenWidthDp =
-                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
-            mOverrideConfig.orientation =
-                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
-                            ? Configuration.ORIENTATION_PORTRAIT
-                            : Configuration.ORIENTATION_LANDSCAPE;
-            final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
-            mOverrideConfig.screenLayout = Configuration.reduceScreenLayout(
-                    sl, mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+            mOverrideConfig = calculateOverrideConfig(mBounds);
         }
 
         if (mFullscreen != oldFullscreen) {
@@ -1318,6 +1301,41 @@
         return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
+    Configuration calculateOverrideConfig(Rect bounds) {
+        final Configuration serviceConfig = mService.mConfiguration;
+        final Configuration config = new Configuration(Configuration.EMPTY);
+        // TODO(multidisplay): Update Dp to that of display stack is on.
+        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        config.screenWidthDp =
+                Math.min((int)(bounds.width() / density), serviceConfig.screenWidthDp);
+        config.screenHeightDp =
+                Math.min((int)(bounds.height() / density), serviceConfig.screenHeightDp);
+        config.smallestScreenWidthDp =
+                Math.min(config.screenWidthDp, config.screenHeightDp);
+        config.orientation = (config.screenWidthDp <= config.screenHeightDp)
+                ? Configuration.ORIENTATION_PORTRAIT
+                : Configuration.ORIENTATION_LANDSCAPE;
+        final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
+        config.screenLayout = Configuration.reduceScreenLayout(
+                sl, config.screenWidthDp, config.screenHeightDp);
+        return config;
+    }
+
+    /**
+     * Using the existing configuration {@param config}, creates a new task override config such
+     * that all the fields that are usually set in an override config are set to the ones in
+     * {@param config}.
+     */
+    Configuration extractOverrideConfig(Configuration config) {
+        final Configuration extracted = new Configuration(Configuration.EMPTY);
+        extracted.screenWidthDp = config.screenWidthDp;
+        extracted.screenHeightDp = config.screenHeightDp;
+        extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
+        extracted.orientation = config.orientation;
+        extracted.screenLayout = config.screenLayout;
+        return extracted;
+    }
+
     Rect updateOverrideConfigurationFromLaunchBounds() {
         final Rect bounds = validateBounds(getLaunchBounds());
         updateOverrideConfiguration(bounds);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a75f2c9..2833b35 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -299,8 +299,7 @@
         final int orientation = mService.mCurConfiguration.orientation;
         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
-                mService.mContext.getResources(),
-                0 /* minFlingVelocityPxPerSecond */, displayWidth, displayHeight,
+                mService.mContext.getResources(), displayWidth, displayHeight,
                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
 
@@ -552,7 +551,6 @@
             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
                     mTmpRect2);
             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
-                    0 /* minFlingVelocityPxPerSecond */,
                     di.logicalWidth,
                     di.logicalHeight,
                     dockDividerWidth,