From a95ca8de4d8b971d41abe44cd54e82560d1e0b37 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 15 Jan 2016 22:54:46 -0800 Subject: [PATCH 1/2] Fix unneccesary activity relaunches When going from fullscreen to non-fullscreen configuration, task config changes was always non-zero because in fullscreen, task override config was empty. Instead, use the actual previous configuration to calculate diff. Also make recents handle screenLayout changes. Bug: 26593320 Change-Id: I57633d60b1e0fc4ae506e276410191a44e1fe221 --- packages/SystemUI/AndroidManifest.xml | 2 +- .../com/android/server/am/ActivityStack.java | 8 +++ .../com/android/server/am/TaskRecord.java | 54 ++++++++++++------- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 6ec757d1610e7..8edfe9000addb 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -226,7 +226,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"> diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index e3f4999adf0d9..10b4ba74e6989 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 @@ final class ActivityStack { 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 cc86a62a902d5..4ce8b2f67eee0 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 @@ final class TaskRecord { 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 @@ final class TaskRecord { 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); From df012d5102735412d9f38513c103aa53df4bcab9 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Fri, 15 Jan 2016 22:40:13 -0800 Subject: [PATCH 2/2] Divider tuning - Make it harder to dismiss - When dragging from the bottom, don't allow dismissing at the top Change-Id: Ifd2de38abece7b996a813af41dcf777fa5cd1c18 --- .../internal/policy/DividerSnapAlgorithm.java | 61 ++++++++++++++----- .../systemui/stackdivider/DividerView.java | 23 ++++--- .../phone/NavigationBarGestureHelper.java | 5 +- .../java/com/android/server/wm/TaskStack.java | 4 +- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java index 59a1e4a782994..5b40bc0ed3a90 100644 --- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java @@ -19,6 +19,7 @@ package com.android.internal.policy; 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 @@ import java.util.ArrayList; */ 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 @@ public class DividerSnapAlgorithm { 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 @@ public class DividerSnapAlgorithm { 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 class DividerSnapAlgorithm { } 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 class DividerSnapAlgorithm { } 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 @@ public class DividerSnapAlgorithm { 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 @@ public class DividerSnapAlgorithm { 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 @@ public class DividerSnapAlgorithm { 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 class DividerSnapAlgorithm { 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/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index c16703e86a10e..9e83dcf64a805 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 class DividerView extends FrameLayout implements OnTouchListener, 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 class DividerView extends FrameLayout implements OnTouchListener, } } - 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 @@ public class DividerView extends FrameLayout implements OnTouchListener, 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 2db08041be8e8..4ff11a808eab8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -218,7 +218,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL 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()); @@ -237,7 +237,8 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL : (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/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index a75f2c96a0c9a..2833b35c5c9c2 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 @@ public class TaskStack implements DimLayer.DimLayerUser { 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 @@ public class TaskStack implements DimLayer.DimLayerUser { 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,