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

Commit 3b96a2c5 authored by jasonwshsu's avatar jasonwshsu
Browse files

Apply new flow to hint user about triple-tap will delay when user select...

Apply new flow to hint user about triple-tap will delay when user select triple-tap shortcut on window-mode.

Root Cause: Original content in magnification switch shortcut dialog needs to have different versions for different accessibility software shortcuts. Use the generic content and new flow to replace it.

Solution: Apply new flow from UX suggestion.

Bug: 210593079
Test: make RunSettingsRoboTests ROBOTEST_FILTER=MagnificationModePreferenceControllerTest
Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityDialogUtilsTest
Change-Id: Id09b8847cca4fce1f3fb77770a03bff53ae05855
parent ca73aa40
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  Copyright (C) 2020 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?>
<!--
  Copyright (C) 2022 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.
@@ -13,51 +14,24 @@
  See the License for the specific language governing permissions and
  limitations under the License
  -->

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_height="wrap_content"
    android:scrollbarStyle="outsideOverlay">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="24dp">

        <ImageView
            android:id="@+id/image"
            android:layout_width="@dimen/accessibility_imageview_size"
            android:layout_height="@dimen/accessibility_imageview_size"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/accessibility_textview_layout_margin_bottom"
            android:scaleType="fitCenter"/>
        android:paddingTop="?android:attr/dialogPreferredPadding"
        android:paddingStart="?android:attr/dialogPreferredPadding"
        android:paddingEnd="?android:attr/dialogPreferredPadding">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/accessibility_magnification_switch_shortcut_message"
            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
            android:textColor="?android:attr/textColorSecondary"
            android:layout_marginBottom="@dimen/accessibility_textview_layout_margin_bottom"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            android:id="@+id/message"
            android:text="@string/accessibility_magnification_triple_tap_warning_message"
            style="@style/AccessibilityDialogDescription" />

            <Button
                android:id="@+id/custom_positive_button"
                style="@style/AccessibilityDialogButton"
                android:gravity="center|end"
                android:text="@string/accessibility_magnification_switch_shortcut_positive_button"/>

            <Button
                android:id="@+id/custom_negative_button"
                style="@style/AccessibilityDialogButton"
                android:gravity="center|end"
                android:text="@string/accessibility_magnification_switch_shortcut_negative_button"/>

        </LinearLayout>
    </LinearLayout>
</ScrollView>
 No newline at end of file
