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

Commit a46d6dce authored by Jason Hsu's avatar Jason Hsu Committed by Android (Google) Code Review
Browse files

Merge changes from topic "triple-tap" into tm-dev

* changes:
  Add link functionality in message of magnification triple-tap dialog
  Apply new flow to hint user about triple-tap will delay when user select triple-tap shortcut on window-mode.
parents 9badccfc 4bfe215e
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);
+85 −61
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,12 +25,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
@@ -45,6 +44,7 @@ import com.android.settings.DialogCreatable;
import com.android.settings.R;
import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.utils.AnnotationSpan;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnResume;
@@ -52,7 +52,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,17 +62,18 @@ 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;
    private ShortcutPreference mLinkPreference;

    @VisibleForTesting
    ListView mMagnificationModesListView;
@@ -113,7 +113,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);
        }
    }

@@ -121,8 +121,10 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mModePreference = screen.findPreference(getPreferenceKey());
        mLinkPreference = screen.findPreference(
                ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE);
        mModePreference.setOnPreferenceClickListener(preference -> {
            mMode = MagnificationCapabilities.getCapabilities(mContext);
            mModeCache = MagnificationCapabilities.getCapabilities(mContext);
            mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
            return true;
        });
@@ -130,7 +132,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl

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

    /**
@@ -147,8 +149,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 +160,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 +180,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 +221,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 +244,56 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
    }

    private Dialog createMagnificationShortCutConfirmDialog() {
        return AccessibilityDialogUtils.createMagnificationSwitchShortcutDialog(mContext,
                this::onSwitchShortcutDialogButtonClicked);
    }
    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);

    @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();
    }
        final Dialog dialog = AccessibilityDialogUtils.createCustomDialog(mContext, title,
                contentView,
                positiveBtnText, this::onMagnificationTripleTapWarningDialogPositiveButtonClicked,
                negativeBtnText, this::onMagnificationTripleTapWarningDialogNegativeButtonClicked);

    private void optOutMagnificationFromTripleTap() {
        Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
    }
        updateLinkInTripleTapWarningDialog(dialog, contentView);

    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 dialog;
    }

        final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
    private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) {
        final TextView messageView = contentView.findViewById(R.id.message);
        // TODO(b/225682559): Need to remove performClick() after refactoring accessibility dialog.
        final View.OnClickListener linkListener = view -> {
            mLinkPreference.performClick();
            dialog.dismiss();
        };
        final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
                AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener);
        final CharSequence textWithLink = AnnotationSpan.linkify(mContext.getText(
                R.string.accessibility_magnification_triple_tap_warning_message), linkInfo);

        if (!TextUtils.isEmpty(targetString)) {
            joiner.add(targetString);
        if (messageView != null) {
            messageView.setText(textWithLink);
            messageView.setMovementMethod(LinkMovementMethod.getInstance());
        }
        dialog.setContentView(contentView);
    }
        joiner.add(MAGNIFICATION_CONTROLLER_NAME);

        Settings.Secure.putString(mContext.getContentResolver(), targetKey,
                joiner.toString());
    @VisibleForTesting
    void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
            DialogInterface dialogInterface, int which) {
        mModeCache = MagnificationCapabilities.getCapabilities(mContext);
        mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
    }

    @VisibleForTesting
    void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
            DialogInterface dialogInterface, int which) {
        updateCapabilitiesAndSummary(mModeCache);
    }

    // TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only.
@@ -277,7 +302,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.
     */
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ public class ShortcutPreference extends Preference {
        setLayoutResource(R.layout.accessibility_shortcut_secondary_action);
        setWidgetLayoutResource(R.layout.preference_widget_primary_switch);
        setIconSpaceReserved(false);
        // Treat onSettingsClicked as this preference's click.
        setOnPreferenceClickListener(preference -> {
            callOnSettingsClicked();
            return true;
        });
    }

    @Override
+1 −1
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
    protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service";
    public static final String KEY_GENERAL_CATEGORY = "general_categories";
    protected static final String KEY_HTML_DESCRIPTION_PREFERENCE = "html_description";
    private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
    public static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
    protected static final String KEY_SAVED_USER_SHORTCUT_TYPE = "shortcut_type";
    protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
    protected static final String KEY_SAVED_QS_TOOLTIP_TYPE = "qs_tooltip_type";
Loading