Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd4c9d15 authored by Ats Jenk's avatar Ats Jenk
Browse files

Add content description to bubble bar and bubbles

Set content description on the bubble bar when it is collapsed. Only
allow focus on the bar itself. In collapsed mode, bubbles in the bar
can't be focused.
Content description for the bar matches what we have in floating mode.
We include the text for the first bubble and then how many bubbles are
there more.

Set content description on bubbles in bubble bar. When bubble bar is
expanded, only the bubbles are focusable.
Bubble content description matches the floating bubbles content
description. Includes the notification title and app name.

Bug: 344670947
Flag: com.android.wm.shell.enable_bubble_bar
Test: enable talkback, focus on bubble bar when it is collapsed, check
  that only bubble bar receives focus
Test: enable talkback and expand bubble bar, check that only the bubbles
  receive focus
Change-Id: Id931f0360b9ebadd01dd16b05b75546fcc4df803
parent 1507a2c5
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -623,6 +623,8 @@ public class BubbleBarView extends FrameLayout {
        }
        super.addView(child, index, params);
        updateWidth();
        updateBubbleAccessibilityStates();
        updateContentDescription();
    }

    // TODO: (b/283309949) animate it
@@ -634,6 +636,8 @@ public class BubbleBarView extends FrameLayout {
            mBubbleBarBackground.showArrow(false);
        }
        updateWidth();
        updateBubbleAccessibilityStates();
        updateContentDescription();
    }

    private void updateWidth() {
@@ -799,6 +803,7 @@ public class BubbleBarView extends FrameLayout {
                }
            }
            updateChildrenRenderNodeProperties(mBubbleBarLocation);
            updateContentDescription();
        }
    }

@@ -927,6 +932,7 @@ public class BubbleBarView extends FrameLayout {
            } else {
                mWidthAnimator.reverse();
            }
            updateBubbleAccessibilityStates();
        }
    }

@@ -998,6 +1004,47 @@ public class BubbleBarView extends FrameLayout {
        return mIsAnimatingNewBubble;
    }

    private boolean hasOverview() {
        // Overview is always the last bubble
        View lastChild = getChildAt(getChildCount() - 1);
        if (lastChild instanceof BubbleView bubbleView) {
            return bubbleView.getBubble() instanceof BubbleBarOverflow;
        }
        return false;
    }

    private void updateBubbleAccessibilityStates() {
        final int childA11y;
        if (mIsBarExpanded) {
            // Bar is expanded, focus on the bubbles
            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
            childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
        } else {
            // Bar is collapsed, only focus on the bar
            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
            childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_NO;
        }
        for (int i = 0; i < getChildCount(); i++) {
            getChildAt(i).setImportantForAccessibility(childA11y);
            // Only allowing focusing on bubbles when bar is expanded. Otherwise, in talkback mode,
            // bubbles can be navigates to in collapsed mode.
            getChildAt(i).setFocusable(mIsBarExpanded);
        }
    }

    private void updateContentDescription() {
        View firstChild = getChildAt(0);
        CharSequence contentDesc = firstChild != null ? firstChild.getContentDescription() : "";

        // Don't count overflow if it exists
        int bubbleCount = getChildCount() - (hasOverview() ? 1 : 0);
        if (bubbleCount > 1) {
            contentDesc = getResources().getString(R.string.bubble_bar_description_multiple_bubbles,
                    contentDesc, bubbleCount - 1);
        }
        setContentDescription(contentDesc);
    }

    /** Interface for BubbleBarView to communicate with its controller. */
    interface Controller {

+11 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -187,6 +188,16 @@ public class BubbleView extends ConstraintLayout {
        mAppIcon.setImageBitmap(bubble.getBadge());
        mDotColor = bubble.getDotColor();
        mDotRenderer = new DotRenderer(mBubbleSize, bubble.getDotPath(), DEFAULT_PATH_SIZE);
        String contentDesc = bubble.getInfo().getTitle();
        if (TextUtils.isEmpty(contentDesc)) {
            contentDesc = getResources().getString(R.string.bubble_bar_bubble_fallback_description);
        }
        String appName = bubble.getInfo().getAppName();
        if (!TextUtils.isEmpty(appName)) {
            contentDesc = getResources().getString(R.string.bubble_bar_bubble_description,
                    contentDesc, appName);
        }
        setContentDescription(contentDesc);
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -392,7 +392,8 @@ class BubbleBarViewAnimatorTest {
            overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
            bubbleBarView.addView(overflowView)

            val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false)
            val bubbleInfo =
                BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
            bubbleView =
                inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
            bubble =
+6 −0
Original line number Diff line number Diff line
@@ -500,6 +500,12 @@
    <string name="ps_add_button_content_description">Install apps to Private Space</string>

    <!-- Strings for bubble bar -->
    <!-- Fallback name for a bubble if it does have a title [CHAR_LIMIT=none] -->
    <string name="bubble_bar_bubble_fallback_description">Bubble</string>
    <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
    <string name="bubble_bar_overflow_description">Overflow</string>
    <!-- Content description for a bubble bar bubble. [CHAR_LIMIT=none] -->
    <string name="bubble_bar_bubble_description"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
    <!-- Content description for bubble bar when it has multiple bubbles. [CHAR_LIMIT=NONE] -->
    <string name="bubble_bar_description_multiple_bubbles"><xliff:g id="bubble_bar_bubble_description" example="some title from YouTube">%1$s</xliff:g> and <xliff:g id="bubble_count" example="4">%2$d</xliff:g> more</string>
</resources>