Merge "Fix dot for smart reply and bubble groups [DO NOT MERGE]" into qt-qpr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9b61e99398
@@ -169,7 +169,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
* Callback to run after the flyout hides. Also called if a new flyout is shown before the
|
* Callback to run after the flyout hides. Also called if a new flyout is shown before the
|
||||||
* previous one animates out.
|
* previous one animates out.
|
||||||
*/
|
*/
|
||||||
private Runnable mAfterFlyoutHides;
|
private Runnable mFlyoutOnHide;
|
||||||
|
|
||||||
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
|
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
|
||||||
private OnLayoutChangeListener mOrientationChangedListener;
|
private OnLayoutChangeListener mOrientationChangedListener;
|
||||||
@@ -1401,111 +1401,106 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void animateInFlyoutForBubble(Bubble bubble) {
|
void animateInFlyoutForBubble(Bubble bubble) {
|
||||||
final CharSequence updateMessage = bubble.getUpdateMessage(getContext());
|
final CharSequence updateMessage = bubble.getUpdateMessage(getContext());
|
||||||
|
|
||||||
if (!bubble.showFlyoutForBubble()) {
|
if (!bubble.showFlyoutForBubble()) {
|
||||||
// In case flyout was suppressed for this update, reset now.
|
// In case flyout was suppressed for this update, reset now.
|
||||||
bubble.setSuppressFlyout(false);
|
bubble.setSuppressFlyout(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateMessage == null
|
if (updateMessage == null
|
||||||
|| isExpanded()
|
|| isExpanded()
|
||||||
|| mIsExpansionAnimating
|
|| mIsExpansionAnimating
|
||||||
|| mIsGestureInProgress
|
|| mIsGestureInProgress
|
||||||
|| mBubbleToExpandAfterFlyoutCollapse != null) {
|
|| mBubbleToExpandAfterFlyoutCollapse != null
|
||||||
|
|| bubble.getIconView() == null) {
|
||||||
// Skip the message if none exists, we're expanded or animating expansion, or we're
|
// Skip the message if none exists, we're expanded or animating expansion, or we're
|
||||||
// about to expand a bubble from the previous tapped flyout.
|
// about to expand a bubble from the previous tapped flyout, or if bubble view is null.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mFlyoutDragDeltaX = 0f;
|
||||||
if (bubble.getIconView() != null) {
|
clearFlyoutOnHide();
|
||||||
// Temporarily suppress the dot while the flyout is visible.
|
mFlyoutOnHide = () -> {
|
||||||
bubble.getIconView().setSuppressDot(
|
resetDot(bubble);
|
||||||
true /* suppressDot */, false /* animate */);
|
if (mBubbleToExpandAfterFlyoutCollapse == null) {
|
||||||
|
return;
|
||||||
mFlyout.removeCallbacks(mAnimateInFlyout);
|
|
||||||
mFlyoutDragDeltaX = 0f;
|
|
||||||
|
|
||||||
if (mAfterFlyoutHides != null) {
|
|
||||||
mAfterFlyoutHides.run();
|
|
||||||
}
|
}
|
||||||
|
mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse);
|
||||||
|
mBubbleData.setExpanded(true);
|
||||||
|
mBubbleToExpandAfterFlyoutCollapse = null;
|
||||||
|
};
|
||||||
|
mFlyout.setVisibility(INVISIBLE);
|
||||||
|
|
||||||
mAfterFlyoutHides = () -> {
|
// Temporarily suppress the dot while the flyout is visible.
|
||||||
final boolean suppressDot = !bubble.showBubbleDot();
|
bubble.getIconView().setSuppressDot(
|
||||||
// If we're going to suppress the dot, make it visible first so it'll
|
true /* suppressDot */, false /* animate */);
|
||||||
// visibly animate away.
|
|
||||||
if (suppressDot) {
|
|
||||||
bubble.getIconView().setSuppressDot(
|
|
||||||
false /* suppressDot */, false /* animate */);
|
|
||||||
}
|
|
||||||
// Reset dot suppression. If we're not suppressing due to DND, then
|
|
||||||
// stop suppressing it with no animation (since the flyout has
|
|
||||||
// transformed into the dot). If we are suppressing due to DND, animate
|
|
||||||
// it away.
|
|
||||||
bubble.getIconView().setSuppressDot(
|
|
||||||
suppressDot /* suppressDot */,
|
|
||||||
suppressDot /* animate */);
|
|
||||||
|
|
||||||
if (mBubbleToExpandAfterFlyoutCollapse != null) {
|
// Start flyout expansion. Post in case layout isn't complete and getWidth returns 0.
|
||||||
mBubbleData.setSelectedBubble(mBubbleToExpandAfterFlyoutCollapse);
|
post(() -> {
|
||||||
mBubbleData.setExpanded(true);
|
// An auto-expanding bubble could have been posted during the time it takes to
|
||||||
mBubbleToExpandAfterFlyoutCollapse = null;
|
// layout.
|
||||||
}
|
if (isExpanded()) {
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
mFlyout.setVisibility(INVISIBLE);
|
final Runnable expandFlyoutAfterDelay = () -> {
|
||||||
|
mAnimateInFlyout = () -> {
|
||||||
// Post in case layout isn't complete and getWidth returns 0.
|
mFlyout.setVisibility(VISIBLE);
|
||||||
post(() -> {
|
mFlyoutDragDeltaX =
|
||||||
// An auto-expanding bubble could have been posted during the time it takes to
|
mStackAnimationController.isStackOnLeftSide()
|
||||||
// layout.
|
? -mFlyout.getWidth()
|
||||||
if (isExpanded()) {
|
: mFlyout.getWidth();
|
||||||
return;
|
animateFlyoutCollapsed(false /* collapsed */, 0 /* velX */);
|
||||||
}
|
mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
|
||||||
|
|
||||||
final Runnable afterShow = () -> {
|
|
||||||
mAnimateInFlyout = () -> {
|
|
||||||
mFlyout.setVisibility(VISIBLE);
|
|
||||||
bubble.getIconView().setSuppressDot(
|
|
||||||
true /* suppressDot */, false /* animate */);
|
|
||||||
mFlyoutDragDeltaX =
|
|
||||||
mStackAnimationController.isStackOnLeftSide()
|
|
||||||
? -mFlyout.getWidth()
|
|
||||||
: mFlyout.getWidth();
|
|
||||||
animateFlyoutCollapsed(false /* collapsed */, 0 /* velX */);
|
|
||||||
mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
|
|
||||||
};
|
|
||||||
|
|
||||||
mFlyout.postDelayed(mAnimateInFlyout, 200);
|
|
||||||
};
|
};
|
||||||
|
mFlyout.postDelayed(mAnimateInFlyout, 200);
|
||||||
mFlyout.setupFlyoutStartingAsDot(
|
};
|
||||||
updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
|
mFlyout.setupFlyoutStartingAsDot(
|
||||||
mStackAnimationController.isStackOnLeftSide(),
|
updateMessage, mStackAnimationController.getStackPosition(), getWidth(),
|
||||||
bubble.getIconView().getBadgeColor(),
|
mStackAnimationController.isStackOnLeftSide(),
|
||||||
afterShow,
|
bubble.getIconView().getBadgeColor() /* dotColor */,
|
||||||
mAfterFlyoutHides,
|
expandFlyoutAfterDelay /* onLayoutComplete */,
|
||||||
bubble.getIconView().getDotCenter());
|
mFlyoutOnHide,
|
||||||
mFlyout.bringToFront();
|
bubble.getIconView().getDotCenter());
|
||||||
});
|
mFlyout.bringToFront();
|
||||||
}
|
});
|
||||||
|
|
||||||
mFlyout.removeCallbacks(mHideFlyout);
|
mFlyout.removeCallbacks(mHideFlyout);
|
||||||
mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
|
mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
|
||||||
logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT);
|
logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__FLYOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetDot(Bubble bubble) {
|
||||||
|
final boolean suppressDot = !bubble.showBubbleDot();
|
||||||
|
// If we're going to suppress the dot, make it visible first so it'll
|
||||||
|
// visibly animate away.
|
||||||
|
|
||||||
|
if (suppressDot) {
|
||||||
|
bubble.getIconView().setSuppressDot(
|
||||||
|
false /* suppressDot */, false /* animate */);
|
||||||
|
}
|
||||||
|
// Reset dot suppression. If we're not suppressing due to DND, then
|
||||||
|
// stop suppressing it with no animation (since the flyout has
|
||||||
|
// transformed into the dot). If we are suppressing due to DND, animate
|
||||||
|
// it away.
|
||||||
|
bubble.getIconView().setSuppressDot(
|
||||||
|
suppressDot /* suppressDot */,
|
||||||
|
suppressDot /* animate */);
|
||||||
|
}
|
||||||
|
|
||||||
/** Hide the flyout immediately and cancel any pending hide runnables. */
|
/** Hide the flyout immediately and cancel any pending hide runnables. */
|
||||||
private void hideFlyoutImmediate() {
|
private void hideFlyoutImmediate() {
|
||||||
if (mAfterFlyoutHides != null) {
|
clearFlyoutOnHide();
|
||||||
mAfterFlyoutHides.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
mFlyout.removeCallbacks(mAnimateInFlyout);
|
mFlyout.removeCallbacks(mAnimateInFlyout);
|
||||||
mFlyout.removeCallbacks(mHideFlyout);
|
mFlyout.removeCallbacks(mHideFlyout);
|
||||||
mFlyout.hideFlyout();
|
mFlyout.hideFlyout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearFlyoutOnHide() {
|
||||||
|
mFlyout.removeCallbacks(mAnimateInFlyout);
|
||||||
|
if (mFlyoutOnHide == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mFlyoutOnHide.run();
|
||||||
|
mFlyoutOnHide = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getBoundsOnScreen(Rect outRect) {
|
public void getBoundsOnScreen(Rect outRect) {
|
||||||
if (!mIsExpanded) {
|
if (!mIsExpanded) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class BubbleView extends FrameLayout {
|
|||||||
// mBubbleIconFactory cannot be static because it depends on Context.
|
// mBubbleIconFactory cannot be static because it depends on Context.
|
||||||
private BubbleIconFactory mBubbleIconFactory;
|
private BubbleIconFactory mBubbleIconFactory;
|
||||||
|
|
||||||
private boolean mSuppressDot = false;
|
private boolean mSuppressDot;
|
||||||
|
|
||||||
private Bubble mBubble;
|
private Bubble mBubble;
|
||||||
|
|
||||||
@@ -140,6 +140,7 @@ public class BubbleView extends FrameLayout {
|
|||||||
public void setAppIcon(Drawable appIcon) {
|
public void setAppIcon(Drawable appIcon) {
|
||||||
mUserBadgedAppIcon = appIcon;
|
mUserBadgedAppIcon = appIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the {@link ExpandableNotificationRow} view to display notification content when the
|
* @return the {@link ExpandableNotificationRow} view to display notification content when the
|
||||||
* bubble is expanded.
|
* bubble is expanded.
|
||||||
@@ -154,7 +155,6 @@ public class BubbleView extends FrameLayout {
|
|||||||
updateDotVisibility(animate, null /* after */);
|
updateDotVisibility(animate, null /* after */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not to hide the dot even if we'd otherwise show it. This is used while the
|
* Sets whether or not to hide the dot even if we'd otherwise show it. This is used while the
|
||||||
* flyout is visible or animating, to hide the dot until the flyout visually transforms into it.
|
* flyout is visible or animating, to hide the dot until the flyout visually transforms into it.
|
||||||
@@ -166,7 +166,7 @@ public class BubbleView extends FrameLayout {
|
|||||||
|
|
||||||
/** Sets the position of the 'new' dot, animating it out and back in if requested. */
|
/** Sets the position of the 'new' dot, animating it out and back in if requested. */
|
||||||
void setDotPosition(boolean onLeft, boolean animate) {
|
void setDotPosition(boolean onLeft, boolean animate) {
|
||||||
if (animate && onLeft != mBadgedImageView.getDotOnLeft() && !mSuppressDot) {
|
if (animate && onLeft != mBadgedImageView.getDotOnLeft() && shouldShowDot()) {
|
||||||
animateDot(false /* showDot */, () -> {
|
animateDot(false /* showDot */, () -> {
|
||||||
mBadgedImageView.setDotOnLeft(onLeft);
|
mBadgedImageView.setDotOnLeft(onLeft);
|
||||||
animateDot(true /* showDot */, null);
|
animateDot(true /* showDot */, null);
|
||||||
@@ -190,12 +190,12 @@ public class BubbleView extends FrameLayout {
|
|||||||
* after animation if requested.
|
* after animation if requested.
|
||||||
*/
|
*/
|
||||||
private void updateDotVisibility(boolean animate, Runnable after) {
|
private void updateDotVisibility(boolean animate, Runnable after) {
|
||||||
boolean showDot = mBubble.showBubbleDot() && !mSuppressDot;
|
final boolean showDot = shouldShowDot();
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
animateDot(showDot, after);
|
animateDot(showDot, after);
|
||||||
} else {
|
} else {
|
||||||
mBadgedImageView.setShowDot(showDot);
|
mBadgedImageView.setShowDot(showDot);
|
||||||
|
mBadgedImageView.setDotScale(showDot ? 1f : 0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,27 +203,25 @@ public class BubbleView extends FrameLayout {
|
|||||||
* Animates the badge to show or hide.
|
* Animates the badge to show or hide.
|
||||||
*/
|
*/
|
||||||
private void animateDot(boolean showDot, Runnable after) {
|
private void animateDot(boolean showDot, Runnable after) {
|
||||||
if (mBadgedImageView.isShowingDot() != showDot) {
|
if (mBadgedImageView.isShowingDot() == showDot) {
|
||||||
if (showDot) {
|
return;
|
||||||
mBadgedImageView.setShowDot(true);
|
|
||||||
}
|
|
||||||
mBadgedImageView.clearAnimation();
|
|
||||||
mBadgedImageView.animate().setDuration(200)
|
|
||||||
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
|
|
||||||
.setUpdateListener((valueAnimator) -> {
|
|
||||||
float fraction = valueAnimator.getAnimatedFraction();
|
|
||||||
fraction = showDot ? fraction : 1f - fraction;
|
|
||||||
mBadgedImageView.setDotScale(fraction);
|
|
||||||
}).withEndAction(() -> {
|
|
||||||
if (!showDot) {
|
|
||||||
mBadgedImageView.setShowDot(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (after != null) {
|
|
||||||
after.run();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
|
// Do NOT wait until after animation ends to setShowDot
|
||||||
|
// to avoid overriding more recent showDot states.
|
||||||
|
mBadgedImageView.setShowDot(showDot);
|
||||||
|
mBadgedImageView.clearAnimation();
|
||||||
|
mBadgedImageView.animate().setDuration(200)
|
||||||
|
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
|
||||||
|
.setUpdateListener((valueAnimator) -> {
|
||||||
|
float fraction = valueAnimator.getAnimatedFraction();
|
||||||
|
fraction = showDot ? fraction : 1f - fraction;
|
||||||
|
mBadgedImageView.setDotScale(fraction);
|
||||||
|
}).withEndAction(() -> {
|
||||||
|
mBadgedImageView.setDotScale(showDot ? 1f : 0f);
|
||||||
|
if (after != null) {
|
||||||
|
after.run();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateViews() {
|
void updateViews() {
|
||||||
@@ -273,7 +271,11 @@ public class BubbleView extends FrameLayout {
|
|||||||
iconPath.transform(matrix);
|
iconPath.transform(matrix);
|
||||||
mBadgedImageView.drawDot(iconPath);
|
mBadgedImageView.drawDot(iconPath);
|
||||||
|
|
||||||
animateDot(mBubble.showBubbleDot() /* showDot */, null /* after */);
|
animateDot(shouldShowDot(), null /* after */);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldShowDot() {
|
||||||
|
return mBubble.showBubbleDot() && !mSuppressDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getBadgeColor() {
|
int getBadgeColor() {
|
||||||
|
|||||||
Reference in New Issue
Block a user