Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,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; Loading Loading @@ -173,6 +174,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. Loading Loading @@ -736,6 +743,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); Loading Loading @@ -806,6 +814,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi try { mAddedToWindowManager = false; if (mStackView != null) { mPositionFromRemovedStack = mStackView.getRelativeStackPosition(); mWindowManager.removeView(mStackView); mStackView.removeView(mBubbleScrim); mStackView = null; Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +60 −19 Original line number Diff line number Diff line Loading @@ -253,13 +253,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; Loading Loading @@ -940,9 +935,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); }; Loading Loading @@ -1189,13 +1185,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(); Loading Loading @@ -1459,7 +1449,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) { Loading Loading @@ -1674,7 +1664,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() Loading Loading @@ -2740,10 +2730,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. * Loading Loading @@ -2797,4 +2795,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()); } } } packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +47 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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:"); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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() { Loading Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,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; Loading Loading @@ -173,6 +174,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. Loading Loading @@ -736,6 +743,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); Loading Loading @@ -806,6 +814,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi try { mAddedToWindowManager = false; if (mStackView != null) { mPositionFromRemovedStack = mStackView.getRelativeStackPosition(); mWindowManager.removeView(mStackView); mStackView.removeView(mBubbleScrim); mStackView = null; Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +60 −19 Original line number Diff line number Diff line Loading @@ -253,13 +253,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; Loading Loading @@ -940,9 +935,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); }; Loading Loading @@ -1189,13 +1185,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(); Loading Loading @@ -1459,7 +1449,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) { Loading Loading @@ -1674,7 +1664,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() Loading Loading @@ -2740,10 +2730,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. * Loading Loading @@ -2797,4 +2795,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()); } } }
packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +47 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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:"); Loading Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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() { Loading