Loading cmds/statsd/src/atoms.proto +1 −0 Original line number Diff line number Diff line Loading @@ -5263,6 +5263,7 @@ message BubbleUIChanged { PERMISSION_IGNORED = 12; SWIPE_LEFT = 13; SWIPE_RIGHT = 14; STACK_EXPANDED = 15; } optional Action action = 6; Loading packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +87 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,9 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading @@ -54,6 +56,9 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import java.math.BigDecimal; import java.math.RoundingMode; /** * Renders bubbles in a stack and handles animating expanded and collapsed states. */ Loading Loading @@ -240,16 +245,20 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F // Previously expanded, notify that this bubble is no longer expanded notifyExpansionChanged(mExpandedBubble, false /* expanded */); } BubbleView prevBubble = mExpandedBubble; mExpandedBubble = bubbleToExpand; if (!mIsExpanded) { // If we weren't previously expanded we should animate open. animateExpansion(true /* expand */); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); } else { // Otherwise just update the views // TODO: probably animate / page to expanded one updateExpandedBubble(); updatePointerPosition(); requestUpdate(); logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); } mExpandedBubble.getEntry().setShowInShadeWhenBubble(false); notifyExpansionChanged(mExpandedBubble, true /* expanded */); Loading Loading @@ -278,6 +287,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); ViewClippingUtil.setClippingDeactivated(bubbleView, true, mClippingParameters); requestUpdate(); logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED); } /** Loading @@ -300,6 +310,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F if (wasExpanded != mIsExpanded) { notifyExpansionChanged(mExpandedBubble, mIsExpanded); } logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); } /** Loading @@ -308,6 +319,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F public void stackDismissed() { collapseStack(); mBubbleContainer.removeAllViews(); logBubbleEvent(null /* no bubble associated with bubble stack dismiss */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED); } /** Loading @@ -331,6 +344,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F entry.setShowInShadeWhenBubble(false); requestUpdate(); } logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED); } /** Loading Loading @@ -366,6 +380,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F // TODO: Save opened bubble & move it to top of stack animateExpansion(false /* shouldExpand */); notifyExpansionChanged(mExpandedBubble, mIsExpanded); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); } } Loading @@ -382,6 +397,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F if (!mIsExpanded) { mExpandedBubble = getTopBubble(); setExpandedBubble(mExpandedBubble); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED); } } Loading Loading @@ -574,6 +590,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F .setStiffness(SpringForce.STIFFNESS_LOW) .setDampingRatio(SPRING_DAMPING_RATIO), /* destination */ null); logBubbleEvent(null /* no bubble associated with bubble stack move */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); } /** Loading Loading @@ -733,4 +752,72 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F viewState.headsUpIsVisible = false; viewState.applyToView(view); } /** * @return the number of bubbles in the stack view. */ private int getBubbleCount() { return mBubbleContainer.getChildCount(); } /** * Finds the bubble index within the stack. * * @param bubbleView the view of the bubble. * @return the index of the bubble view within the bubble stack. The range of the position * is between 0 and the bubble count minus 1. */ private int getBubbleIndex(BubbleView bubbleView) { return mBubbleContainer.indexOfChild(bubbleView); } /** * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places. */ private float getNormalizedXPosition() { return new BigDecimal(getPosition().x / mDisplaySize.x) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } /** * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places. */ private float getNormalizedYPosition() { return new BigDecimal(getPosition().y / mDisplaySize.y) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } /** * Logs the bubble UI event. * * @param bubble the bubble that is being interacted on. Null value indicates that * the user interaction is not specific to one bubble. * @param action the user interaction enum. */ private void logBubbleEvent(@Nullable BubbleView bubble, int action) { if (bubble == null) { StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, null /* package name */, null /* notification channel */, 0 /* notification ID */, 0 /* bubble position */, getBubbleCount(), action, getNormalizedXPosition(), getNormalizedYPosition()); } else { StatusBarNotification notification = bubble.getEntry().notification; StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, notification.getPackageName(), notification.getNotification().getChannelId(), notification.getId(), getBubbleIndex(bubble), getBubbleCount(), action, getNormalizedXPosition(), getNormalizedYPosition()); } } } Loading
cmds/statsd/src/atoms.proto +1 −0 Original line number Diff line number Diff line Loading @@ -5263,6 +5263,7 @@ message BubbleUIChanged { PERMISSION_IGNORED = 12; SWIPE_LEFT = 13; SWIPE_RIGHT = 14; STACK_EXPANDED = 15; } optional Action action = 6; Loading
packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +87 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,9 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.service.notification.StatusBarNotification; import android.util.Log; import android.util.StatsLog; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; Loading @@ -54,6 +56,9 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import java.math.BigDecimal; import java.math.RoundingMode; /** * Renders bubbles in a stack and handles animating expanded and collapsed states. */ Loading Loading @@ -240,16 +245,20 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F // Previously expanded, notify that this bubble is no longer expanded notifyExpansionChanged(mExpandedBubble, false /* expanded */); } BubbleView prevBubble = mExpandedBubble; mExpandedBubble = bubbleToExpand; if (!mIsExpanded) { // If we weren't previously expanded we should animate open. animateExpansion(true /* expand */); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); } else { // Otherwise just update the views // TODO: probably animate / page to expanded one updateExpandedBubble(); updatePointerPosition(); requestUpdate(); logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED); } mExpandedBubble.getEntry().setShowInShadeWhenBubble(false); notifyExpansionChanged(mExpandedBubble, true /* expanded */); Loading Loading @@ -278,6 +287,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); ViewClippingUtil.setClippingDeactivated(bubbleView, true, mClippingParameters); requestUpdate(); logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED); } /** Loading @@ -300,6 +310,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F if (wasExpanded != mIsExpanded) { notifyExpansionChanged(mExpandedBubble, mIsExpanded); } logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED); } /** Loading @@ -308,6 +319,8 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F public void stackDismissed() { collapseStack(); mBubbleContainer.removeAllViews(); logBubbleEvent(null /* no bubble associated with bubble stack dismiss */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED); } /** Loading @@ -331,6 +344,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F entry.setShowInShadeWhenBubble(false); requestUpdate(); } logBubbleEvent(bubbleView, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED); } /** Loading Loading @@ -366,6 +380,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F // TODO: Save opened bubble & move it to top of stack animateExpansion(false /* shouldExpand */); notifyExpansionChanged(mExpandedBubble, mIsExpanded); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED); } } Loading @@ -382,6 +397,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F if (!mIsExpanded) { mExpandedBubble = getTopBubble(); setExpandedBubble(mExpandedBubble); logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED); } } Loading Loading @@ -574,6 +590,9 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F .setStiffness(SpringForce.STIFFNESS_LOW) .setDampingRatio(SPRING_DAMPING_RATIO), /* destination */ null); logBubbleEvent(null /* no bubble associated with bubble stack move */, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); } /** Loading Loading @@ -733,4 +752,72 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F viewState.headsUpIsVisible = false; viewState.applyToView(view); } /** * @return the number of bubbles in the stack view. */ private int getBubbleCount() { return mBubbleContainer.getChildCount(); } /** * Finds the bubble index within the stack. * * @param bubbleView the view of the bubble. * @return the index of the bubble view within the bubble stack. The range of the position * is between 0 and the bubble count minus 1. */ private int getBubbleIndex(BubbleView bubbleView) { return mBubbleContainer.indexOfChild(bubbleView); } /** * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places. */ private float getNormalizedXPosition() { return new BigDecimal(getPosition().x / mDisplaySize.x) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } /** * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places. */ private float getNormalizedYPosition() { return new BigDecimal(getPosition().y / mDisplaySize.y) .setScale(4, RoundingMode.CEILING.HALF_UP) .floatValue(); } /** * Logs the bubble UI event. * * @param bubble the bubble that is being interacted on. Null value indicates that * the user interaction is not specific to one bubble. * @param action the user interaction enum. */ private void logBubbleEvent(@Nullable BubbleView bubble, int action) { if (bubble == null) { StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, null /* package name */, null /* notification channel */, 0 /* notification ID */, 0 /* bubble position */, getBubbleCount(), action, getNormalizedXPosition(), getNormalizedYPosition()); } else { StatusBarNotification notification = bubble.getEntry().notification; StatsLog.write(StatsLog.BUBBLE_UI_CHANGED, notification.getPackageName(), notification.getNotification().getChannelId(), notification.getId(), getBubbleIndex(bubble), getBubbleCount(), action, getNormalizedXPosition(), getNormalizedYPosition()); } } }