+11 −85
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -131,7 +130,6 @@ public class AccessibilityDialogUtils {
         DialogType.EDIT_SHORTCUT_GENERIC_SUW,
         DialogType.EDIT_SHORTCUT_MAGNIFICATION,
         DialogType.EDIT_SHORTCUT_MAGNIFICATION_SUW,
         DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT,
    })

    public @interface DialogType {
@@ -139,7 +137,6 @@ public class AccessibilityDialogUtils {
        int EDIT_SHORTCUT_GENERIC_SUW = 1;
        int EDIT_SHORTCUT_MAGNIFICATION = 2;
        int EDIT_SHORTCUT_MAGNIFICATION_SUW = 3;
        int EDIT_MAGNIFICATION_SWITCH_SHORTCUT = 4;
    }

    /**
@@ -159,27 +156,6 @@ public class AccessibilityDialogUtils {
        return alertDialog;
    }

    /**
     * Method to show the magnification edit shortcut dialog in Magnification.
     *
     * @param context A valid context
     * @param positiveBtnListener The positive button listener
     * @return A magnification edit shortcut dialog in Magnification
     */
    public static Dialog createMagnificationSwitchShortcutDialog(Context context,
            CustomButtonsClickListener positiveBtnListener) {
        final View contentView = createSwitchShortcutDialogContentView(context);
        final AlertDialog alertDialog = new AlertDialog.Builder(context)
                .setView(contentView)
                .setTitle(context.getString(
                        R.string.accessibility_magnification_switch_shortcut_title))
                .create();
        setCustomButtonsClickListener(alertDialog, contentView,
                positiveBtnListener, /* negativeBtnListener= */ null);
        setScrollIndicators(contentView);
        return alertDialog;
    }

    /**
     * Updates the software shortcut in edit shortcut dialog.
     *
@@ -233,56 +209,6 @@ public class AccessibilityDialogUtils {
                View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
    }


    interface CustomButtonsClickListener {
        void onClick(@CustomButton int which);
    }

    /**
     * Annotation for customized dialog button type.
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({
            CustomButton.POSITIVE,
            CustomButton.NEGATIVE,
    })

    public @interface CustomButton {
        int POSITIVE = 1;
        int NEGATIVE = 2;
    }

    private static void setCustomButtonsClickListener(Dialog dialog, View contentView,
            CustomButtonsClickListener positiveBtnListener,
            CustomButtonsClickListener negativeBtnListener) {
        final Button positiveButton = contentView.findViewById(
                R.id.custom_positive_button);
        final Button negativeButton = contentView.findViewById(
                R.id.custom_negative_button);

        if (positiveButton != null) {
            positiveButton.setOnClickListener(v -> {
                if (positiveBtnListener != null) {
                    positiveBtnListener.onClick(CustomButton.POSITIVE);
                }
                dialog.dismiss();
            });
        }

        if (negativeButton != null) {
            negativeButton.setOnClickListener(v -> {
                if (negativeBtnListener != null) {
                    negativeBtnListener.onClick(CustomButton.NEGATIVE);
                }
                dialog.dismiss();
            });
        }
    }

    private static View createSwitchShortcutDialogContentView(Context context) {
        return createEditDialogContentView(context, DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT);
    }

    /**
     * Get a content View for the edit shortcut dialog.
     *
@@ -325,12 +251,6 @@ public class AccessibilityDialogUtils {
                initMagnifyShortcut(context, contentView);
                initAdvancedWidget(contentView);
                break;
            case DialogType.EDIT_MAGNIFICATION_SWITCH_SHORTCUT:
                contentView = inflater.inflate(
                        R.layout.accessibility_edit_magnification_shortcut, null);
                final ImageView image = contentView.findViewById(R.id.image);
                image.setImageResource(retrieveSoftwareShortcutImageResId(context));
                break;
            default:
                throw new IllegalArgumentException();
        }
@@ -548,18 +468,24 @@ public class AccessibilityDialogUtils {
     * @param context A valid context
     * @param dialogTitle The title of the dialog
     * @param customView The customized view
     * @param listener This listener will be invoked when the positive button in the dialog is
     *                 clicked
     * @param positiveButtonText The text of the positive button
     * @param positiveListener This listener will be invoked when the positive button in the dialog
     *                         is clicked
     * @param negativeButtonText The text of the negative button
     * @param negativeListener This listener will be invoked when the negative button in the dialog
     *                         is clicked
     * @return the {@link Dialog} with the given view
     */
    public static Dialog createCustomDialog(Context context, CharSequence dialogTitle,
            View customView, DialogInterface.OnClickListener listener) {
            View customView, CharSequence positiveButtonText,
            DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText,
            DialogInterface.OnClickListener negativeListener) {
        final AlertDialog alertDialog = new AlertDialog.Builder(context)
                .setView(customView)
                .setTitle(dialogTitle)
                .setCancelable(true)
                .setPositiveButton(R.string.save, listener)
                .setNegativeButton(R.string.cancel, null)
                .setPositiveButton(positiveButtonText, positiveListener)
                .setNegativeButton(negativeButtonText, negativeListener)
                .create();
        if (customView instanceof ScrollView || customView instanceof AbsListView) {
            setScrollIndicators(customView);
+57 −63
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.settings.accessibility;

import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.settings.accessibility.AccessibilityDialogUtils.CustomButton;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;

@@ -27,7 +25,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -52,7 +49,6 @@ import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;

import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

/** Controller that shows the magnification area mode summary and the preference click behavior. */
public class MagnificationModePreferenceController extends BasePreferenceController implements
@@ -63,16 +59,16 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
    @VisibleForTesting
    static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1;
    @VisibleForTesting
    static final int DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = DIALOG_ID_BASE + 2;
    static final int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = DIALOG_ID_BASE + 2;
    @VisibleForTesting
    static final String EXTRA_MODE = "mode";

    private static final String TAG = "MagnificationModePreferenceController";
    private static final char COMPONENT_NAME_SEPARATOR = ':';

    private DialogHelper mDialogHelper;
    // The magnification mode in the dialog.
    private int mMode = MagnificationMode.NONE;
    @MagnificationMode
    private int mModeCache = MagnificationMode.NONE;
    private Preference mModePreference;

    @VisibleForTesting
@@ -113,7 +109,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
    @Override
    public void onCreate(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mMode = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
            mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
        }
    }

@@ -122,7 +118,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
        super.displayPreference(screen);
        mModePreference = screen.findPreference(getPreferenceKey());
        mModePreference.setOnPreferenceClickListener(preference -> {
            mMode = MagnificationCapabilities.getCapabilities(mContext);
            mModeCache = MagnificationCapabilities.getCapabilities(mContext);
            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
            return true;
        });
@@ -130,7 +126,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt(EXTRA_MODE, mMode);
        outState.putInt(EXTRA_MODE, mModeCache);
    }

    /**
@@ -147,8 +143,8 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
            case DIALOG_MAGNIFICATION_MODE:
                return createMagnificationModeDialog();

            case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
                return createMagnificationShortCutConfirmDialog();
            case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
                return createMagnificationTripleTapWarningDialog();
        }
        return null;
    }
@@ -158,8 +154,8 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
        switch (dialogId) {
            case DIALOG_MAGNIFICATION_MODE:
                return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
            case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
                return SettingsEnums.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT;
            case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
                return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
            default:
                return 0;
        }
@@ -178,29 +174,40 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
        mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true);
        final CharSequence title = mContext.getString(
                R.string.accessibility_magnification_mode_dialog_title);
        final CharSequence positiveBtnText = mContext.getString(R.string.save);
        final CharSequence negativeBtnText = mContext.getString(R.string.cancel);

        return AccessibilityDialogUtils.createCustomDialog(mContext, title,
                mMagnificationModesListView, this::onMagnificationModeDialogPositiveButtonClicked);
                mMagnificationModesListView,
                positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked,
                negativeBtnText, /* negativeListener= */ null);
    }

    private void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
    @VisibleForTesting
    void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
            int which) {
        final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
        if (selectedIndex != AdapterView.INVALID_POSITION) {
            final MagnificationModeInfo modeInfo =
                    (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
                            selectedIndex);
            setMode(modeInfo.mMagnificationMode);
        } else {
        if (selectedIndex == AdapterView.INVALID_POSITION) {
            Log.w(TAG, "invalid index");
            return;
        }

        mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
                        selectedIndex)).mMagnificationMode;

        // Do not save mode until user clicks positive button in triple tap warning dialog.
        if (isTripleTapEnabled(mContext) && mModeCache != MagnificationMode.FULLSCREEN) {
            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
        } else { // Save mode (capabilities) value, don't need to show dialog to confirm.
            updateCapabilitiesAndSummary(mModeCache);
        }
    }

    private void setMode(int mode) {
        mMode = mode;
        MagnificationCapabilities.setCapabilities(mContext, mMode);
    private void updateCapabilitiesAndSummary(@MagnificationMode int mode) {
        mModeCache = mode;
        MagnificationCapabilities.setCapabilities(mContext, mModeCache);
        mModePreference.setSummary(
                MagnificationCapabilities.getSummary(mContext, mMode));
                MagnificationCapabilities.getSummary(mContext, mModeCache));
    }

    private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
