Loading src/com/android/settings/accessibility/AccessibilityDialogUtils.java +36 −13 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.DialogInterface; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ScrollView; Loading @@ -34,14 +35,15 @@ import androidx.appcompat.app.AlertDialog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Optional; /** * Utility class for creating the edit dialog. */ public class AccessibilityDialogUtils { private static final String TAG = "AccessibilityDialogUtils"; private static final String TAG = AccessibilityDialogUtils.class.getSimpleName(); /** Denotes the dialog emuns for show dialog. */ /** Denotes the dialog enums for show dialog. */ @Retention(RetentionPolicy.SOURCE) public @interface DialogEnums { /** Loading Loading @@ -89,6 +91,19 @@ public class AccessibilityDialogUtils { * OPEN: Settings > Accessibility > Display size and text > Click 'Reset settings' button. */ int DIALOG_RESET_SETTINGS = 1009; /** * OPEN: Settings > Accessibility > Magnification > Magnification type. */ int DIALOG_MAGNIFICATION_MODE = 1010; /** * Enable: Settings > Accessibility > Magnification > Magnification shortcut > Advanced > * Triple tap. * OPEN: Settings > Accessibility > Magnification > Magnification type > Magnify part of * screen / Switch between full and partial screen > Save. */ int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = 1011; } /** Loading Loading @@ -118,17 +133,26 @@ public class AccessibilityDialogUtils { * is clicked * @return the {@link Dialog} with the given view */ public static Dialog createCustomDialog(Context context, CharSequence dialogTitle, View customView, CharSequence positiveButtonText, DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText, DialogInterface.OnClickListener negativeListener) { final AlertDialog alertDialog = new AlertDialog.Builder(context) .setView(customView) @NonNull public static Dialog createCustomDialog(@NonNull Context context, @NonNull CharSequence dialogTitle, @Nullable View customView, @NonNull CharSequence positiveButtonText, @Nullable DialogInterface.OnClickListener positiveListener, @NonNull CharSequence negativeButtonText, @Nullable DialogInterface.OnClickListener negativeListener) { DialogInterface.OnClickListener doNothingListener = (DialogInterface dialogInterface, int which) -> {}; final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context) .setTitle(dialogTitle) .setCancelable(true) .setPositiveButton(positiveButtonText, positiveListener) .setNegativeButton(negativeButtonText, negativeListener) .create(); .setPositiveButton(positiveButtonText, Optional.ofNullable(positiveListener).orElse(doNothingListener)) .setNegativeButton(negativeButtonText, Optional.ofNullable(negativeListener).orElse(doNothingListener)); if (customView != null) { dialogBuilder.setView(customView); } final AlertDialog alertDialog = dialogBuilder.create(); if (customView instanceof ScrollView || customView instanceof AbsListView) { setScrollIndicators(customView); } Loading @@ -151,8 +175,7 @@ public class AccessibilityDialogUtils { list.setId(android.R.id.list); list.setDivider(/* divider= */ null); list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); final ItemInfoArrayAdapter adapter = new ItemInfoArrayAdapter(context, itemInfoList); final ListAdapter adapter = new ItemInfoArrayAdapter<>(context, itemInfoList); list.setAdapter(adapter); list.setOnItemClickListener(itemListener); return list; Loading src/com/android/settings/accessibility/DialogHelper.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.accessibility; /** * The {@code DialogHelper} interface provides methods for displaying dialogs. * It helps the dialog delegate to show the dialog, and will be injected to the dialog delegate. */ public interface DialogHelper { /** * Shows a dialog with the specified dialog ID. * * @param dialogId The ID of the dialog to display. */ void showDialog(int dialogId); } src/com/android/settings/accessibility/MagnificationModePreferenceController.java +73 −72 Original line number Diff line number Diff line Loading @@ -37,11 +37,13 @@ import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.util.Preconditions; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums; import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import com.android.settings.core.BasePreferenceController; import com.android.settings.utils.AnnotationSpan; Loading @@ -57,33 +59,37 @@ public class MagnificationModePreferenceController extends BasePreferenceControl DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState { static final String PREF_KEY = "screen_magnification_mode"; private static final int DIALOG_ID_BASE = 10; @VisibleForTesting static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1; @VisibleForTesting 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 String TAG = MagnificationModePreferenceController.class.getSimpleName(); @Nullable private DialogHelper mDialogHelper; // The magnification mode in the dialog. @MagnificationMode private int mModeCache = MagnificationMode.NONE; @Nullable private Preference mModePreference; @Nullable private ShortcutPreference mLinkPreference; @VisibleForTesting @Nullable ListView mMagnificationModesListView; private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>(); public MagnificationModePreferenceController(Context context, String preferenceKey) { public MagnificationModePreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); initModeInfos(); } public void setDialogHelper(@NonNull DialogHelper dialogHelper) { mDialogHelper = dialogHelper; } private void initModeInfos() { mModeInfos.add(new MagnificationModeInfo(mContext.getText( R.string.accessibility_magnification_mode_dialog_option_full_screen), null, Loading @@ -103,6 +109,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl return AVAILABLE; } @NonNull @Override public CharSequence getSummary() { final int capabilities = MagnificationCapabilities.getCapabilities(mContext); Loading @@ -110,99 +117,98 @@ public class MagnificationModePreferenceController extends BasePreferenceControl } @Override public void onCreate(Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) { if (savedInstanceState != null) { mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE); } } @Override public void displayPreference(PreferenceScreen screen) { public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); mModePreference = screen.findPreference(getPreferenceKey()); mLinkPreference = screen.findPreference( ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE); mModePreference.setOnPreferenceClickListener(preference -> { Preconditions.checkNotNull(mModePreference).setOnPreferenceClickListener(preference -> { mModeCache = MagnificationCapabilities.getCapabilities(mContext); mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_MODE); return true; }); } @Override public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(@NonNull Bundle outState) { outState.putInt(EXTRA_MODE, mModeCache); } /** * Sets {@link DialogHelper} used to show the dialog. */ public void setDialogHelper(DialogHelper dialogHelper) { mDialogHelper = dialogHelper; mDialogHelper.setDialogDelegate(this); } @NonNull @Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { case DIALOG_MAGNIFICATION_MODE: return createMagnificationModeDialog(); case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING: return createMagnificationTripleTapWarningDialog(); } return null; return switch (dialogId) { case DialogEnums.DIALOG_MAGNIFICATION_MODE -> createMagnificationModeDialog(); case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING -> createMagnificationTripleTapWarningDialog(); default -> throw new IllegalArgumentException( "This only handles magnification mode and triple tap warning dialog"); }; } @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { case DIALOG_MAGNIFICATION_MODE: return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY; case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING: return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING; default: return 0; return switch (dialogId) { case DialogEnums.DIALOG_MAGNIFICATION_MODE -> SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY; case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING -> SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING; default -> 0; }; } @NonNull private ListView getMagnificationModesListView() { return Preconditions.checkNotNull(mMagnificationModesListView); } @NonNull private Dialog createMagnificationModeDialog() { mMagnificationModesListView = AccessibilityDialogUtils.createSingleChoiceListView( mContext, mModeInfos, this::onMagnificationModeSelected); final View headerView = LayoutInflater.from(mContext).inflate( R.layout.accessibility_magnification_mode_header, mMagnificationModesListView, false); mMagnificationModesListView.addHeaderView(headerView, /* data= */ null, /* isSelectable= */ false); R.layout.accessibility_magnification_mode_header, getMagnificationModesListView(), /* attachToRoot= */false); getMagnificationModesListView().addHeaderView(headerView, /* data= */null, /* isSelectable= */false); mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true); getMagnificationModesListView().setItemChecked(computeSelectionIndex(), /* value= */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, positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked, getMagnificationModesListView(), positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked, negativeBtnText, /* negativeListener= */null); } @VisibleForTesting void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface, void onMagnificationModeDialogPositiveButtonClicked(@NonNull DialogInterface dialogInterface, int which) { final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition(); final int selectedIndex = getMagnificationModesListView().getCheckedItemPosition(); if (selectedIndex == AdapterView.INVALID_POSITION) { Log.w(TAG, "invalid index"); Log.w(TAG, "Selected positive button with INVALID_POSITION index"); return; } mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition( mModeCache = ((MagnificationModeInfo) getMagnificationModesListView().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); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } else { // Save mode (capabilities) value, don't need to show dialog to confirm. updateCapabilitiesAndSummary(mModeCache); } Loading @@ -211,15 +217,14 @@ public class MagnificationModePreferenceController extends BasePreferenceControl private void updateCapabilitiesAndSummary(@MagnificationMode int mode) { mModeCache = mode; MagnificationCapabilities.setCapabilities(mContext, mModeCache); mModePreference.setSummary( Preconditions.checkNotNull(mModePreference).setSummary( MagnificationCapabilities.getSummary(mContext, mModeCache)); } private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position, long id) { private void onMagnificationModeSelected(@NonNull AdapterView<?> parent, @NonNull View view, int position, long id) { final MagnificationModeInfo modeInfo = (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition( position); (MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(position); if (modeInfo.mMagnificationMode == mModeCache) { return; } Loading @@ -230,20 +235,22 @@ public class MagnificationModePreferenceController extends BasePreferenceControl final int modesSize = mModeInfos.size(); for (int i = 0; i < modesSize; i++) { if (mModeInfos.get(i).mMagnificationMode == mModeCache) { return i + mMagnificationModesListView.getHeaderViewsCount(); return i + getMagnificationModesListView().getHeaderViewsCount(); } } Log.w(TAG, "computeSelectionIndex failed"); Log.w(TAG, "Can not find matching mode in mModeInfos"); return 0; } @VisibleForTesting static boolean isTripleTapEnabled(Context context) { static boolean isTripleTapEnabled(@NonNull Context context) { return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON; } @NonNull private Dialog createMagnificationTripleTapWarningDialog() { @SuppressWarnings({"InflateParams"}) final View contentView = LayoutInflater.from(mContext).inflate( R.layout.magnification_triple_tap_warning_dialog, /* root= */ null); final CharSequence title = mContext.getString( Loading @@ -263,12 +270,13 @@ public class MagnificationModePreferenceController extends BasePreferenceControl return dialog; } private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) { private void updateLinkInTripleTapWarningDialog(@NonNull Dialog dialog, @NonNull 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 -> { updateCapabilitiesAndSummary(mModeCache); mLinkPreference.performClick(); Preconditions.checkNotNull(mLinkPreference).performClick(); dialog.dismiss(); }; final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( Loading @@ -285,25 +293,18 @@ public class MagnificationModePreferenceController extends BasePreferenceControl @VisibleForTesting void onMagnificationTripleTapWarningDialogNegativeButtonClicked( DialogInterface dialogInterface, int which) { @NonNull DialogInterface dialogInterface, int which) { mModeCache = MagnificationCapabilities.getCapabilities(mContext); mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_MODE); } @VisibleForTesting void onMagnificationTripleTapWarningDialogPositiveButtonClicked( DialogInterface dialogInterface, int which) { @NonNull DialogInterface dialogInterface, int which) { updateCapabilitiesAndSummary(mModeCache); } /** * An interface to help the delegate to show the dialog. It will be injected to the delegate. */ interface DialogHelper extends DialogCreatable { void showDialog(int dialogId); void setDialogDelegate(DialogCreatable delegate); } @VisibleForTesting static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo { @MagnificationMode Loading src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +37 −33 File changed.Preview size limit exceeded, changes collapsed. Show changes tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java +16 −19 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.settings.accessibility; import static com.android.settings.accessibility.AccessibilityUtil.State.ON; import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo; import static com.google.common.truth.Truth.assertThat; Loading @@ -37,6 +35,7 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; Loading @@ -44,6 +43,9 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums; import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo; import com.android.settings.utils.AnnotationSpan; import org.junit.Before; Loading Loading @@ -82,6 +84,8 @@ public class MagnificationModePreferenceControllerTest { mScreen.addPreference(mModePreference); MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT); mController = new MagnificationModePreferenceController(mContext, PREF_KEY); mController.setDialogHelper(mDialogHelper); mDialogHelper.setDialogDelegate(mController); showPreferenceOnTheScreen(null); } Loading @@ -107,7 +111,7 @@ public class MagnificationModePreferenceControllerTest { performItemClickWith(MagnificationMode.WINDOW); reshowPreferenceOnTheScreen(); mDialogHelper.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE); assertThat(getCheckedModeFromDialog()).isEqualTo( MagnificationMode.WINDOW); Loading @@ -123,7 +127,7 @@ public class MagnificationModePreferenceControllerTest { DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper, never()).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test Loading @@ -135,8 +139,7 @@ public class MagnificationModePreferenceControllerTest { mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(), DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test Loading @@ -148,20 +151,17 @@ public class MagnificationModePreferenceControllerTest { mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(), DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test public void onTripleTapWarningDialogNegativeButtonClicked_showModeDialog() { mDialogHelper.showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mController.onMagnificationTripleTapWarningDialogNegativeButtonClicked( mDialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE); } @Test Loading @@ -182,8 +182,7 @@ public class MagnificationModePreferenceControllerTest { @Test public void checkSpansInTripleTapWarningDialog_existAnnotationSpan() { mDialogHelper.showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); final View contentView = mDialogHelper.getDialog().findViewById(android.R.id.content); final TextView messageView = contentView.findViewById(R.id.message); final CharSequence textInTripleTapWarningDialog = messageView.getText(); Loading Loading @@ -256,13 +255,11 @@ public class MagnificationModePreferenceControllerTest { } private void showPreferenceOnTheScreen(Bundle savedInstanceState) { mController.setDialogHelper(mDialogHelper); mController.onCreate(savedInstanceState); mController.displayPreference(mScreen); } private static class TestDialogHelper implements DialogCreatable, MagnificationModePreferenceController.DialogHelper { private static class TestDialogHelper implements DialogCreatable, DialogHelper { private DialogCreatable mDialogDelegate; private Dialog mDialog; Loading @@ -271,11 +268,11 @@ public class MagnificationModePreferenceControllerTest { mDialog = onCreateDialog(dialogId); } @Override public void setDialogDelegate(DialogCreatable delegate) { public void setDialogDelegate(@NonNull DialogCreatable delegate) { mDialogDelegate = delegate; } @NonNull @Override public Dialog onCreateDialog(int dialogId) { return mDialogDelegate.onCreateDialog(dialogId); Loading Loading
src/com/android/settings/accessibility/AccessibilityDialogUtils.java +36 −13 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.DialogInterface; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ScrollView; Loading @@ -34,14 +35,15 @@ import androidx.appcompat.app.AlertDialog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Optional; /** * Utility class for creating the edit dialog. */ public class AccessibilityDialogUtils { private static final String TAG = "AccessibilityDialogUtils"; private static final String TAG = AccessibilityDialogUtils.class.getSimpleName(); /** Denotes the dialog emuns for show dialog. */ /** Denotes the dialog enums for show dialog. */ @Retention(RetentionPolicy.SOURCE) public @interface DialogEnums { /** Loading Loading @@ -89,6 +91,19 @@ public class AccessibilityDialogUtils { * OPEN: Settings > Accessibility > Display size and text > Click 'Reset settings' button. */ int DIALOG_RESET_SETTINGS = 1009; /** * OPEN: Settings > Accessibility > Magnification > Magnification type. */ int DIALOG_MAGNIFICATION_MODE = 1010; /** * Enable: Settings > Accessibility > Magnification > Magnification shortcut > Advanced > * Triple tap. * OPEN: Settings > Accessibility > Magnification > Magnification type > Magnify part of * screen / Switch between full and partial screen > Save. */ int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = 1011; } /** Loading Loading @@ -118,17 +133,26 @@ public class AccessibilityDialogUtils { * is clicked * @return the {@link Dialog} with the given view */ public static Dialog createCustomDialog(Context context, CharSequence dialogTitle, View customView, CharSequence positiveButtonText, DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText, DialogInterface.OnClickListener negativeListener) { final AlertDialog alertDialog = new AlertDialog.Builder(context) .setView(customView) @NonNull public static Dialog createCustomDialog(@NonNull Context context, @NonNull CharSequence dialogTitle, @Nullable View customView, @NonNull CharSequence positiveButtonText, @Nullable DialogInterface.OnClickListener positiveListener, @NonNull CharSequence negativeButtonText, @Nullable DialogInterface.OnClickListener negativeListener) { DialogInterface.OnClickListener doNothingListener = (DialogInterface dialogInterface, int which) -> {}; final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context) .setTitle(dialogTitle) .setCancelable(true) .setPositiveButton(positiveButtonText, positiveListener) .setNegativeButton(negativeButtonText, negativeListener) .create(); .setPositiveButton(positiveButtonText, Optional.ofNullable(positiveListener).orElse(doNothingListener)) .setNegativeButton(negativeButtonText, Optional.ofNullable(negativeListener).orElse(doNothingListener)); if (customView != null) { dialogBuilder.setView(customView); } final AlertDialog alertDialog = dialogBuilder.create(); if (customView instanceof ScrollView || customView instanceof AbsListView) { setScrollIndicators(customView); } Loading @@ -151,8 +175,7 @@ public class AccessibilityDialogUtils { list.setId(android.R.id.list); list.setDivider(/* divider= */ null); list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); final ItemInfoArrayAdapter adapter = new ItemInfoArrayAdapter(context, itemInfoList); final ListAdapter adapter = new ItemInfoArrayAdapter<>(context, itemInfoList); list.setAdapter(adapter); list.setOnItemClickListener(itemListener); return list; Loading
src/com/android/settings/accessibility/DialogHelper.java 0 → 100644 +30 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.accessibility; /** * The {@code DialogHelper} interface provides methods for displaying dialogs. * It helps the dialog delegate to show the dialog, and will be injected to the dialog delegate. */ public interface DialogHelper { /** * Shows a dialog with the specified dialog ID. * * @param dialogId The ID of the dialog to display. */ void showDialog(int dialogId); }
src/com/android/settings/accessibility/MagnificationModePreferenceController.java +73 −72 Original line number Diff line number Diff line Loading @@ -37,11 +37,13 @@ import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.util.Preconditions; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums; import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import com.android.settings.core.BasePreferenceController; import com.android.settings.utils.AnnotationSpan; Loading @@ -57,33 +59,37 @@ public class MagnificationModePreferenceController extends BasePreferenceControl DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState { static final String PREF_KEY = "screen_magnification_mode"; private static final int DIALOG_ID_BASE = 10; @VisibleForTesting static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1; @VisibleForTesting 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 String TAG = MagnificationModePreferenceController.class.getSimpleName(); @Nullable private DialogHelper mDialogHelper; // The magnification mode in the dialog. @MagnificationMode private int mModeCache = MagnificationMode.NONE; @Nullable private Preference mModePreference; @Nullable private ShortcutPreference mLinkPreference; @VisibleForTesting @Nullable ListView mMagnificationModesListView; private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>(); public MagnificationModePreferenceController(Context context, String preferenceKey) { public MagnificationModePreferenceController(@NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); initModeInfos(); } public void setDialogHelper(@NonNull DialogHelper dialogHelper) { mDialogHelper = dialogHelper; } private void initModeInfos() { mModeInfos.add(new MagnificationModeInfo(mContext.getText( R.string.accessibility_magnification_mode_dialog_option_full_screen), null, Loading @@ -103,6 +109,7 @@ public class MagnificationModePreferenceController extends BasePreferenceControl return AVAILABLE; } @NonNull @Override public CharSequence getSummary() { final int capabilities = MagnificationCapabilities.getCapabilities(mContext); Loading @@ -110,99 +117,98 @@ public class MagnificationModePreferenceController extends BasePreferenceControl } @Override public void onCreate(Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) { if (savedInstanceState != null) { mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE); } } @Override public void displayPreference(PreferenceScreen screen) { public void displayPreference(@NonNull PreferenceScreen screen) { super.displayPreference(screen); mModePreference = screen.findPreference(getPreferenceKey()); mLinkPreference = screen.findPreference( ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE); mModePreference.setOnPreferenceClickListener(preference -> { Preconditions.checkNotNull(mModePreference).setOnPreferenceClickListener(preference -> { mModeCache = MagnificationCapabilities.getCapabilities(mContext); mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_MODE); return true; }); } @Override public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(@NonNull Bundle outState) { outState.putInt(EXTRA_MODE, mModeCache); } /** * Sets {@link DialogHelper} used to show the dialog. */ public void setDialogHelper(DialogHelper dialogHelper) { mDialogHelper = dialogHelper; mDialogHelper.setDialogDelegate(this); } @NonNull @Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { case DIALOG_MAGNIFICATION_MODE: return createMagnificationModeDialog(); case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING: return createMagnificationTripleTapWarningDialog(); } return null; return switch (dialogId) { case DialogEnums.DIALOG_MAGNIFICATION_MODE -> createMagnificationModeDialog(); case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING -> createMagnificationTripleTapWarningDialog(); default -> throw new IllegalArgumentException( "This only handles magnification mode and triple tap warning dialog"); }; } @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { case DIALOG_MAGNIFICATION_MODE: return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY; case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING: return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING; default: return 0; return switch (dialogId) { case DialogEnums.DIALOG_MAGNIFICATION_MODE -> SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY; case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING -> SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING; default -> 0; }; } @NonNull private ListView getMagnificationModesListView() { return Preconditions.checkNotNull(mMagnificationModesListView); } @NonNull private Dialog createMagnificationModeDialog() { mMagnificationModesListView = AccessibilityDialogUtils.createSingleChoiceListView( mContext, mModeInfos, this::onMagnificationModeSelected); final View headerView = LayoutInflater.from(mContext).inflate( R.layout.accessibility_magnification_mode_header, mMagnificationModesListView, false); mMagnificationModesListView.addHeaderView(headerView, /* data= */ null, /* isSelectable= */ false); R.layout.accessibility_magnification_mode_header, getMagnificationModesListView(), /* attachToRoot= */false); getMagnificationModesListView().addHeaderView(headerView, /* data= */null, /* isSelectable= */false); mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true); getMagnificationModesListView().setItemChecked(computeSelectionIndex(), /* value= */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, positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked, getMagnificationModesListView(), positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked, negativeBtnText, /* negativeListener= */null); } @VisibleForTesting void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface, void onMagnificationModeDialogPositiveButtonClicked(@NonNull DialogInterface dialogInterface, int which) { final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition(); final int selectedIndex = getMagnificationModesListView().getCheckedItemPosition(); if (selectedIndex == AdapterView.INVALID_POSITION) { Log.w(TAG, "invalid index"); Log.w(TAG, "Selected positive button with INVALID_POSITION index"); return; } mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition( mModeCache = ((MagnificationModeInfo) getMagnificationModesListView().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); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } else { // Save mode (capabilities) value, don't need to show dialog to confirm. updateCapabilitiesAndSummary(mModeCache); } Loading @@ -211,15 +217,14 @@ public class MagnificationModePreferenceController extends BasePreferenceControl private void updateCapabilitiesAndSummary(@MagnificationMode int mode) { mModeCache = mode; MagnificationCapabilities.setCapabilities(mContext, mModeCache); mModePreference.setSummary( Preconditions.checkNotNull(mModePreference).setSummary( MagnificationCapabilities.getSummary(mContext, mModeCache)); } private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position, long id) { private void onMagnificationModeSelected(@NonNull AdapterView<?> parent, @NonNull View view, int position, long id) { final MagnificationModeInfo modeInfo = (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition( position); (MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(position); if (modeInfo.mMagnificationMode == mModeCache) { return; } Loading @@ -230,20 +235,22 @@ public class MagnificationModePreferenceController extends BasePreferenceControl final int modesSize = mModeInfos.size(); for (int i = 0; i < modesSize; i++) { if (mModeInfos.get(i).mMagnificationMode == mModeCache) { return i + mMagnificationModesListView.getHeaderViewsCount(); return i + getMagnificationModesListView().getHeaderViewsCount(); } } Log.w(TAG, "computeSelectionIndex failed"); Log.w(TAG, "Can not find matching mode in mModeInfos"); return 0; } @VisibleForTesting static boolean isTripleTapEnabled(Context context) { static boolean isTripleTapEnabled(@NonNull Context context) { return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON; } @NonNull private Dialog createMagnificationTripleTapWarningDialog() { @SuppressWarnings({"InflateParams"}) final View contentView = LayoutInflater.from(mContext).inflate( R.layout.magnification_triple_tap_warning_dialog, /* root= */ null); final CharSequence title = mContext.getString( Loading @@ -263,12 +270,13 @@ public class MagnificationModePreferenceController extends BasePreferenceControl return dialog; } private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) { private void updateLinkInTripleTapWarningDialog(@NonNull Dialog dialog, @NonNull 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 -> { updateCapabilitiesAndSummary(mModeCache); mLinkPreference.performClick(); Preconditions.checkNotNull(mLinkPreference).performClick(); dialog.dismiss(); }; final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( Loading @@ -285,25 +293,18 @@ public class MagnificationModePreferenceController extends BasePreferenceControl @VisibleForTesting void onMagnificationTripleTapWarningDialogNegativeButtonClicked( DialogInterface dialogInterface, int which) { @NonNull DialogInterface dialogInterface, int which) { mModeCache = MagnificationCapabilities.getCapabilities(mContext); mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE); Preconditions.checkNotNull(mDialogHelper).showDialog( DialogEnums.DIALOG_MAGNIFICATION_MODE); } @VisibleForTesting void onMagnificationTripleTapWarningDialogPositiveButtonClicked( DialogInterface dialogInterface, int which) { @NonNull DialogInterface dialogInterface, int which) { updateCapabilitiesAndSummary(mModeCache); } /** * An interface to help the delegate to show the dialog. It will be injected to the delegate. */ interface DialogHelper extends DialogCreatable { void showDialog(int dialogId); void setDialogDelegate(DialogCreatable delegate); } @VisibleForTesting static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo { @MagnificationMode Loading
src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +37 −33 File changed.Preview size limit exceeded, changes collapsed. Show changes
tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java +16 −19 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.settings.accessibility; import static com.android.settings.accessibility.AccessibilityUtil.State.ON; import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo; import static com.google.common.truth.Truth.assertThat; Loading @@ -37,6 +35,7 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; Loading @@ -44,6 +43,9 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums; import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; import com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo; import com.android.settings.utils.AnnotationSpan; import org.junit.Before; Loading Loading @@ -82,6 +84,8 @@ public class MagnificationModePreferenceControllerTest { mScreen.addPreference(mModePreference); MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT); mController = new MagnificationModePreferenceController(mContext, PREF_KEY); mController.setDialogHelper(mDialogHelper); mDialogHelper.setDialogDelegate(mController); showPreferenceOnTheScreen(null); } Loading @@ -107,7 +111,7 @@ public class MagnificationModePreferenceControllerTest { performItemClickWith(MagnificationMode.WINDOW); reshowPreferenceOnTheScreen(); mDialogHelper.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE); assertThat(getCheckedModeFromDialog()).isEqualTo( MagnificationMode.WINDOW); Loading @@ -123,7 +127,7 @@ public class MagnificationModePreferenceControllerTest { DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper, never()).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test Loading @@ -135,8 +139,7 @@ public class MagnificationModePreferenceControllerTest { mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(), DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test Loading @@ -148,20 +151,17 @@ public class MagnificationModePreferenceControllerTest { mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(), DialogInterface.BUTTON_POSITIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); } @Test public void onTripleTapWarningDialogNegativeButtonClicked_showModeDialog() { mDialogHelper.showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mController.onMagnificationTripleTapWarningDialogNegativeButtonClicked( mDialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE); verify(mDialogHelper).showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE); verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE); } @Test Loading @@ -182,8 +182,7 @@ public class MagnificationModePreferenceControllerTest { @Test public void checkSpansInTripleTapWarningDialog_existAnnotationSpan() { mDialogHelper.showDialog( MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING); final View contentView = mDialogHelper.getDialog().findViewById(android.R.id.content); final TextView messageView = contentView.findViewById(R.id.message); final CharSequence textInTripleTapWarningDialog = messageView.getText(); Loading Loading @@ -256,13 +255,11 @@ public class MagnificationModePreferenceControllerTest { } private void showPreferenceOnTheScreen(Bundle savedInstanceState) { mController.setDialogHelper(mDialogHelper); mController.onCreate(savedInstanceState); mController.displayPreference(mScreen); } private static class TestDialogHelper implements DialogCreatable, MagnificationModePreferenceController.DialogHelper { private static class TestDialogHelper implements DialogCreatable, DialogHelper { private DialogCreatable mDialogDelegate; private Dialog mDialog; Loading @@ -271,11 +268,11 @@ public class MagnificationModePreferenceControllerTest { mDialog = onCreateDialog(dialogId); } @Override public void setDialogDelegate(DialogCreatable delegate) { public void setDialogDelegate(@NonNull DialogCreatable delegate) { mDialogDelegate = delegate; } @NonNull @Override public Dialog onCreateDialog(int dialogId) { return mDialogDelegate.onCreateDialog(dialogId); Loading