Merge "Remember the stack position, including across configuration changes." into rvc-qpr-dev am: 9020ed08e1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12254380

Change-Id: I904330889de1da23b2d44c0a948b51e6d454fd76
This commit is contained in:
Josh Tsuji
2020-08-04 15:37:37 +00:00
committed by Automerger Merge Worker
3 changed files with 116 additions and 45 deletions

View File

@@ -82,6 +82,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -168,6 +169,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
/**
* The relative position of the stack when we removed it and nulled it out. If the stack is
* re-created, it will re-appear at this position.
*/
@Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
// Saves notification keys of active bubbles when users are switched.
@@ -718,6 +725,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
this::hideCurrentInputMethod);
mStackView.setStackStartPosition(mPositionFromRemovedStack);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -787,6 +795,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
try {
mAddedToWindowManager = false;
if (mStackView != null) {
mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
mWindowManager.removeView(mStackView);
mStackView.removeView(mBubbleScrim);
mStackView = null;

View File

@@ -258,13 +258,8 @@ public class BubbleStackView extends FrameLayout
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
private OnLayoutChangeListener mOrientationChangedListener;
/** Whether the stack was on the left side of the screen prior to rotation. */
private boolean mWasOnLeftBeforeRotation = false;
/**
* How far down the screen the stack was before rotation, in terms of percentage of the way down
* the allowable region. Defaults to -1 if not set.
*/
private float mVerticalPosPercentBeforeRotation = -1;
@Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;
private int mMaxBubbles;
private int mBubbleSize;
@@ -967,9 +962,10 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setTranslationY(getExpandedViewY());
mExpandedViewContainer.setAlpha(1f);
}
if (mVerticalPosPercentBeforeRotation >= 0) {
mStackAnimationController.moveStackToSimilarPositionAfterRotation(
mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
if (mRelativeStackPositionBeforeRotation != null) {
mStackAnimationController.setStackPosition(
mRelativeStackPositionBeforeRotation);
mRelativeStackPositionBeforeRotation = null;
}
removeOnLayoutChangeListener(mOrientationChangedListener);
};
@@ -1231,13 +1227,7 @@ public class BubbleStackView extends FrameLayout
com.android.internal.R.dimen.status_bar_height);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
mVerticalPosPercentBeforeRotation =
(mStackAnimationController.getStackPosition().y - allowablePos.top)
/ (allowablePos.bottom - allowablePos.top);
mVerticalPosPercentBeforeRotation =
Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation));
mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
addOnLayoutChangeListener(mOrientationChangedListener);
hideFlyoutImmediate();
@@ -1506,7 +1496,7 @@ public class BubbleStackView extends FrameLayout
if (getBubbleCount() == 0 && mShouldShowUserEducation) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
mStackAnimationController.getDefaultStartPosition());
mStackAnimationController.getStartPosition());
}
if (getBubbleCount() == 0) {
@@ -1721,7 +1711,7 @@ public class BubbleStackView extends FrameLayout
// Post so we have height of mUserEducationView
mUserEducationView.post(() -> {
final int viewHeight = mUserEducationView.getHeight();
PointF stackPosition = mStackAnimationController.getDefaultStartPosition();
PointF stackPosition = mStackAnimationController.getStartPosition();
final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
mUserEducationView.setTranslationY(translationY);
mUserEducationView.animate()
@@ -2877,10 +2867,18 @@ public class BubbleStackView extends FrameLayout
.floatValue();
}
public void setStackStartPosition(RelativeStackPosition position) {
mStackAnimationController.setStackStartPosition(position);
}
public PointF getStackPosition() {
return mStackAnimationController.getStackPosition();
}
public RelativeStackPosition getRelativeStackPosition() {
return mStackAnimationController.getRelativeStackPosition();
}
/**
* Logs the bubble UI event.
*
@@ -2944,4 +2942,47 @@ public class BubbleStackView extends FrameLayout
}
return bubbles;
}
/**
* Representation of stack position that uses relative properties rather than absolute
* coordinates. This is used to maintain similar stack positions across configuration changes.
*/
public static class RelativeStackPosition {
/** Whether to place the stack at the leftmost allowed position. */
private boolean mOnLeft;
/**
* How far down the vertically allowed region to place the stack. For example, if the stack
* allowed region is between y = 100 and y = 1100 and this is 0.2f, we'll place the stack at
* 100 + (0.2f * 1000) = 300.
*/
private float mVerticalOffsetPercent;
public RelativeStackPosition(boolean onLeft, float verticalOffsetPercent) {
mOnLeft = onLeft;
mVerticalOffsetPercent = clampVerticalOffsetPercent(verticalOffsetPercent);
}
/** Constructs a relative position given a region and a point in that region. */
public RelativeStackPosition(PointF position, RectF region) {
mOnLeft = position.x < region.width() / 2;
mVerticalOffsetPercent =
clampVerticalOffsetPercent((position.y - region.top) / region.height());
}
/** Ensures that the offset percent is between 0f and 1f. */
private float clampVerticalOffsetPercent(float offsetPercent) {
return Math.max(0f, Math.min(1f, offsetPercent));
}
/**
* Given an allowable stack position region, returns the point within that region
* represented by this relative position.
*/
public PointF getAbsolutePositionInRegion(RectF region) {
return new PointF(
mOnLeft ? region.left : region.right,
region.top + mVerticalOffsetPercent * region.height());
}
}
}

View File

@@ -35,6 +35,7 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleStackView;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
import com.android.systemui.util.magnetictarget.MagnetizedObject;
@@ -125,6 +126,9 @@ public class StackAnimationController extends
*/
private Rect mAnimatingToBounds = new Rect();
/** Initial starting location for the stack. */
@Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
@@ -431,21 +435,6 @@ public class StackAnimationController extends
return stackPos;
}
/**
* Moves the stack in response to rotation. We keep it in the most similar position by keeping
* it on the same side, and positioning it the same percentage of the way down the screen
* (taking status bar/nav bar into account by using the allowable region's height).
*/
public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) {
final RectF allowablePos = getAllowableStackPositionRegion();
final float allowableRegionHeight = allowablePos.bottom - allowablePos.top;
final float x = wasOnLeft ? allowablePos.left : allowablePos.right;
final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top;
setStackPosition(new PointF(x, y));
}
/** Description of current animation controller state. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StackAnimationController state:");
@@ -815,7 +804,7 @@ public class StackAnimationController extends
} else {
// When all children are removed ensure stack position is sane
setStackPosition(mRestingStackPosition == null
? getDefaultStartPosition()
? getStartPosition()
: mRestingStackPosition);
// Remove the stack from the coordinator since we don't have any bubbles and aren't
@@ -868,7 +857,7 @@ public class StackAnimationController extends
mLayout.setVisibility(View.INVISIBLE);
mLayout.post(() -> {
setStackPosition(mRestingStackPosition == null
? getDefaultStartPosition()
? getStartPosition()
: mRestingStackPosition);
mStackMovedToStartPosition = true;
mLayout.setVisibility(View.VISIBLE);
@@ -938,15 +927,47 @@ public class StackAnimationController extends
}
}
/** Returns the default stack position, which is on the top left. */
public PointF getDefaultStartPosition() {
boolean isRtl = mLayout != null
&& mLayout.getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
return new PointF(isRtl
? getAllowableStackPositionRegion().right
: getAllowableStackPositionRegion().left,
getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
public void setStackPosition(BubbleStackView.RelativeStackPosition position) {
setStackPosition(position.getAbsolutePositionInRegion(getAllowableStackPositionRegion()));
}
public BubbleStackView.RelativeStackPosition getRelativeStackPosition() {
return new BubbleStackView.RelativeStackPosition(
mStackPosition, getAllowableStackPositionRegion());
}
/**
* Sets the starting position for the stack, where it will be located when the first bubble is
* added.
*/
public void setStackStartPosition(BubbleStackView.RelativeStackPosition position) {
mStackStartPosition = position;
}
/**
* Returns the starting stack position. If {@link #setStackStartPosition} was called, this will
* return that position - otherwise, a reasonable default will be returned.
*/
@Nullable public PointF getStartPosition() {
if (mLayout == null) {
return null;
}
if (mStackStartPosition == null) {
// Start on the left if we're in LTR, right otherwise.
final boolean startOnLeft =
mLayout.getResources().getConfiguration().getLayoutDirection()
!= View.LAYOUT_DIRECTION_RTL;
final float startingVerticalOffset = mLayout.getResources().getDimensionPixelOffset(
R.dimen.bubble_stack_starting_offset_y);
mStackStartPosition = new BubbleStackView.RelativeStackPosition(
startOnLeft,
startingVerticalOffset / getAllowableStackPositionRegion().height());
}
return mStackStartPosition.getAbsolutePositionInRegion(getAllowableStackPositionRegion());
}
private boolean isStackPositionSet() {