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

Commit 238639c4 authored by menghanli's avatar menghanli
Browse files

Allow users dismiss accessibility quick settings tooltips when clicked

Problem: When Talkback on, users cannot use double tap or swipe to move focus on the next window.
Solution: Talkback speaks out "double tap to dismiss" to allow dismissing this tooltips.

Bug: 215656141
Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityQuickSettingsTooltipWindowTest
Change-Id: I8f7066a805ec963f9f0f8fee1b81ad008418c4a6
parent a67bb943
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5481,6 +5481,8 @@
    <string name="accessibility_service_primary_open_title">Open <xliff:g id="accessibility_app_name" example="TalkBack">%1$s</xliff:g></string>
    <!-- Used in the accessibility service settings to show quick settings tooltips. [CHAR LIMIT=NONE] -->
    <string name="accessibility_service_quick_settings_tooltips_content">Swipe down to quickly turn <xliff:g id="accessibility_app_name" example="TalkBack">%1$s</xliff:g> on or off in quick settings</string>
    <!-- Used in the accessibility action for accessibility quick settings tooltips to dismiss. [CHAR LIMIT=NONE] -->
    <string name="accessibility_quick_settings_tooltips_dismiss">Dismiss</string>
    <!-- Used in the Color correction settings screen to control turning on/off the feature entirely [CHAR LIMIT=60] -->
    <string name="accessibility_daltonizer_primary_switch_title">Use color correction</string>
    <!-- Title for accessibility shortcut preference for color correction. [CHAR LIMIT=60] -->
+27 −1
Original line number Diff line number Diff line
@@ -19,10 +19,14 @@ package com.android.settings.accessibility;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
@@ -49,6 +53,25 @@ public class AccessibilityQuickSettingsTooltipWindow extends PopupWindow {
        this.mContext = context;
    }

    private final AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
            @Override
            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
                super.onInitializeAccessibilityNodeInfo(host, info);
                final AccessibilityAction clickAction = new AccessibilityAction(
                        AccessibilityNodeInfo.ACTION_CLICK,
                        mContext.getString(R.string.accessibility_quick_settings_tooltips_dismiss));
                info.addAction(clickAction);
            }

            @Override
            public boolean performAccessibilityAction(View host, int action, Bundle args) {
                if (action == AccessibilityNodeInfo.ACTION_CLICK) {
                    dismiss();
                    return true;
                }
                return super.performAccessibilityAction(host, action, args);
            }
        };
    /**
     * Sets up {@link #AccessibilityQuickSettingsTooltipWindow}'s layout and content.
     *
@@ -74,13 +97,16 @@ public class AccessibilityQuickSettingsTooltipWindow extends PopupWindow {
        final LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
        final View popupView =
                inflater.inflate(R.layout.accessibility_qs_tooltips, /* root= */ null);
        popupView.setFocusable(/* focusable= */ true);
        popupView.setAccessibilityDelegate(mAccessibilityDelegate);
        setContentView(popupView);

        final TextView textView = getContentView().findViewById(R.id.qs_content);
        textView.setText(text);

        setWidth(getWindowWidthWith(textView));
        setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
        setFocusable(/* focusable= */ true);
        setOutsideTouchable(/* touchable= */ true);
    }

    /**
+36 −19
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.verify;

import android.content.Context;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.PopupWindow;

import androidx.test.core.app.ApplicationProvider;
@@ -53,52 +54,68 @@ public class AccessibilityQuickSettingsTooltipWindowTest {

    private static final String TEST_PACKAGE_NAME = "com.test.package";
    private final Context mContext = ApplicationProvider.getApplicationContext();
    private AccessibilityQuickSettingsTooltipWindow mToolTipView;
    private AccessibilityQuickSettingsTooltipWindow mTooltipView;
    private View mView;

    @Before
    public void setUp() {
        mToolTipView = new AccessibilityQuickSettingsTooltipWindow(mContext);
        mTooltipView = new AccessibilityQuickSettingsTooltipWindow(mContext);
        mView = new View(RuntimeEnvironment.application);
    }

    @Test
    public void initToolTipView_atMostAvailableTextWidth() {
    public void initTooltipView_atMostAvailableTextWidth() {
        final String quickSettingsTooltipsContent = mContext.getString(
                R.string.accessibility_service_quick_settings_tooltips_content, TEST_PACKAGE_NAME);
        mToolTipView.setup(quickSettingsTooltipsContent);
        mTooltipView.setup(quickSettingsTooltipsContent);

        final int getMaxWidth = mToolTipView.getAvailableWindowWidth();
        assertThat(mToolTipView.getWidth()).isAtMost(getMaxWidth);
        final int getMaxWidth = mTooltipView.getAvailableWindowWidth();
        assertThat(mTooltipView.getWidth()).isAtMost(getMaxWidth);
    }

    @Test
    public void showToolTipView_success() {
        mToolTipView.setup(TEST_PACKAGE_NAME);
    public void showTooltipView_success() {
        mTooltipView.setup(TEST_PACKAGE_NAME);
        assertThat(getLatestPopupWindow()).isNull();

        mToolTipView.showAtTopCenter(mView);
        mTooltipView.showAtTopCenter(mView);

        assertThat(getLatestPopupWindow()).isSameInstanceAs(mToolTipView);
        assertThat(getLatestPopupWindow()).isSameInstanceAs(mTooltipView);
    }

    @Test
    public void dismiss_toolTipViewShown_shouldInvokeCallbackAndNotShowing() {
        mToolTipView.setup(TEST_PACKAGE_NAME);
        mToolTipView.setOnDismissListener(mMockOnDismissListener);
        mToolTipView.showAtTopCenter(mView);
    public void accessibilityClickActionOnTooltipViewShown_shouldInvokeCallbackAndNotShowing() {
        mTooltipView.setup(TEST_PACKAGE_NAME);
        mTooltipView.setOnDismissListener(mMockOnDismissListener);
        mTooltipView.showAtTopCenter(mView);

        mToolTipView.dismiss();
        final boolean isActionPerformed =
                mTooltipView.getContentView().performAccessibilityAction(
                        AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.getId(),
                        /* arguments= */ null);

        assertThat(isActionPerformed).isTrue();
        verify(mMockOnDismissListener).onDismiss();
        assertThat(getLatestPopupWindow().isShowing()).isFalse();
    }

    @Test
    public void waitAutoCloseDelayTime_toolTipViewShown_shouldInvokeCallbackAndNotShowing() {
        mToolTipView.setup(TEST_PACKAGE_NAME, /* closeDelayTimeMillis= */ 1);
        mToolTipView.setOnDismissListener(mMockOnDismissListener);
        mToolTipView.showAtTopCenter(mView);
    public void dismiss_tooltipViewShown_shouldInvokeCallbackAndNotShowing() {
        mTooltipView.setup(TEST_PACKAGE_NAME);
        mTooltipView.setOnDismissListener(mMockOnDismissListener);
        mTooltipView.showAtTopCenter(mView);

        mTooltipView.dismiss();

        verify(mMockOnDismissListener).onDismiss();
        assertThat(getLatestPopupWindow().isShowing()).isFalse();
    }

    @Test
    public void waitAutoCloseDelayTime_tooltipViewShown_shouldInvokeCallbackAndNotShowing() {
        mTooltipView.setup(TEST_PACKAGE_NAME, /* closeDelayTimeMillis= */ 1);
        mTooltipView.setOnDismissListener(mMockOnDismissListener);
        mTooltipView.showAtTopCenter(mView);

        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();