Merge "a11y local actions - fling bubble stack to corners" into qt-dev
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f75f255..e97055f0 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -103,6 +103,12 @@
<item type="id" name="action_snooze_assistant_suggestion_1"/>
<item type="id" name="action_snooze"/>
+ <!-- Accessibility actions for bubbles. -->
+ <item type="id" name="action_move_top_left"/>
+ <item type="id" name="action_move_top_right"/>
+ <item type="id" name="action_move_bottom_left"/>
+ <item type="id" name="action_move_bottom_right"/>
+
<!-- For StatusIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" />
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index d1bc9a9..123d73d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -45,6 +45,7 @@
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -391,11 +392,34 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
+
+ // Custom actions.
+ AccessibilityAction moveTopLeft = new AccessibilityAction(R.id.action_move_top_left,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_top_left));
+ info.addAction(moveTopLeft);
+
+ AccessibilityAction moveTopRight = new AccessibilityAction(R.id.action_move_top_right,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_top_right));
+ info.addAction(moveTopRight);
+
+ AccessibilityAction moveBottomLeft = new AccessibilityAction(R.id.action_move_bottom_left,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_bottom_left));
+ info.addAction(moveBottomLeft);
+
+ AccessibilityAction moveBottomRight = new AccessibilityAction(R.id.action_move_bottom_right,
+ getContext().getResources()
+ .getString(R.string.bubble_accessibility_action_move_bottom_right));
+ info.addAction(moveBottomRight);
+
+ // Default actions.
+ info.addAction(AccessibilityAction.ACTION_DISMISS);
if (mIsExpanded) {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ info.addAction(AccessibilityAction.ACTION_COLLAPSE);
} else {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ info.addAction(AccessibilityAction.ACTION_EXPAND);
}
}
@@ -404,16 +428,30 @@
if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
}
- switch (action) {
- case AccessibilityNodeInfo.ACTION_DISMISS:
- mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
- return true;
- case AccessibilityNodeInfo.ACTION_COLLAPSE:
- mBubbleData.setExpanded(false);
- return true;
- case AccessibilityNodeInfo.ACTION_EXPAND:
- mBubbleData.setExpanded(true);
- return true;
+ final RectF stackBounds = mStackAnimationController.getAllowableStackPositionRegion();
+
+ // R constants are not final so we cannot use switch-case here.
+ if (action == AccessibilityNodeInfo.ACTION_DISMISS) {
+ mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
+ return true;
+ } else if (action == AccessibilityNodeInfo.ACTION_COLLAPSE) {
+ mBubbleData.setExpanded(false);
+ return true;
+ } else if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
+ mBubbleData.setExpanded(true);
+ return true;
+ } else if (action == R.id.action_move_top_left) {
+ mStackAnimationController.springStack(stackBounds.left, stackBounds.top);
+ return true;
+ } else if (action == R.id.action_move_top_right) {
+ mStackAnimationController.springStack(stackBounds.right, stackBounds.top);
+ return true;
+ } else if (action == R.id.action_move_bottom_left) {
+ mStackAnimationController.springStack(stackBounds.left, stackBounds.bottom);
+ return true;
+ } else if (action == R.id.action_move_bottom_right) {
+ mStackAnimationController.springStack(stackBounds.right, stackBounds.bottom);
+ return true;
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 47f2cd4..bc249ae 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -175,11 +175,33 @@
/** Whether the stack is on the left side of the screen. */
public boolean isStackOnLeftSide() {
- if (mLayout != null) {
- return mStackPosition.x - mIndividualBubbleSize / 2 < mLayout.getWidth() / 2;
- } else {
+ if (mLayout == null) {
return false;
}
+ float stackCenter = mStackPosition.x + mIndividualBubbleSize / 2;
+ float screenCenter = mLayout.getWidth() / 2;
+ return stackCenter < screenCenter;
+ }
+
+ /**
+ * Fling stack to given corner, within allowable screen bounds.
+ * Note that we need new SpringForce instances per animation despite identical configs because
+ * SpringAnimation uses SpringForce's internal (changing) velocity while the animation runs.
+ */
+ public void springStack(float destinationX, float destinationY) {
+ springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_X,
+ new SpringForce()
+ .setStiffness(SPRING_AFTER_FLING_STIFFNESS)
+ .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
+ 0 /* startXVelocity */,
+ destinationX);
+
+ springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_Y,
+ new SpringForce()
+ .setStiffness(SPRING_AFTER_FLING_STIFFNESS)
+ .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
+ 0 /* startYVelocity */,
+ destinationY);
}
/**
@@ -352,6 +374,7 @@
float destinationY = Float.MIN_VALUE;
if (imeVisible) {
+ // Stack is lower than it should be and overlaps the now-visible IME.
if (mStackPosition.y > maxBubbleY && mPreImeY == Float.MIN_VALUE) {
mPreImeY = mStackPosition.y;
destinationY = maxBubbleY;