@@ -208,19 +215,16 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
        final MagnificationModeInfo modeInfo =
                (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
                        position);
        if (modeInfo.mMagnificationMode == mMode) {
        if (modeInfo.mMagnificationMode == mModeCache) {
            return;
        }
        mMode = modeInfo.mMagnificationMode;
        if (isTripleTapEnabled(mContext) && mMode != MagnificationMode.FULLSCREEN) {
            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
        }
        mModeCache = modeInfo.mMagnificationMode;
    }

    private int computeSelectionIndex() {
        final int modesSize = mModeInfos.size();
        for (int i = 0; i < modesSize; i++) {
            if (mModeInfos.get(i).mMagnificationMode == mMode) {
            if (mModeInfos.get(i).mMagnificationMode == mModeCache) {
                return i + mMagnificationModesListView.getHeaderViewsCount();
            }
        }
@@ -234,41 +238,32 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
    }

    private Dialog createMagnificationShortCutConfirmDialog() {
        return AccessibilityDialogUtils.createMagnificationSwitchShortcutDialog(mContext,
                this::onSwitchShortcutDialogButtonClicked);
    }

    @VisibleForTesting
    void onSwitchShortcutDialogButtonClicked(@CustomButton int which) {
        optOutMagnificationFromTripleTap();
        //TODO(b/147990389): Merge this function into AccessibilityUtils after the format of
        // magnification target is changed to ComponentName.
        optInMagnificationToAccessibilityButton();
    }

    private void optOutMagnificationFromTripleTap() {
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
    }
    private Dialog createMagnificationTripleTapWarningDialog() {
        final View contentView = LayoutInflater.from(mContext).inflate(
                R.layout.magnification_triple_tap_warning_dialog, /* root= */ null);
        final CharSequence title = mContext.getString(
                R.string.accessibility_magnification_triple_tap_warning_title);
        final CharSequence positiveBtnText = mContext.getString(
                R.string.accessibility_magnification_triple_tap_warning_positive_button);
        final CharSequence negativeBtnText = mContext.getString(
                R.string.accessibility_magnification_triple_tap_warning_negative_button);

    private void optInMagnificationToAccessibilityButton() {
        final String targetKey = Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
        final String targetString = Settings.Secure.getString(mContext.getContentResolver(),
                targetKey);
        if (targetString != null && targetString.contains(MAGNIFICATION_CONTROLLER_NAME)) {
            return;
        return AccessibilityDialogUtils.createCustomDialog(mContext, title, contentView,
                positiveBtnText, this::onMagnificationTripleTapWarningDialogPositiveButtonClicked,
                negativeBtnText, this::onMagnificationTripleTapWarningDialogNegativeButtonClicked);
    }

        final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));

        if (!TextUtils.isEmpty(targetString)) {
            joiner.add(targetString);
    @VisibleForTesting
    void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
            DialogInterface dialogInterface, int which) {
        mModeCache = MagnificationCapabilities.getCapabilities(mContext);
        mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
    }
        joiner.add(MAGNIFICATION_CONTROLLER_NAME);

        Settings.Secure.putString(mContext.getContentResolver(), targetKey,
                joiner.toString());
    @VisibleForTesting
    void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
            DialogInterface dialogInterface, int which) {
        updateCapabilitiesAndSummary(mModeCache);
    }

    // TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only.
@@ -277,7 +272,6 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
        updateState(mModePreference);
    }


    /**
     * An interface to help the delegate to show the dialog. It will be injected to the delegate.
     */
+11 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.accessibility;

import static com.google.common.truth.Truth.assertThat;

import android.app.Dialog;
import android.content.Context;

import androidx.appcompat.app.AlertDialog;
@@ -58,4 +59,14 @@ public class AccessibilityDialogUtilsTest {
        assertThat(AccessibilityDialogUtils.updateSoftwareShortcutInDialog(mContext,
                dialog)).isFalse();
    }

    @Test
    public void showDialog_createCustomDialog_isShowing() {
        final Dialog dialog = AccessibilityDialogUtils.createCustomDialog(mContext,
                "Title", /* customView= */ null, "positiveButton", /* positiveListener= */ null,
                "negativeButton", /* negativeListener= */ null);
        dialog.show();

        assertThat(dialog.isShowing()).isTrue();
    }
}
+63 −20

File changed.

Preview size limit exceeded, changes collapsed.

Loading