a11y local actions - fling bubble stack to corners

Test: manual
Bug: 123541035

Change-Id: I6ac547fd6d3c60a4b93ecac2d6e610a416fcec18
This commit is contained in:
Lyn Han
2019-05-02 18:28:01 -07:00
parent d20d4b1d65
commit e68d091ae1
3 changed files with 83 additions and 16 deletions

View File

@@ -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" />

View File

@@ -45,6 +45,7 @@ import android.view.ViewTreeObserver;
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 @@ public class BubbleStackView extends FrameLayout {
@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 @@ public class BubbleStackView extends FrameLayout {
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;
}

View File

@@ -175,11 +175,33 @@ public class StackAnimationController extends
/** 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 @@ public class StackAnimationController extends
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;