diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl index 36a81db2880ac..4cf7cf3ef1f03 100644 --- a/core/java/android/view/IDockedStackListener.aidl +++ b/core/java/android/view/IDockedStackListener.aidl @@ -40,8 +40,11 @@ oneway interface IDockedStackListener { * * @param minimized Whether the docked stack is currently minimized. * @param animDuration The duration of the animation for changing the minimized state. + * @param isHomeStackResizable If the home stack is resizable, a portion of the docked stack + * will be shown with the divider */ - void onDockedStackMinimizedChanged(boolean minimized, long animDuration); + void onDockedStackMinimizedChanged(boolean minimized, long animDuration, + boolean isHomeStackResizable); /** * Called when window manager decides to adjust the divider for IME. Like the minimized state, diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java index cf14471f381a5..11e71026bf093 100644 --- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java +++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java @@ -53,6 +53,11 @@ public class DividerSnapAlgorithm { */ private static final int SNAP_ONLY_1_1 = 2; + /** + * 1 snap target: minimized height, (1 - minimized height) + */ + private static final int SNAP_MODE_MINIMIZED = 3; + private final float mMinFlingVelocityPxPerSecond; private final float mMinDismissVelocityPxPerSecond; private final int mDisplayWidth; @@ -62,6 +67,7 @@ public class DividerSnapAlgorithm { private final Rect mInsets = new Rect(); private final int mSnapMode; private final int mMinimalSizeResizableTask; + private final int mTaskHeightInMinimizedMode; private final float mFixedRatio; private boolean mIsHorizontalDivision; @@ -93,6 +99,11 @@ public class DividerSnapAlgorithm { public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision, Rect insets) { + this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false); + } + + public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize, + boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) { mMinFlingVelocityPxPerSecond = MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density; mMinDismissVelocityPxPerSecond = @@ -102,12 +113,14 @@ public class DividerSnapAlgorithm { mDisplayHeight = displayHeight; mIsHorizontalDivision = isHorizontalDivision; mInsets.set(insets); - mSnapMode = res.getInteger( - com.android.internal.R.integer.config_dockedStackDividerSnapMode); + mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED : + res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode); mFixedRatio = res.getFraction( com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1); mMinimalSizeResizableTask = res.getDimensionPixelSize( com.android.internal.R.dimen.default_minimal_size_resizable_task); + mTaskHeightInMinimizedMode = res.getDimensionPixelSize( + com.android.internal.R.dimen.task_height_of_minimized_mode); calculateTargets(isHorizontalDivision); mFirstSplitTarget = mTargets.get(1); mLastSplitTarget = mTargets.get(mTargets.size() - 2); @@ -246,6 +259,7 @@ public class DividerSnapAlgorithm { int dividerMax = isHorizontalDivision ? mDisplayHeight : mDisplayWidth; + int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right; mTargets.add(new SnapTarget(-mDividerSize, -mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f)); switch (mSnapMode) { @@ -258,8 +272,10 @@ public class DividerSnapAlgorithm { case SNAP_ONLY_1_1: addMiddleTarget(isHorizontalDivision); break; + case SNAP_MODE_MINIMIZED: + addMinimizedTarget(isHorizontalDivision); + break; } - int navBarSize = isHorizontalDivision ? mInsets.bottom : mInsets.right; mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f)); } @@ -315,6 +331,12 @@ public class DividerSnapAlgorithm { mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE)); } + private void addMinimizedTarget(boolean isHorizontalDivision) { + int position = mTaskHeightInMinimizedMode; + position += isHorizontalDivision ? mInsets.top : mInsets.left; + mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE)); + } + public SnapTarget getMiddleTarget() { return mMiddleTarget; } diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index e6358a37bdedb..4266f887abe31 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -488,6 +488,9 @@ 220dp + + 80dp + 720dp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 78f6b4901a768..169930eb1f6ac 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1772,6 +1772,7 @@ + diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 3cd2a7a1011a0..b9a0f74058695 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -44,6 +44,7 @@ public class Divider extends SystemUI { private boolean mVisible = false; private boolean mMinimized = false; private boolean mAdjustedForIme = false; + private boolean mHomeStackResizable = false; private ForcedResizableInfoActivityController mForcedResizableController; @Override @@ -75,6 +76,7 @@ public class Divider extends SystemUI { mView = (DividerView) LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null); mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE); + mView.setMinimizedDockStack(mMinimized, mHomeStackResizable); final int size = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.docked_stack_divider_thickness); final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE; @@ -92,7 +94,7 @@ public class Divider extends SystemUI { removeDivider(); addDivider(configuration); if (mMinimized) { - mView.setMinimizedDockStack(true); + mView.setMinimizedDockStack(true, mHomeStackResizable); updateTouchable(); } } @@ -106,13 +108,14 @@ public class Divider extends SystemUI { mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); // Update state because animations won't finish. - mView.setMinimizedDockStack(mMinimized); + mView.setMinimizedDockStack(mMinimized, mHomeStackResizable); } } }); } - private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) { + private void updateMinimizedDockedStack(final boolean minimized, final long animDuration, + final boolean isHomeStackResizable) { mView.post(new Runnable() { @Override public void run() { @@ -120,9 +123,9 @@ public class Divider extends SystemUI { mMinimized = minimized; updateTouchable(); if (animDuration > 0) { - mView.setMinimizedDockStack(minimized, animDuration); + mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable); } else { - mView.setMinimizedDockStack(minimized); + mView.setMinimizedDockStack(minimized, isHomeStackResizable); } } } @@ -139,7 +142,7 @@ public class Divider extends SystemUI { } private void updateTouchable() { - mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme); + mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme); } @Override @@ -162,9 +165,10 @@ public class Divider extends SystemUI { } @Override - public void onDockedStackMinimizedChanged(boolean minimized, long animDuration) - throws RemoteException { - updateMinimizedDockedStack(minimized, animDuration); + public void onDockedStackMinimizedChanged(boolean minimized, long animDuration, + boolean isHomeStackResizable) throws RemoteException { + mHomeStackResizable = isHomeStackResizable; + updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 47d2def0cf63f..49035ba5bde54 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -64,6 +64,7 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DockedTopTaskEvent; import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent; +import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.activity.UndockingTaskEvent; import com.android.systemui.recents.events.ui.RecentsDrawnEvent; import com.android.systemui.recents.events.ui.RecentsGrowingEvent; @@ -123,6 +124,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mMoving; private int mTouchSlop; private boolean mBackgroundLifted; + private boolean mIsInMinimizeInteraction; + private int mDividerPositionBeforeMinimized; private int mDividerInsets; private int mDisplayWidth; @@ -145,6 +148,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private VelocityTracker mVelocityTracker; private FlingAnimationUtils mFlingAnimationUtils; private DividerSnapAlgorithm mSnapAlgorithm; + private DividerSnapAlgorithm mMinimizedSnapAlgorithm; private final Rect mStableInsets = new Rect(); private boolean mGrowRecents; @@ -154,6 +158,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private int mExitStartPosition; private GestureDetector mGestureDetector; private boolean mDockedStackMinimized; + private boolean mHomeStackResizable; private boolean mAdjustedForIme; private DividerState mState; @@ -350,8 +355,9 @@ public class DividerView extends FrameLayout implements OnTouchListener, || mStableInsets.bottom != insets.getStableInsetBottom()) { mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(), insets.getStableInsetRight(), insets.getStableInsetBottom()); - if (mSnapAlgorithm != null) { + if (mSnapAlgorithm != null || mMinimizedSnapAlgorithm != null) { mSnapAlgorithm = null; + mMinimizedSnapAlgorithm = null; initializeSnapAlgorithm(); } } @@ -446,11 +452,17 @@ public class DividerView extends FrameLayout implements OnTouchListener, mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets); } + if (mMinimizedSnapAlgorithm == null) { + mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), + mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(), + mStableInsets, mDockedStackMinimized && mHomeStackResizable); + } } public DividerSnapAlgorithm getSnapAlgorithm() { initializeSnapAlgorithm(); - return mSnapAlgorithm; + return mDockedStackMinimized && mHomeStackResizable ? mMinimizedSnapAlgorithm : + mSnapAlgorithm; } public int getCurrentPosition() { @@ -495,7 +507,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mMoving = true; } if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) { - SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget( + SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget( mStartPosition, 0 /* velocity */, false /* hardDismiss */); resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget); } @@ -551,9 +563,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, private void fling(int position, float velocity, boolean avoidDismissStart, boolean logMetrics) { - SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity); - if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) { - snapTarget = mSnapAlgorithm.getFirstSplitTarget(); + DividerSnapAlgorithm currentSnapAlgorithm = getSnapAlgorithm(); + SnapTarget snapTarget = currentSnapAlgorithm.calculateSnapTarget(position, velocity); + if (avoidDismissStart && snapTarget == currentSnapAlgorithm.getDismissStartTarget()) { + snapTarget = currentSnapAlgorithm.getFirstSplitTarget(); } if (logMetrics) { logResizeEvent(snapTarget); @@ -574,6 +587,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget, final long endDelay) { + if (mCurrentAnimator != null) { + cancelFlingAnimation(); + updateDockSide(); + } final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE; ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(), @@ -590,6 +607,12 @@ public class DividerView extends FrameLayout implements OnTouchListener, mExitAnimationRunning = false; EventBus.getDefault().send(new StoppedDragingEvent()); }; + Runnable notCancelledEndAction = () -> { + // Reset minimized divider position after unminimized state animation finishes + if (!mDockedStackMinimized && mIsInMinimizeInteraction) { + mIsInMinimizeInteraction = false; + } + }; anim.addListener(new AnimatorListenerAdapter() { private boolean mCancelled; @@ -612,8 +635,14 @@ public class DividerView extends FrameLayout implements OnTouchListener, } if (delay == 0) { endAction.run(); + if (!mCancelled) { + notCancelledEndAction.run(); + } } else { mHandler.postDelayed(endAction, delay); + if (!mCancelled) { + mHandler.postDelayed(notCancelledEndAction, delay); + } } } }); @@ -692,57 +721,92 @@ public class DividerView extends FrameLayout implements OnTouchListener, } - public void setMinimizedDockStack(boolean minimized) { + public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) { + mHomeStackResizable = isHomeStackResizable; updateDockSide(); - mHandle.setAlpha(minimized ? 0f : 1f); if (!minimized) { resetBackground(); - } else if (mDockSide == WindowManager.DOCKED_TOP) { - mBackground.setPivotY(0); - mBackground.setScaleY(MINIMIZE_DOCK_SCALE); - } else if (mDockSide == WindowManager.DOCKED_LEFT - || mDockSide == WindowManager.DOCKED_RIGHT) { - mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT - ? 0 - : mBackground.getWidth()); - mBackground.setScaleX(MINIMIZE_DOCK_SCALE); + } else if (!isHomeStackResizable) { + if (mDockSide == WindowManager.DOCKED_TOP) { + mBackground.setPivotY(0); + mBackground.setScaleY(MINIMIZE_DOCK_SCALE); + } else if (mDockSide == WindowManager.DOCKED_LEFT + || mDockSide == WindowManager.DOCKED_RIGHT) { + mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT + ? 0 + : mBackground.getWidth()); + mBackground.setScaleX(MINIMIZE_DOCK_SCALE); + } } mMinimizedShadow.setAlpha(minimized ? 1f : 0f); - mDockedStackMinimized = minimized; + if (!isHomeStackResizable) { + mHandle.setAlpha(minimized ? 0f : 1f); + mDockedStackMinimized = minimized; + } else if (mDockedStackMinimized != minimized) { + if (mStableInsets.isEmpty()) { + SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); + } + if (!mIsInMinimizeInteraction && minimized) { + mIsInMinimizeInteraction = true; + mDividerPositionBeforeMinimized = DockedDividerUtils.calculateMiddlePosition( + isHorizontalDivision(), mStableInsets, mDisplayWidth, mDisplayHeight, + mDividerSize); + } + mMinimizedSnapAlgorithm = null; + mDockedStackMinimized = minimized; + initializeSnapAlgorithm(); + } } - public void setMinimizedDockStack(boolean minimized, long animDuration) { + public void setMinimizedDockStack(boolean minimized, long animDuration, + boolean isHomeStackResizable) { + mHomeStackResizable = isHomeStackResizable; updateDockSide(); - mHandle.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(animDuration) - .alpha(minimized ? 0f : 1f) - .start(); - if (mDockSide == WindowManager.DOCKED_TOP) { - mBackground.setPivotY(0); - mBackground.animate() - .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f); - } else if (mDockSide == WindowManager.DOCKED_LEFT - || mDockSide == WindowManager.DOCKED_RIGHT) { - mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT - ? 0 - : mBackground.getWidth()); - mBackground.animate() - .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f); + if (!isHomeStackResizable) { + mMinimizedShadow.animate() + .alpha(minimized ? 1f : 0f) + .setInterpolator(Interpolators.ALPHA_IN) + .setDuration(animDuration) + .start(); + mHandle.animate() + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setDuration(animDuration) + .alpha(minimized ? 0f : 1f) + .start(); + if (mDockSide == WindowManager.DOCKED_TOP) { + mBackground.setPivotY(0); + mBackground.animate() + .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f); + } else if (mDockSide == WindowManager.DOCKED_LEFT + || mDockSide == WindowManager.DOCKED_RIGHT) { + mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT + ? 0 + : mBackground.getWidth()); + mBackground.animate() + .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f); + } + mDockedStackMinimized = minimized; + } else if (mDockedStackMinimized != minimized) { + mIsInMinimizeInteraction = true; + if (minimized) { + mDividerPositionBeforeMinimized = getCurrentPosition(); + } + mMinimizedSnapAlgorithm = null; + mDockedStackMinimized = minimized; + initializeSnapAlgorithm(); + stopDragging(getCurrentPosition(), minimized ? + mMinimizedSnapAlgorithm.getMiddleTarget() : + mSnapAlgorithm.calculateNonDismissingSnapTarget( + mDividerPositionBeforeMinimized), + animDuration, Interpolators.FAST_OUT_SLOW_IN, 0); } if (!minimized) { mBackground.animate().withEndAction(mResetBackgroundRunnable); } - mMinimizedShadow.animate() - .alpha(minimized ? 1f : 0f) - .setInterpolator(Interpolators.ALPHA_IN) - .setDuration(animDuration) - .start(); mBackground.animate() .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setDuration(animDuration) .start(); - mDockedStackMinimized = minimized; } public void setAdjustedForIme(boolean adjustedForIme) { @@ -809,6 +873,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDisplayWidth = info.logicalWidth; mDisplayHeight = info.logicalHeight; mSnapAlgorithm = null; + mMinimizedSnapAlgorithm = null; initializeSnapAlgorithm(); } @@ -871,6 +936,15 @@ public class DividerView extends FrameLayout implements OnTouchListener, } mLastResizeRect.set(mDockedRect); + if (mHomeStackResizable && mIsInMinimizeInteraction) { + calculateBoundsForPosition(mDividerPositionBeforeMinimized, mDockSide, mDockedTaskRect); + calculateBoundsForPosition(mDividerPositionBeforeMinimized, + DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect); + mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect, + mOtherTaskRect, null); + return; + } + if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) { if (mCurrentAnimator != null) { calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect); @@ -922,7 +996,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, } else { mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null); } - SnapTarget closestDismissTarget = mSnapAlgorithm.getClosestDismissTarget(position); + SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position); float dimFraction = getDimFraction(position, closestDismissTarget); mWindowManagerProxy.setResizeDimLayer(dimFraction != 0f, getStackIdForDismissTarget(closestDismissTarget), @@ -943,7 +1017,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mEntranceAnimationRunning) { return 0f; } - float fraction = mSnapAlgorithm.calculateDismissingFraction(position); + float fraction = getSnapAlgorithm().calculateDismissingFraction(position); fraction = Math.max(0, Math.min(fraction, 1f)); fraction = DIM_INTERPOLATOR.getInterpolation(fraction); if (hasInsetsAtDismissTarget(dismissTarget)) { @@ -959,13 +1033,13 @@ public class DividerView extends FrameLayout implements OnTouchListener, */ private boolean hasInsetsAtDismissTarget(SnapTarget dismissTarget) { if (isHorizontalDivision()) { - if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) { + if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) { return mStableInsets.top != 0; } else { return mStableInsets.bottom != 0; } } else { - if (dismissTarget == mSnapAlgorithm.getDismissStartTarget()) { + if (dismissTarget == getSnapAlgorithm().getDismissStartTarget()) { return mStableInsets.left != 0; } else { return mStableInsets.right != 0; @@ -1135,6 +1209,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mStableInsets.isEmpty()) { SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets); mSnapAlgorithm = null; + mMinimizedSnapAlgorithm = null; initializeSnapAlgorithm(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 319f124f05544..2f4f30e3dabfe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -553,8 +553,8 @@ public class NavigationBarView extends FrameLayout implements PluginListener