Merge "Delete BubbleTouchHandler in favor of more traditional touch handling." into rvc-dev am: 8fc6e456b2
Change-Id: Iccddbde2b10380768bbafae3255378c5250717fc
This commit is contained in:
@@ -718,13 +718,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
return mBubbleData.isExpanded();
|
return mBubbleData.isExpanded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the stack of bubbles to expand.
|
|
||||||
*/
|
|
||||||
public void expandStack() {
|
|
||||||
mBubbleData.setExpanded(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the stack of bubbles to collapse.
|
* Tell the stack of bubbles to collapse.
|
||||||
*/
|
*/
|
||||||
@@ -753,12 +746,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed;
|
return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void selectBubble(String key) {
|
|
||||||
Bubble bubble = mBubbleData.getBubbleWithKey(key);
|
|
||||||
mBubbleData.setSelectedBubble(bubble);
|
|
||||||
}
|
|
||||||
|
|
||||||
void promoteBubbleFromOverflow(Bubble bubble) {
|
void promoteBubbleFromOverflow(Bubble bubble) {
|
||||||
bubble.setInflateSynchronously(mInflateSynchronously);
|
bubble.setInflateSynchronously(mInflateSynchronously);
|
||||||
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
|
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
|
||||||
@@ -777,13 +764,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
|
|
||||||
*/
|
|
||||||
void dismissStack(@DismissReason int reason) {
|
|
||||||
mBubbleData.dismissAll(reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directs a back gesture at the bubble stack. When opened, the current expanded bubble
|
* Directs a back gesture at the bubble stack. When opened, the current expanded bubble
|
||||||
* is forwarded a back key down/up pair.
|
* is forwarded a back key down/up pair.
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.content.Context;
|
|||||||
import android.service.notification.NotificationListenerService;
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -751,6 +752,7 @@ public class BubbleData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(visibility = PRIVATE)
|
@VisibleForTesting(visibility = PRIVATE)
|
||||||
|
@Nullable
|
||||||
Bubble getBubbleWithKey(String key) {
|
Bubble getBubbleWithKey(String key) {
|
||||||
for (int i = 0; i < mBubbles.size(); i++) {
|
for (int i = 0; i < mBubbles.size(); i++) {
|
||||||
Bubble bubble = mBubbles.get(i);
|
Bubble bubble = mBubbles.get(i);
|
||||||
@@ -761,6 +763,17 @@ public class BubbleData {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Bubble getBubbleWithView(View view) {
|
||||||
|
for (int i = 0; i < mBubbles.size(); i++) {
|
||||||
|
Bubble bubble = mBubbles.get(i);
|
||||||
|
if (bubble.getIconView() != null && bubble.getIconView().equals(view)) {
|
||||||
|
return bubble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting(visibility = PRIVATE)
|
@VisibleForTesting(visibility = PRIVATE)
|
||||||
Bubble getOverflowBubbleWithKey(String key) {
|
Bubble getOverflowBubbleWithKey(String key) {
|
||||||
for (int i = 0; i < mOverflowBubbles.size(); i++) {
|
for (int i = 0; i < mOverflowBubbles.size(); i++) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
|
|||||||
import android.animation.Animator;
|
import android.animation.Animator;
|
||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
@@ -43,6 +44,7 @@ import android.graphics.Point;
|
|||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.Region;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -83,6 +85,7 @@ import com.android.systemui.shared.system.QuickStepContract;
|
|||||||
import com.android.systemui.shared.system.SysUiStatsLog;
|
import com.android.systemui.shared.system.SysUiStatsLog;
|
||||||
import com.android.systemui.util.DismissCircleView;
|
import com.android.systemui.util.DismissCircleView;
|
||||||
import com.android.systemui.util.FloatingContentCoordinator;
|
import com.android.systemui.util.FloatingContentCoordinator;
|
||||||
|
import com.android.systemui.util.RelativeTouchListener;
|
||||||
import com.android.systemui.util.animation.PhysicsAnimator;
|
import com.android.systemui.util.animation.PhysicsAnimator;
|
||||||
import com.android.systemui.util.magnetictarget.MagnetizedObject;
|
import com.android.systemui.util.magnetictarget.MagnetizedObject;
|
||||||
|
|
||||||
@@ -239,7 +242,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mExpandedAnimationController.dump(fd, pw, args);
|
mExpandedAnimationController.dump(fd, pw, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BubbleTouchHandler mTouchHandler;
|
|
||||||
private BubbleController.BubbleExpandListener mExpandListener;
|
private BubbleController.BubbleExpandListener mExpandListener;
|
||||||
private SysUiState mSysUiState;
|
private SysUiState mSysUiState;
|
||||||
|
|
||||||
@@ -296,7 +298,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Object o, float v) {
|
public void setValue(Object o, float v) {
|
||||||
onFlyoutDragged(v);
|
setFlyoutStateForDragLength(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -336,13 +338,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
*/
|
*/
|
||||||
private MagnetizedObject<?> mMagnetizedObject;
|
private MagnetizedObject<?> mMagnetizedObject;
|
||||||
|
|
||||||
/**
|
|
||||||
* The action to run when the magnetized object is released in the dismiss target.
|
|
||||||
*
|
|
||||||
* This will actually perform the dismissal of either the stack or an individual bubble.
|
|
||||||
*/
|
|
||||||
private Runnable mReleasedInDismissTargetAction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The MagneticTarget instance for our circular dismiss view. This is added to the
|
* The MagneticTarget instance for our circular dismiss view. This is added to the
|
||||||
* MagnetizedObject instances for the stack and any dragged-out bubbles.
|
* MagnetizedObject instances for the stack and any dragged-out bubbles.
|
||||||
@@ -377,7 +372,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
|
public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
|
||||||
mExpandedAnimationController.dismissDraggedOutBubble(
|
mExpandedAnimationController.dismissDraggedOutBubble(
|
||||||
mExpandedAnimationController.getDraggedOutBubble(),
|
mExpandedAnimationController.getDraggedOutBubble(),
|
||||||
mReleasedInDismissTargetAction);
|
BubbleStackView.this::dismissMagnetizedObject);
|
||||||
hideDismissTarget();
|
hideDismissTarget();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -410,7 +405,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mStackAnimationController.implodeStack(
|
mStackAnimationController.implodeStack(
|
||||||
() -> {
|
() -> {
|
||||||
resetDesaturationAndDarken();
|
resetDesaturationAndDarken();
|
||||||
mReleasedInDismissTargetAction.run();
|
dismissMagnetizedObject();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -418,6 +413,197 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Click listener set on each bubble view. When collapsed, clicking a bubble expands the stack.
|
||||||
|
* When expanded, clicking a bubble either expands that bubble, or collapses the stack.
|
||||||
|
*/
|
||||||
|
private OnClickListener mBubbleClickListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
final Bubble clickedBubble = mBubbleData.getBubbleWithView(view);
|
||||||
|
|
||||||
|
// If the bubble has since left us, ignore the click.
|
||||||
|
if (clickedBubble == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean clickedBubbleIsCurrentlyExpandedBubble =
|
||||||
|
clickedBubble.getKey().equals(mExpandedBubble.getKey());
|
||||||
|
|
||||||
|
if (isExpanded() && !clickedBubbleIsCurrentlyExpandedBubble) {
|
||||||
|
if (clickedBubble != mBubbleData.getSelectedBubble()) {
|
||||||
|
// Select the clicked bubble.
|
||||||
|
mBubbleData.setSelectedBubble(clickedBubble);
|
||||||
|
} else {
|
||||||
|
// If the clicked bubble is the selected bubble (but not the expanded bubble),
|
||||||
|
// that means overflow was previously expanded. Set the selected bubble
|
||||||
|
// internally without going through BubbleData (which would ignore it since it's
|
||||||
|
// already selected).
|
||||||
|
setSelectedBubble(clickedBubble);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, we either tapped the stack (which means we're collapsed
|
||||||
|
// and should expand) or the currently selected bubble (we're expanded
|
||||||
|
// and should collapse).
|
||||||
|
if (!maybeShowStackUserEducation()) {
|
||||||
|
mBubbleData.setExpanded(!mBubbleData.isExpanded());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Touch listener set on each bubble view. This enables dragging and dismissing the stack (when
|
||||||
|
* collapsed), or individual bubbles (when expanded).
|
||||||
|
*/
|
||||||
|
private RelativeTouchListener mBubbleTouchListener = new RelativeTouchListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) {
|
||||||
|
// If we're expanding or collapsing, consume but ignore all touch events.
|
||||||
|
if (mIsExpansionAnimating) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBubbleData.isExpanded()) {
|
||||||
|
maybeShowManageEducation(false /* show */);
|
||||||
|
|
||||||
|
// If we're expanded, tell the animation controller to prepare to drag this bubble,
|
||||||
|
// dispatching to the individual bubble magnet listener.
|
||||||
|
mExpandedAnimationController.prepareForBubbleDrag(
|
||||||
|
v /* bubble */,
|
||||||
|
mMagneticTarget,
|
||||||
|
mIndividualBubbleMagnetListener);
|
||||||
|
|
||||||
|
// Save the magnetized individual bubble so we can dispatch touch events to it.
|
||||||
|
mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
|
||||||
|
} else {
|
||||||
|
// If we're collapsed, prepare to drag the stack. Cancel active animations, set the
|
||||||
|
// animation controller, and hide the flyout.
|
||||||
|
mStackAnimationController.cancelStackPositionAnimations();
|
||||||
|
mBubbleContainer.setActiveController(mStackAnimationController);
|
||||||
|
hideFlyoutImmediate();
|
||||||
|
|
||||||
|
// Also, save the magnetized stack so we can dispatch touch events to it.
|
||||||
|
mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
|
||||||
|
mMagnetizedObject.setMagnetListener(mStackMagnetListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
passEventToMagnetizedObject(ev);
|
||||||
|
|
||||||
|
// Bubbles are always interested in all touch events!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy) {
|
||||||
|
// If we're expanding or collapsing, ignore all touch events.
|
||||||
|
if (mIsExpansionAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the dismiss target, if we haven't already.
|
||||||
|
springInDismissTargetMaybe();
|
||||||
|
|
||||||
|
// First, see if the magnetized object consumes the event - if so, we shouldn't move the
|
||||||
|
// bubble since it's stuck to the target.
|
||||||
|
if (!passEventToMagnetizedObject(ev)) {
|
||||||
|
if (mBubbleData.isExpanded()) {
|
||||||
|
mExpandedAnimationController.dragBubbleOut(
|
||||||
|
v, viewInitialX + dx, viewInitialY + dy);
|
||||||
|
} else {
|
||||||
|
hideStackUserEducation(false /* fromExpansion */);
|
||||||
|
mStackAnimationController.moveStackFromTouch(
|
||||||
|
viewInitialX + dx, viewInitialY + dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy, float velX, float velY) {
|
||||||
|
// If we're expanding or collapsing, ignore all touch events.
|
||||||
|
if (mIsExpansionAnimating) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, see if the magnetized object consumes the event - if so, the bubble was
|
||||||
|
// released in the target or flung out of it, and we should ignore the event.
|
||||||
|
if (!passEventToMagnetizedObject(ev)) {
|
||||||
|
if (mBubbleData.isExpanded()) {
|
||||||
|
mExpandedAnimationController.snapBubbleBack(v, velX, velY);
|
||||||
|
} else {
|
||||||
|
// Fling the stack to the edge, and save whether or not it's going to end up on
|
||||||
|
// the left side of the screen.
|
||||||
|
mStackOnLeftOrWillBe =
|
||||||
|
mStackAnimationController.flingStackThenSpringToEdge(
|
||||||
|
viewInitialX + dx, velX, velY) <= 0;
|
||||||
|
|
||||||
|
updateBubbleZOrdersAndDotPosition(true /* animate */);
|
||||||
|
|
||||||
|
logBubbleEvent(null /* no bubble associated with bubble stack move */,
|
||||||
|
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideDismissTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Click listener set on the flyout, which expands the stack when the flyout is tapped. */
|
||||||
|
private OnClickListener mFlyoutClickListener = new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
if (maybeShowStackUserEducation()) {
|
||||||
|
// If we're showing user education, don't open the bubble show the education first
|
||||||
|
mBubbleToExpandAfterFlyoutCollapse = null;
|
||||||
|
} else {
|
||||||
|
mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble();
|
||||||
|
}
|
||||||
|
|
||||||
|
mFlyout.removeCallbacks(mHideFlyout);
|
||||||
|
mHideFlyout.run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Touch listener for the flyout. This enables the drag-to-dismiss gesture on the flyout. */
|
||||||
|
private RelativeTouchListener mFlyoutTouchListener = new RelativeTouchListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) {
|
||||||
|
mFlyout.removeCallbacks(mHideFlyout);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy) {
|
||||||
|
setFlyoutStateForDragLength(dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy, float velX, float velY) {
|
||||||
|
final boolean onLeft = mStackAnimationController.isStackOnLeftSide();
|
||||||
|
final boolean metRequiredVelocity =
|
||||||
|
onLeft ? velX < -FLYOUT_DISMISS_VELOCITY : velX > FLYOUT_DISMISS_VELOCITY;
|
||||||
|
final boolean metRequiredDeltaX =
|
||||||
|
onLeft
|
||||||
|
? dx < -mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS
|
||||||
|
: dx > mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS;
|
||||||
|
final boolean isCancelFling = onLeft ? velX > 0 : velX < 0;
|
||||||
|
final boolean shouldDismiss = metRequiredVelocity
|
||||||
|
|| (metRequiredDeltaX && !isCancelFling);
|
||||||
|
|
||||||
|
mFlyout.removeCallbacks(mHideFlyout);
|
||||||
|
animateFlyoutCollapsed(shouldDismiss, velX);
|
||||||
|
|
||||||
|
maybeShowStackUserEducation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private ViewGroup mDismissTargetContainer;
|
private ViewGroup mDismissTargetContainer;
|
||||||
private PhysicsAnimator<View> mDismissTargetAnimator;
|
private PhysicsAnimator<View> mDismissTargetAnimator;
|
||||||
private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig(
|
private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig(
|
||||||
@@ -436,6 +622,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
private BubbleManageEducationView mManageEducationView;
|
private BubbleManageEducationView mManageEducationView;
|
||||||
private boolean mAnimatingManageEducationAway;
|
private boolean mAnimatingManageEducationAway;
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
public BubbleStackView(Context context, BubbleData data,
|
public BubbleStackView(Context context, BubbleData data,
|
||||||
@Nullable SurfaceSynchronizer synchronizer,
|
@Nullable SurfaceSynchronizer synchronizer,
|
||||||
FloatingContentCoordinator floatingContentCoordinator,
|
FloatingContentCoordinator floatingContentCoordinator,
|
||||||
@@ -444,8 +631,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
|
|
||||||
mBubbleData = data;
|
mBubbleData = data;
|
||||||
mInflater = LayoutInflater.from(context);
|
mInflater = LayoutInflater.from(context);
|
||||||
mTouchHandler = new BubbleTouchHandler(this, data, context);
|
|
||||||
setOnTouchListener(mTouchHandler);
|
|
||||||
|
|
||||||
mSysUiState = sysUiState;
|
mSysUiState = sysUiState;
|
||||||
|
|
||||||
@@ -641,6 +826,18 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
|
mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
|
||||||
mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
|
mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If the stack itself is touched, it means none of its touchable views (bubbles, flyouts,
|
||||||
|
// ActivityViews, etc.) were touched. Collapse the stack if it's expanded.
|
||||||
|
setOnTouchListener((view, ev) -> {
|
||||||
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (mBubbleData.isExpanded()) {
|
||||||
|
mBubbleData.setExpanded(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpUserEducation() {
|
private void setUpUserEducation() {
|
||||||
@@ -690,6 +887,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private void setUpFlyout() {
|
private void setUpFlyout() {
|
||||||
if (mFlyout != null) {
|
if (mFlyout != null) {
|
||||||
removeView(mFlyout);
|
removeView(mFlyout);
|
||||||
@@ -699,6 +897,8 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mFlyout.animate()
|
mFlyout.animate()
|
||||||
.setDuration(FLYOUT_ALPHA_ANIMATION_DURATION)
|
.setDuration(FLYOUT_ALPHA_ANIMATION_DURATION)
|
||||||
.setInterpolator(new AccelerateDecelerateInterpolator());
|
.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
mFlyout.setOnClickListener(mFlyoutClickListener);
|
||||||
|
mFlyout.setOnTouchListener(mFlyoutTouchListener);
|
||||||
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,6 +918,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
|
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
|
||||||
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||||
|
|
||||||
|
mBubbleOverflow.getBtn().setOnClickListener(v -> setSelectedBubble(mBubbleOverflow));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Handle theme changes.
|
* Handle theme changes.
|
||||||
@@ -920,6 +1121,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// via BubbleData.Listener
|
// via BubbleData.Listener
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
void addBubble(Bubble bubble) {
|
void addBubble(Bubble bubble) {
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
if (DEBUG_BUBBLE_STACK_VIEW) {
|
||||||
Log.d(TAG, "addBubble: " + bubble);
|
Log.d(TAG, "addBubble: " + bubble);
|
||||||
@@ -944,6 +1146,9 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
bubble.getIconView().setDotPositionOnLeft(
|
bubble.getIconView().setDotPositionOnLeft(
|
||||||
!mStackOnLeftOrWillBe /* onLeft */, false /* animate */);
|
!mStackOnLeftOrWillBe /* onLeft */, false /* animate */);
|
||||||
|
|
||||||
|
bubble.getIconView().setOnClickListener(mBubbleClickListener);
|
||||||
|
bubble.getIconView().setOnTouchListener(mBubbleTouchListener);
|
||||||
|
|
||||||
mBubbleContainer.addView(bubble.getIconView(), 0,
|
mBubbleContainer.addView(bubble.getIconView(), 0,
|
||||||
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||||
ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters);
|
ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters);
|
||||||
@@ -1009,10 +1214,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
updatePointerPosition();
|
updatePointerPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void showOverflow() {
|
|
||||||
setSelectedBubble(mBubbleOverflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the currently selected bubble. If the stack is already expanded, the newly selected
|
* Changes the currently selected bubble. If the stack is already expanded, the newly selected
|
||||||
* bubble will be shown immediately. This does not change the expanded state or change the
|
* bubble will be shown immediately. This does not change the expanded state or change the
|
||||||
@@ -1177,14 +1378,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets the action to run to dismiss the currently dragging object (either the stack or an
|
|
||||||
* individual bubble).
|
|
||||||
*/
|
|
||||||
public void setReleasedInDismissTargetAction(Runnable action) {
|
|
||||||
mReleasedInDismissTargetAction = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dismiss the stack of bubbles.
|
* Dismiss the stack of bubbles.
|
||||||
*
|
*
|
||||||
@@ -1200,54 +1393,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
|
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the view the touch event is on
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public View getTargetView(MotionEvent event) {
|
|
||||||
float x = event.getRawX();
|
|
||||||
float y = event.getRawY();
|
|
||||||
if (mIsExpanded) {
|
|
||||||
if (isIntersecting(mBubbleContainer, x, y)) {
|
|
||||||
if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
|
|
||||||
&& isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
|
|
||||||
return mBubbleOverflow.getBtn();
|
|
||||||
}
|
|
||||||
// Could be tapping or dragging a bubble while expanded
|
|
||||||
for (int i = 0; i < getBubbleCount(); i++) {
|
|
||||||
BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i);
|
|
||||||
if (isIntersecting(view, x, y)) {
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BubbleExpandedView bev = (BubbleExpandedView) mExpandedViewContainer.getChildAt(0);
|
|
||||||
if (bev.intersectingTouchableContent((int) x, (int) y)) {
|
|
||||||
return bev;
|
|
||||||
}
|
|
||||||
// Outside of the parts we care about.
|
|
||||||
return null;
|
|
||||||
} else if (mFlyout.getVisibility() == VISIBLE && isIntersecting(mFlyout, x, y)) {
|
|
||||||
return mFlyout;
|
|
||||||
} else if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) {
|
|
||||||
View bubbleChild = mBubbleContainer.getChildAt(0);
|
|
||||||
if (isIntersecting(bubbleChild, x, y)) {
|
|
||||||
return this;
|
|
||||||
} else if (isIntersecting(mUserEducationView, x, y)) {
|
|
||||||
return mUserEducationView;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it wasn't an individual bubble in the expanded state, or the flyout, it's the stack.
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
View getFlyoutView() {
|
|
||||||
return mFlyout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use {@link #setExpanded(boolean)} and
|
* @deprecated use {@link #setExpanded(boolean)} and
|
||||||
* {@link BubbleData#setSelectedBubble(Bubble)}
|
* {@link BubbleData#setSelectedBubble(Bubble)}
|
||||||
@@ -1385,124 +1530,70 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when the collapsed stack is tapped on. */
|
/**
|
||||||
void onStackTapped() {
|
* This method is called by {@link android.app.ActivityView} because the BubbleStackView has a
|
||||||
if (!maybeShowStackUserEducation()) {
|
* higher Z-index than the ActivityView (so that dragged-out bubbles are visible over the AV).
|
||||||
mBubbleData.setExpanded(true);
|
* ActivityView is asking BubbleStackView to subtract the stack's bounds from the provided
|
||||||
}
|
* touchable region, so that the ActivityView doesn't consume events meant for the stack. Due to
|
||||||
|
* the special nature of ActivityView, it does not respect the standard
|
||||||
|
* {@link #dispatchTouchEvent} and {@link #onInterceptTouchEvent} methods typically used for
|
||||||
|
* this purpose.
|
||||||
|
*
|
||||||
|
* BubbleStackView is MATCH_PARENT, so that bubbles can be positioned via their translation
|
||||||
|
* properties for performance reasons. This means that the default implementation of this method
|
||||||
|
* subtracts the entirety of the screen from the ActivityView's touchable region, resulting in
|
||||||
|
* it not receiving any touch events. This was previously addressed by returning false in the
|
||||||
|
* stack's {@link View#canReceivePointerEvents()} method, but this precluded the use of any
|
||||||
|
* touch handlers in the stack or its child views.
|
||||||
|
*
|
||||||
|
* To support touch handlers, we're overriding this method to leave the ActivityView's touchable
|
||||||
|
* region alone. The only touchable part of the stack that can ever overlap the AV is a
|
||||||
|
* dragged-out bubble that is animating back into the row of bubbles. It's not worth continually
|
||||||
|
* updating the touchable region to allow users to grab a bubble while it completes its ~50ms
|
||||||
|
* animation back to the bubble row.
|
||||||
|
*
|
||||||
|
* NOTE: Any future additions to the stack that obscure the ActivityView region will need their
|
||||||
|
* bounds subtracted here in order to receive touch events.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a drag operation on an individual bubble has started. */
|
/**
|
||||||
public void onBubbleDragStart(View bubble) {
|
* If you're here because you're not receiving touch events on a view that is a descendant of
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
* BubbleStackView, and you think BSV is intercepting them - it's not! You need to subtract the
|
||||||
Log.d(TAG, "onBubbleDragStart: bubble=" + ((BadgedImageView) bubble).getKey());
|
* bounds of the view in question in {@link #subtractObscuredTouchableRegion}. The ActivityView
|
||||||
}
|
* consumes all touch events within its bounds, even for views like the BubbleStackView that are
|
||||||
|
* above it. It ignores typical view touch handling methods like this one and
|
||||||
if (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView())) {
|
* dispatchTouchEvent.
|
||||||
return;
|
*/
|
||||||
}
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
|
return super.onInterceptTouchEvent(ev);
|
||||||
|
|
||||||
// We're dragging an individual bubble, so set the magnetized object to the magnetized
|
|
||||||
// bubble.
|
|
||||||
mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
|
|
||||||
mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener);
|
|
||||||
|
|
||||||
maybeShowManageEducation(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called with the coordinates to which an individual bubble has been dragged. */
|
@Override
|
||||||
public void onBubbleDragged(View bubble, float x, float y) {
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
if (!mIsExpanded || mIsExpansionAnimating
|
boolean dispatched = super.dispatchTouchEvent(ev);
|
||||||
|| (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
|
|
||||||
return;
|
// If a new bubble arrives while the collapsed stack is being dragged, it will be positioned
|
||||||
|
// at the front of the stack (under the touch position). Subsequent ACTION_MOVE events will
|
||||||
|
// then be passed to the new bubble, which will not consume them since it hasn't received an
|
||||||
|
// ACTION_DOWN yet. Work around this by passing MotionEvents directly to the touch handler
|
||||||
|
// until the current gesture ends with an ACTION_UP event.
|
||||||
|
if (!dispatched && !mIsExpanded && mIsGestureInProgress) {
|
||||||
|
dispatched = mBubbleTouchListener.onTouch(this /* view */, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
mExpandedAnimationController.dragBubbleOut(bubble, x, y);
|
mIsGestureInProgress =
|
||||||
springInDismissTarget();
|
ev.getAction() != MotionEvent.ACTION_UP
|
||||||
|
&& ev.getAction() != MotionEvent.ACTION_CANCEL;
|
||||||
|
|
||||||
|
return dispatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a drag operation on an individual bubble has finished. */
|
void setFlyoutStateForDragLength(float deltaX) {
|
||||||
public void onBubbleDragFinish(
|
|
||||||
View bubble, float x, float y, float velX, float velY) {
|
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
|
||||||
Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mIsExpanded || mIsExpansionAnimating
|
|
||||||
|| (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mExpandedAnimationController.snapBubbleBack(bubble, velX, velY);
|
|
||||||
hideDismissTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Expands the clicked bubble. */
|
|
||||||
public void expandBubble(Bubble bubble) {
|
|
||||||
if (bubble != null && bubble.equals(mBubbleData.getSelectedBubble())) {
|
|
||||||
// If the bubble we're supposed to expand is the selected bubble, that means the
|
|
||||||
// overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as
|
|
||||||
// selected, since it already is. Just call the stack's setSelectedBubble to expand it.
|
|
||||||
setSelectedBubble(bubble);
|
|
||||||
} else {
|
|
||||||
mBubbleData.setSelectedBubble(bubble);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onDragStart() {
|
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
|
||||||
Log.d(TAG, "onDragStart()");
|
|
||||||
}
|
|
||||||
if (mIsExpanded || mIsExpansionAnimating) {
|
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
|
||||||
Log.d(TAG, "mIsExpanded or mIsExpansionAnimating");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mStackAnimationController.cancelStackPositionAnimations();
|
|
||||||
mBubbleContainer.setActiveController(mStackAnimationController);
|
|
||||||
hideFlyoutImmediate();
|
|
||||||
|
|
||||||
// Since we're dragging the stack, set the magnetized object to the magnetized stack.
|
|
||||||
mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
|
|
||||||
mMagnetizedObject.setMagnetListener(mStackMagnetListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onDragged(float x, float y) {
|
|
||||||
if (mIsExpanded || mIsExpansionAnimating) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hideStackUserEducation(false /* fromExpansion */);
|
|
||||||
springInDismissTarget();
|
|
||||||
mStackAnimationController.moveStackFromTouch(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onDragFinish(float x, float y, float velX, float velY) {
|
|
||||||
if (DEBUG_BUBBLE_STACK_VIEW) {
|
|
||||||
Log.d(TAG, "onDragFinish");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mIsExpanded || mIsExpansionAnimating) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final float newStackX = mStackAnimationController.flingStackThenSpringToEdge(x, velX, velY);
|
|
||||||
logBubbleEvent(null /* no bubble associated with bubble stack move */,
|
|
||||||
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED);
|
|
||||||
|
|
||||||
mStackOnLeftOrWillBe = newStackX <= 0;
|
|
||||||
updateBubbleZOrdersAndDotPosition(true /* animate */);
|
|
||||||
hideDismissTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFlyoutDragStart() {
|
|
||||||
mFlyout.removeCallbacks(mHideFlyout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFlyoutDragged(float deltaX) {
|
|
||||||
// This shouldn't happen, but if it does, just wait until the flyout lays out. This method
|
// This shouldn't happen, but if it does, just wait until the flyout lays out. This method
|
||||||
// is continually called.
|
// is continually called.
|
||||||
if (mFlyout.getWidth() <= 0) {
|
if (mFlyout.getWidth() <= 0) {
|
||||||
@@ -1538,61 +1629,29 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
mFlyout.setTranslationX(mFlyout.getRestingTranslationX() + overscrollTranslation);
|
mFlyout.setTranslationX(mFlyout.getRestingTranslationX() + overscrollTranslation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFlyoutTapped() {
|
|
||||||
if (maybeShowStackUserEducation()) {
|
|
||||||
// If we're showing user education, don't open the bubble show the education first
|
|
||||||
mBubbleToExpandAfterFlyoutCollapse = null;
|
|
||||||
} else {
|
|
||||||
mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble();
|
|
||||||
}
|
|
||||||
|
|
||||||
mFlyout.removeCallbacks(mHideFlyout);
|
|
||||||
mHideFlyout.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the flyout drag has finished, and returns true if the gesture successfully
|
|
||||||
* dismissed the flyout.
|
|
||||||
*/
|
|
||||||
void onFlyoutDragFinished(float deltaX, float velX) {
|
|
||||||
final boolean onLeft = mStackAnimationController.isStackOnLeftSide();
|
|
||||||
final boolean metRequiredVelocity =
|
|
||||||
onLeft ? velX < -FLYOUT_DISMISS_VELOCITY : velX > FLYOUT_DISMISS_VELOCITY;
|
|
||||||
final boolean metRequiredDeltaX =
|
|
||||||
onLeft
|
|
||||||
? deltaX < -mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS
|
|
||||||
: deltaX > mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS;
|
|
||||||
final boolean isCancelFling = onLeft ? velX > 0 : velX < 0;
|
|
||||||
final boolean shouldDismiss = metRequiredVelocity || (metRequiredDeltaX && !isCancelFling);
|
|
||||||
|
|
||||||
mFlyout.removeCallbacks(mHideFlyout);
|
|
||||||
animateFlyoutCollapsed(shouldDismiss, velX);
|
|
||||||
|
|
||||||
maybeShowStackUserEducation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the first touch event of a gesture (stack drag, bubble drag, flyout drag, etc.)
|
|
||||||
* is received.
|
|
||||||
*/
|
|
||||||
void onGestureStart() {
|
|
||||||
mIsGestureInProgress = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called when a gesture is completed or cancelled. */
|
|
||||||
void onGestureFinished() {
|
|
||||||
mIsGestureInProgress = false;
|
|
||||||
|
|
||||||
if (mIsExpanded) {
|
|
||||||
mExpandedAnimationController.onGestureFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */
|
/** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */
|
||||||
boolean passEventToMagnetizedObject(MotionEvent event) {
|
private boolean passEventToMagnetizedObject(MotionEvent event) {
|
||||||
return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event);
|
return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismisses the magnetized object - either an individual bubble, if we're expanded, or the
|
||||||
|
* stack, if we're collapsed.
|
||||||
|
*/
|
||||||
|
private void dismissMagnetizedObject() {
|
||||||
|
if (mIsExpanded) {
|
||||||
|
final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject();
|
||||||
|
final Bubble draggedOutBubble = mBubbleData.getBubbleWithView(draggedOutBubbleView);
|
||||||
|
|
||||||
|
if (mBubbleData.hasBubbleWithKey(draggedOutBubble.getKey())) {
|
||||||
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
draggedOutBubble.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Prepares and starts the desaturate/darken animation on the bubble stack. */
|
/** Prepares and starts the desaturate/darken animation on the bubble stack. */
|
||||||
private void animateDesaturateAndDarken(View targetView, boolean desaturateAndDarken) {
|
private void animateDesaturateAndDarken(View targetView, boolean desaturateAndDarken) {
|
||||||
mDesaturateAndDarkenTargetView = targetView;
|
mDesaturateAndDarkenTargetView = targetView;
|
||||||
@@ -1624,7 +1683,7 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Animates in the dismiss target. */
|
/** Animates in the dismiss target. */
|
||||||
private void springInDismissTarget() {
|
private void springInDismissTargetMaybe() {
|
||||||
if (mShowingDismiss) {
|
if (mShowingDismiss) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1827,13 +1886,6 @@ public class BubbleStackView extends FrameLayout {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIntersecting(View view, float x, float y) {
|
|
||||||
mTempLoc = view.getLocationOnScreen();
|
|
||||||
mTempRect.set(mTempLoc[0], mTempLoc[1], mTempLoc[0] + view.getWidth(),
|
|
||||||
mTempLoc[1] + view.getHeight());
|
|
||||||
return mTempRect.contains(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestUpdate() {
|
private void requestUpdate() {
|
||||||
if (mViewUpdatedRequested || mIsExpansionAnimating) {
|
if (mViewUpdatedRequested || mIsExpansionAnimating) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.systemui.bubbles;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.PointF;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.VelocityTracker;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewConfiguration;
|
|
||||||
|
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing,
|
|
||||||
* dismissing, and flings.
|
|
||||||
*/
|
|
||||||
class BubbleTouchHandler implements View.OnTouchListener {
|
|
||||||
|
|
||||||
private final PointF mTouchDown = new PointF();
|
|
||||||
private final PointF mViewPositionOnTouchDown = new PointF();
|
|
||||||
private final BubbleStackView mStack;
|
|
||||||
private final BubbleData mBubbleData;
|
|
||||||
|
|
||||||
private BubbleController mController = Dependency.get(BubbleController.class);
|
|
||||||
|
|
||||||
private boolean mMovedEnough;
|
|
||||||
private int mTouchSlopSquared;
|
|
||||||
private VelocityTracker mVelocityTracker;
|
|
||||||
|
|
||||||
/** View that was initially touched, when we received the first ACTION_DOWN event. */
|
|
||||||
private View mTouchedView;
|
|
||||||
|
|
||||||
BubbleTouchHandler(BubbleStackView stackView,
|
|
||||||
BubbleData bubbleData, Context context) {
|
|
||||||
final int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
|
||||||
mTouchSlopSquared = touchSlop * touchSlop;
|
|
||||||
mBubbleData = bubbleData;
|
|
||||||
mStack = stackView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
final int action = event.getActionMasked();
|
|
||||||
|
|
||||||
// If we aren't currently in the process of touching a view, figure out what we're touching.
|
|
||||||
// It'll be the stack, an individual bubble, or nothing.
|
|
||||||
if (mTouchedView == null) {
|
|
||||||
mTouchedView = mStack.getTargetView(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is an ACTION_OUTSIDE event, or the stack reported that we aren't touching
|
|
||||||
// anything, collapse the stack.
|
|
||||||
if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) {
|
|
||||||
mBubbleData.setExpanded(false);
|
|
||||||
mStack.hideStackUserEducation(false /* fromExpansion */);
|
|
||||||
resetForNextGesture();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(mTouchedView instanceof BadgedImageView)
|
|
||||||
&& !(mTouchedView instanceof BubbleStackView)
|
|
||||||
&& !(mTouchedView instanceof BubbleFlyoutView)) {
|
|
||||||
|
|
||||||
// Not touching anything touchable, but we shouldn't collapse (e.g. touching edge
|
|
||||||
// of expanded view).
|
|
||||||
mStack.maybeShowManageEducation(false);
|
|
||||||
resetForNextGesture();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean isStack = mStack.equals(mTouchedView);
|
|
||||||
final boolean isFlyout = mStack.getFlyoutView().equals(mTouchedView);
|
|
||||||
final float rawX = event.getRawX();
|
|
||||||
final float rawY = event.getRawY();
|
|
||||||
|
|
||||||
// The coordinates of the touch event, in terms of the touched view's position.
|
|
||||||
final float viewX = mViewPositionOnTouchDown.x + rawX - mTouchDown.x;
|
|
||||||
final float viewY = mViewPositionOnTouchDown.y + rawY - mTouchDown.y;
|
|
||||||
switch (action) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
trackMovement(event);
|
|
||||||
|
|
||||||
mTouchDown.set(rawX, rawY);
|
|
||||||
mStack.onGestureStart();
|
|
||||||
|
|
||||||
if (isStack) {
|
|
||||||
mViewPositionOnTouchDown.set(mStack.getStackPosition());
|
|
||||||
|
|
||||||
// Dismiss the entire stack if it's released in the dismiss target.
|
|
||||||
mStack.setReleasedInDismissTargetAction(
|
|
||||||
() -> mController.dismissStack(BubbleController.DISMISS_USER_GESTURE));
|
|
||||||
mStack.onDragStart();
|
|
||||||
mStack.passEventToMagnetizedObject(event);
|
|
||||||
} else if (isFlyout) {
|
|
||||||
mStack.onFlyoutDragStart();
|
|
||||||
} else {
|
|
||||||
mViewPositionOnTouchDown.set(
|
|
||||||
mTouchedView.getTranslationX(), mTouchedView.getTranslationY());
|
|
||||||
|
|
||||||
// Dismiss only the dragged-out bubble if it's released in the target.
|
|
||||||
final String individualBubbleKey = ((BadgedImageView) mTouchedView).getKey();
|
|
||||||
mStack.setReleasedInDismissTargetAction(() -> {
|
|
||||||
final Bubble bubble =
|
|
||||||
mBubbleData.getBubbleWithKey(individualBubbleKey);
|
|
||||||
// bubble can be null if the user is in the middle of
|
|
||||||
// dismissing the bubble, but the app also sent a cancel
|
|
||||||
if (bubble != null) {
|
|
||||||
mController.removeBubble(bubble.getEntry(),
|
|
||||||
BubbleController.DISMISS_USER_GESTURE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mStack.onBubbleDragStart(mTouchedView);
|
|
||||||
mStack.passEventToMagnetizedObject(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
trackMovement(event);
|
|
||||||
final float deltaX = rawX - mTouchDown.x;
|
|
||||||
final float deltaY = rawY - mTouchDown.y;
|
|
||||||
|
|
||||||
if ((deltaX * deltaX) + (deltaY * deltaY) > mTouchSlopSquared && !mMovedEnough) {
|
|
||||||
mMovedEnough = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mMovedEnough) {
|
|
||||||
if (isFlyout) {
|
|
||||||
mStack.onFlyoutDragged(deltaX);
|
|
||||||
} else if (!mStack.passEventToMagnetizedObject(event)) {
|
|
||||||
// If the magnetic target doesn't consume the event, drag the stack or
|
|
||||||
// bubble.
|
|
||||||
if (isStack) {
|
|
||||||
mStack.onDragged(viewX, viewY);
|
|
||||||
} else {
|
|
||||||
mStack.onBubbleDragged(mTouchedView, viewX, viewY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_CANCEL:
|
|
||||||
resetForNextGesture();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
trackMovement(event);
|
|
||||||
mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
|
|
||||||
final float velX = mVelocityTracker.getXVelocity();
|
|
||||||
final float velY = mVelocityTracker.getYVelocity();
|
|
||||||
|
|
||||||
if (isFlyout && mMovedEnough) {
|
|
||||||
mStack.onFlyoutDragFinished(rawX - mTouchDown.x /* deltaX */, velX);
|
|
||||||
} else if (isFlyout) {
|
|
||||||
if (!mBubbleData.isExpanded() && !mMovedEnough) {
|
|
||||||
mStack.onFlyoutTapped();
|
|
||||||
}
|
|
||||||
} else if (mMovedEnough) {
|
|
||||||
if (!mStack.passEventToMagnetizedObject(event)) {
|
|
||||||
// If the magnetic target didn't consume the event, tell the stack to finish
|
|
||||||
// the drag.
|
|
||||||
if (isStack) {
|
|
||||||
mStack.onDragFinish(viewX, viewY, velX, velY);
|
|
||||||
} else {
|
|
||||||
mStack.onBubbleDragFinish(mTouchedView, viewX, viewY, velX, velY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (mTouchedView == mStack.getExpandedBubbleView()) {
|
|
||||||
mBubbleData.setExpanded(false);
|
|
||||||
} else if (isStack) {
|
|
||||||
mStack.onStackTapped();
|
|
||||||
} else {
|
|
||||||
final String key = ((BadgedImageView) mTouchedView).getKey();
|
|
||||||
if (key == BubbleOverflow.KEY) {
|
|
||||||
mStack.showOverflow();
|
|
||||||
} else {
|
|
||||||
mStack.expandBubble(mBubbleData.getBubbleWithKey(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resetForNextGesture();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clears all touch-related state. */
|
|
||||||
private void resetForNextGesture() {
|
|
||||||
if (mVelocityTracker != null) {
|
|
||||||
mVelocityTracker.recycle();
|
|
||||||
mVelocityTracker = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
mTouchedView = null;
|
|
||||||
mMovedEnough = false;
|
|
||||||
|
|
||||||
mStack.onGestureFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void trackMovement(MotionEvent event) {
|
|
||||||
if (mVelocityTracker == null) {
|
|
||||||
mVelocityTracker = VelocityTracker.obtain();
|
|
||||||
}
|
|
||||||
mVelocityTracker.addMovement(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -252,8 +252,14 @@ public class ExpandedAnimationController
|
|||||||
mSpringToTouchOnNextMotionEvent = true;
|
mSpringToTouchOnNextMotionEvent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Prepares the given bubble to be dragged out. */
|
/**
|
||||||
public void prepareForBubbleDrag(View bubble, MagnetizedObject.MagneticTarget target) {
|
* Prepares the given bubble view to be dragged out, using the provided magnetic target and
|
||||||
|
* listener.
|
||||||
|
*/
|
||||||
|
public void prepareForBubbleDrag(
|
||||||
|
View bubble,
|
||||||
|
MagnetizedObject.MagneticTarget target,
|
||||||
|
MagnetizedObject.MagnetListener listener) {
|
||||||
mLayout.cancelAnimationsOnView(bubble);
|
mLayout.cancelAnimationsOnView(bubble);
|
||||||
|
|
||||||
bubble.setTranslationZ(Short.MAX_VALUE);
|
bubble.setTranslationZ(Short.MAX_VALUE);
|
||||||
@@ -277,6 +283,7 @@ public class ExpandedAnimationController
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
mMagnetizedBubbleDraggingOut.addTarget(target);
|
mMagnetizedBubbleDraggingOut.addTarget(target);
|
||||||
|
mMagnetizedBubbleDraggingOut.setMagnetListener(listener);
|
||||||
mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
|
mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
|
||||||
mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
|
mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1117,9 +1117,4 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
|||||||
mAssociatedController = controller;
|
mAssociatedController = controller;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canReceivePointerEvents() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util
|
||||||
|
|
||||||
|
import android.graphics.PointF
|
||||||
|
import android.os.Handler
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.VelocityTracker
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewConfiguration
|
||||||
|
import kotlin.math.hypot
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener which receives [onDown], [onMove], and [onUp] events, with relevant information about
|
||||||
|
* the coordinates of the touch and the view relative to the initial ACTION_DOWN event and the
|
||||||
|
* view's initial position.
|
||||||
|
*/
|
||||||
|
abstract class RelativeTouchListener : View.OnTouchListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an ACTION_DOWN event is received for the given view.
|
||||||
|
*
|
||||||
|
* @return False if the object is not interested in MotionEvents at this time, or true if we
|
||||||
|
* should consume this event and subsequent events, and begin calling [onMove].
|
||||||
|
*/
|
||||||
|
abstract fun onDown(v: View, ev: MotionEvent): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an ACTION_MOVE event is received for the given view. This signals that the view
|
||||||
|
* is being dragged.
|
||||||
|
*
|
||||||
|
* @param viewInitialX The view's translationX value when this touch gesture started.
|
||||||
|
* @param viewInitialY The view's translationY value when this touch gesture started.
|
||||||
|
* @param dx Horizontal distance covered since the initial ACTION_DOWN event, in pixels.
|
||||||
|
* @param dy Vertical distance covered since the initial ACTION_DOWN event, in pixels.
|
||||||
|
*/
|
||||||
|
abstract fun onMove(
|
||||||
|
v: View,
|
||||||
|
ev: MotionEvent,
|
||||||
|
viewInitialX: Float,
|
||||||
|
viewInitialY: Float,
|
||||||
|
dx: Float,
|
||||||
|
dy: Float
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an ACTION_UP event is received for the given view. This signals that a drag or
|
||||||
|
* fling gesture has completed.
|
||||||
|
*
|
||||||
|
* @param viewInitialX The view's translationX value when this touch gesture started.
|
||||||
|
* @param viewInitialY The view's translationY value when this touch gesture started.
|
||||||
|
* @param dx Horizontal distance covered, in pixels.
|
||||||
|
* @param dy Vertical distance covered, in pixels.
|
||||||
|
* @param velX The final horizontal velocity of the gesture, in pixels/second.
|
||||||
|
* @param velY The final vertical velocity of the gesture, in pixels/second.
|
||||||
|
*/
|
||||||
|
abstract fun onUp(
|
||||||
|
v: View,
|
||||||
|
ev: MotionEvent,
|
||||||
|
viewInitialX: Float,
|
||||||
|
viewInitialY: Float,
|
||||||
|
dx: Float,
|
||||||
|
dy: Float,
|
||||||
|
velX: Float,
|
||||||
|
velY: Float
|
||||||
|
)
|
||||||
|
|
||||||
|
/** The raw coordinates of the last ACTION_DOWN event. */
|
||||||
|
private val touchDown = PointF()
|
||||||
|
|
||||||
|
/** The coordinates of the view, at the time of the last ACTION_DOWN event. */
|
||||||
|
private val viewPositionOnTouchDown = PointF()
|
||||||
|
|
||||||
|
private val velocityTracker = VelocityTracker.obtain()
|
||||||
|
|
||||||
|
private var touchSlop: Int = -1
|
||||||
|
private var movedEnough = false
|
||||||
|
|
||||||
|
private val handler = Handler()
|
||||||
|
private var performedLongClick = false
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun onTouch(v: View, ev: MotionEvent): Boolean {
|
||||||
|
addMovement(ev)
|
||||||
|
|
||||||
|
val dx = ev.rawX - touchDown.x
|
||||||
|
val dy = ev.rawY - touchDown.y
|
||||||
|
|
||||||
|
when (ev.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
if (!onDown(v, ev)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the touch slop, it might have changed if the config changed since the
|
||||||
|
// last gesture.
|
||||||
|
touchSlop = ViewConfiguration.get(v.context).scaledTouchSlop
|
||||||
|
|
||||||
|
touchDown.set(ev.rawX, ev.rawY)
|
||||||
|
viewPositionOnTouchDown.set(v.translationX, v.translationY)
|
||||||
|
|
||||||
|
performedLongClick = false
|
||||||
|
handler.postDelayed({
|
||||||
|
performedLongClick = v.performLongClick()
|
||||||
|
}, ViewConfiguration.getLongPressTimeout().toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
if (!movedEnough && hypot(dx, dy) > touchSlop && !performedLongClick) {
|
||||||
|
movedEnough = true
|
||||||
|
handler.removeCallbacksAndMessages(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movedEnough) {
|
||||||
|
onMove(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
if (movedEnough) {
|
||||||
|
velocityTracker.computeCurrentVelocity(1000 /* units */)
|
||||||
|
onUp(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy,
|
||||||
|
velocityTracker.xVelocity, velocityTracker.yVelocity)
|
||||||
|
} else if (!performedLongClick) {
|
||||||
|
v.performClick()
|
||||||
|
} else {
|
||||||
|
handler.removeCallbacksAndMessages(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
velocityTracker.clear()
|
||||||
|
movedEnough = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a movement to the velocity tracker using raw screen coordinates.
|
||||||
|
*/
|
||||||
|
private fun addMovement(event: MotionEvent) {
|
||||||
|
val deltaX = event.rawX - event.x
|
||||||
|
val deltaY = event.rawY - event.y
|
||||||
|
event.offsetLocation(deltaX, deltaY)
|
||||||
|
velocityTracker.addMovement(event)
|
||||||
|
event.offsetLocation(-deltaX, -deltaY)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -374,7 +374,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
|
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
|
||||||
assertTrue(mBubbleController.hasBubbles());
|
assertTrue(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
|
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
|
||||||
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
|
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
|
||||||
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
@@ -399,7 +399,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand the stack
|
// Expand the stack
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
|
assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
|
||||||
@@ -436,7 +436,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||||
|
|
||||||
@@ -448,7 +448,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
mRow2.getEntry()));
|
mRow2.getEntry()));
|
||||||
|
|
||||||
// Switch which bubble is expanded
|
// Switch which bubble is expanded
|
||||||
mBubbleController.selectBubble(mRow.getEntry().getKey());
|
mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
mBubbleData.setExpanded(true);
|
mBubbleData.setExpanded(true);
|
||||||
assertEquals(mRow.getEntry(),
|
assertEquals(mRow.getEntry(),
|
||||||
mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
|
mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
|
||||||
@@ -482,7 +482,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
|
|
||||||
@@ -544,7 +544,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
|
|
||||||
assertTrue(mSysUiStateBubblesExpanded);
|
assertTrue(mSysUiStateBubblesExpanded);
|
||||||
|
|
||||||
@@ -726,7 +726,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.updateBubble(mRow2.getEntry());
|
mBubbleController.updateBubble(mRow2.getEntry());
|
||||||
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mDeleteIntent, times(2)).send();
|
verify(mDeleteIntent, times(2)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
|
assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
|
||||||
assertTrue(mBubbleController.hasBubbles());
|
assertTrue(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
|
assertFalse(mNotificationShadeWindowController.getBubblesShowing());
|
||||||
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
|
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
|
||||||
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
@@ -344,7 +344,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand the stack
|
// Expand the stack
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
|
assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
|
||||||
@@ -376,7 +376,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
|
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry()));
|
||||||
|
|
||||||
// Switch which bubble is expanded
|
// Switch which bubble is expanded
|
||||||
mBubbleController.selectBubble(mRow.getEntry().getKey());
|
mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
mBubbleData.setExpanded(true);
|
mBubbleData.setExpanded(true);
|
||||||
assertEquals(mRow.getEntry(),
|
assertEquals(mRow.getEntry(),
|
||||||
mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
|
mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
|
||||||
@@ -416,7 +416,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
|
|
||||||
@@ -442,7 +442,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot());
|
||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||||
|
|
||||||
@@ -474,7 +474,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Expand
|
// Expand
|
||||||
BubbleStackView stackView = mBubbleController.getStackView();
|
BubbleStackView stackView = mBubbleController.getStackView();
|
||||||
mBubbleController.expandStack();
|
mBubbleData.setExpanded(true);
|
||||||
|
|
||||||
assertTrue(mBubbleController.isStackExpanded());
|
assertTrue(mBubbleController.isStackExpanded());
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||||
@@ -628,7 +628,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.updateBubble(mRow2.getEntry());
|
mBubbleController.updateBubble(mRow2.getEntry());
|
||||||
mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mDeleteIntent, times(2)).send();
|
verify(mDeleteIntent, times(2)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user