Extract the logic of MagnificationMode to the controller

To move the preference to the upper layer, we extract all logics
to its controller.

We move all tests to the test files and add server tests to
verify the behaviour of edit shortcut dialog.

Bug: 182992338
Test: atest  MagnificationModePreferenceControllerTest

Change-Id: I34c4361e2e116a22c3e34bd35c8ac8cac752ab96
This commit is contained in:
ryanlwlin
2021-04-01 17:25:48 +08:00
parent 9d14071637
commit 8e5e4dec12
8 changed files with 531 additions and 429 deletions

View File

@@ -47,13 +47,13 @@
android:orientation="vertical">
<Button
android:id="@+id/switch_shortcut_positive_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/switch_shortcut_negative_button"
android:id="@+id/custom_negative_button"
style="@style/AccessibilityDialogButton"
android:gravity="center|end"
android:text="@string/accessibility_magnification_switch_shortcut_negative_button"/>

View File

@@ -118,18 +118,19 @@ public class AccessibilityEditDialogUtils {
*
* @param context A valid context
* @param dialogTitle The title of magnify edit shortcut dialog
* @param listener The listener to determine the action of magnify edit shortcut dialog
* @param positiveBtnListener The positive button listener
* @return A magnification edit shortcut dialog in Magnification
*/
public static Dialog showMagnificationSwitchShortcutDialog(Context context,
CharSequence dialogTitle, View.OnClickListener listener) {
public static Dialog createMagnificationSwitchShortcutDialog(Context context,
CharSequence dialogTitle, CustomButtonsClickListener positiveBtnListener) {
final View contentView = createSwitchShortcutDialogContentView(context);
final AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(createSwitchShortcutDialogContentView(context))
.setView(contentView)
.setTitle(dialogTitle)
.create();
alertDialog.show();
setEditShortcutButtonsListener(alertDialog, listener);
setScrollIndicators(alertDialog);
setCustomButtonsClickListener(alertDialog, contentView,
positiveBtnListener, /* negativeBtnListener= */ null);
setScrollIndicators(contentView);
return alertDialog;
}
@@ -169,16 +170,50 @@ public class AccessibilityEditDialogUtils {
View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
}
private static void setEditShortcutButtonsListener(AlertDialog dialog,
View.OnClickListener listener) {
final View contentView = dialog.findViewById(R.id.container_layout);
final Button positiveButton = contentView.findViewById(
R.id.switch_shortcut_positive_button);
final Button negativeButton = contentView.findViewById(
R.id.switch_shortcut_negative_button);
positiveButton.setOnClickListener(listener);
negativeButton.setOnClickListener(v -> dialog.dismiss());
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) {

View File

@@ -42,12 +42,14 @@ public final class MagnificationCapabilities {
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
MagnificationMode.NONE,
MagnificationMode.FULLSCREEN,
MagnificationMode.WINDOW,
MagnificationMode.ALL,
})
public @interface MagnificationMode {
int NONE = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
int FULLSCREEN = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
int WINDOW = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
int ALL = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;

View File

@@ -16,15 +16,85 @@
package com.android.settings.accessibility;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.settings.accessibility.AccessibilityEditDialogUtils.CustomButton;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
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;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
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.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
/** Controller that shows the magnification area mode summary. */
public class MagnificationModePreferenceController extends BasePreferenceController {
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
DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState {
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_SWITCH_SHORTCUT = 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 MagnificationSettingsFragment mParentFragment;
// The magnification mode in the dialog.
private int mMode = MagnificationMode.NONE;
private Preference mModePreference;
@VisibleForTesting
ListView mMagnificationModesListView;
private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
public MagnificationModePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
initModeInfos();
}
private void initModeInfos() {
mModeInfos.add(new MagnificationModeInfo(mContext.getText(
R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
R.drawable.ic_illustration_fullscreen, MagnificationMode.FULLSCREEN));
mModeInfos.add(new MagnificationModeInfo(
mContext.getText(R.string.accessibility_magnification_mode_dialog_option_window),
null, R.drawable.ic_illustration_window, MagnificationMode.WINDOW));
mModeInfos.add(new MagnificationModeInfo(
mContext.getText(R.string.accessibility_magnification_mode_dialog_option_switch),
mContext.getText(
R.string.accessibility_magnification_area_settings_mode_switch_summary),
R.drawable.ic_illustration_switch, MagnificationMode.ALL));
}
@Override
@@ -32,10 +102,180 @@ public class MagnificationModePreferenceController extends BasePreferenceControl
return AVAILABLE;
}
@Override
public CharSequence getSummary() {
final int capabilities = MagnificationCapabilities.getCapabilities(mContext);
return MagnificationCapabilities.getSummary(mContext, capabilities);
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mMode = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mModePreference = screen.findPreference(getPreferenceKey());
mModePreference.setOnPreferenceClickListener(preference -> {
mMode = MagnificationCapabilities.getCapabilities(mContext);
mParentFragment.showDialog(DIALOG_MAGNIFICATION_MODE);
return true;
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(EXTRA_MODE, mMode);
}
public void setParentFragment(MagnificationSettingsFragment parentFragment) {
mParentFragment = parentFragment;
}
@Override
public Dialog onCreateDialog(int dialogId) {
switch (dialogId) {
case DIALOG_MAGNIFICATION_MODE:
return createMagnificationModeDialog();
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
return createMagnificationShortCutConfirmDialog();
}
return null;
}
@Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
case DIALOG_MAGNIFICATION_MODE:
return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
return SettingsEnums.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT;
default:
return 0;
}
}
private Dialog createMagnificationModeDialog() {
mMagnificationModesListView = AccessibilityEditDialogUtils.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);
mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true);
final CharSequence title = mContext.getString(
R.string.accessibility_magnification_mode_dialog_title);
return AccessibilityEditDialogUtils.createCustomDialog(mContext, title,
mMagnificationModesListView, this::onMagnificationModeDialogPositiveButtonClicked);
}
private 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 {
Log.w(TAG, "invalid index");
}
}
private void setMode(int mode) {
mMode = mode;
MagnificationCapabilities.setCapabilities(mContext, mMode);
mModePreference.setSummary(
MagnificationCapabilities.getSummary(mContext, mMode));
}
private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
long id) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
position);
if (modeInfo.mMagnificationMode == mMode) {
return;
}
mMode = modeInfo.mMagnificationMode;
if (isTripleTapEnabled(mContext) && mMode != MagnificationMode.FULLSCREEN) {
mParentFragment.showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
}
private int computeSelectionIndex() {
final int modesSize = mModeInfos.size();
for (int i = 0; i < modesSize; i++) {
if (mModeInfos.get(i).mMagnificationMode == mMode) {
return i + mMagnificationModesListView.getHeaderViewsCount();
}
}
Log.w(TAG, "computeSelectionIndex failed");
return 0;
}
@VisibleForTesting
static boolean isTripleTapEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
}
private Dialog createMagnificationShortCutConfirmDialog() {
final String title = mContext.getString(
R.string.accessibility_magnification_switch_shortcut_title);
return AccessibilityEditDialogUtils.createMagnificationSwitchShortcutDialog(mContext, title,
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 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;
}
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
if (!TextUtils.isEmpty(targetString)) {
joiner.add(targetString);
}
joiner.add(MAGNIFICATION_CONTROLLER_NAME);
Settings.Secure.putString(mContext.getContentResolver(), targetKey,
joiner.toString());
}
@VisibleForTesting
static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
@MagnificationMode
public final int mMagnificationMode;
MagnificationModeInfo(@NonNull CharSequence title, @Nullable CharSequence summary,
@DrawableRes int drawableId, @MagnificationMode int magnificationMode) {
super(title, summary, drawableId);
mMagnificationMode = magnificationMode;
}
}
}

View File

@@ -16,88 +16,22 @@
package com.android.settings.accessibility;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
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;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
/** Settings page for magnification. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class MagnificationSettingsFragment extends DashboardFragment {
private static final String TAG = "MagnificationSettingsFragment";
private static final String PREF_KEY_MODE = "magnification_mode";
@VisibleForTesting
static final int DIALOG_MAGNIFICATION_CAPABILITY = 1;
@VisibleForTesting
static final int DIALOG_MAGNIFICATION_SWITCH_SHORTCUT = 2;
@VisibleForTesting
static final String EXTRA_CAPABILITY = "capability";
private static final int NONE = 0;
private static final char COMPONENT_NAME_SEPARATOR = ':';
private Preference mModePreference;
@VisibleForTesting
Dialog mDialog;
@VisibleForTesting
ListView mMagnificationModesListView;
private int mCapabilities = NONE;
private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCapabilities = savedInstanceState.getInt(EXTRA_CAPABILITY, NONE);
}
if (mCapabilities == NONE) {
mCapabilities = MagnificationCapabilities.getCapabilities(getPrefContext());
}
initModeInfos();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initModePreference();
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(EXTRA_CAPABILITY, mCapabilities);
super.onSaveInstanceState(outState);
}
private MagnificationModePreferenceController mMagnificationModePreferenceController;
@Override
public int getMetricsCategory() {
@@ -105,15 +39,23 @@ public class MagnificationSettingsFragment extends DashboardFragment {
}
@Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
case DIALOG_MAGNIFICATION_CAPABILITY:
return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
return SettingsEnums.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT;
default:
return 0;
public void onAttach(Context context) {
super.onAttach(context);
mMagnificationModePreferenceController = use(MagnificationModePreferenceController.class);
mMagnificationModePreferenceController.setParentFragment(this);
}
@Override
protected void showDialog(int dialogId) {
super.showDialog(dialogId);
}
@Override
public int getDialogMetricsCategory(int dialogId) {
if (mMagnificationModePreferenceController != null) {
return mMagnificationModePreferenceController.getDialogMetricsCategory(dialogId);
}
return 0;
}
@Override
@@ -128,157 +70,15 @@ public class MagnificationSettingsFragment extends DashboardFragment {
@Override
public Dialog onCreateDialog(int dialogId) {
final CharSequence title;
switch (dialogId) {
case DIALOG_MAGNIFICATION_CAPABILITY:
mDialog = createMagnificationModeDialog();
return mDialog;
case DIALOG_MAGNIFICATION_SWITCH_SHORTCUT:
title = getPrefContext().getString(
R.string.accessibility_magnification_switch_shortcut_title);
mDialog = AccessibilityEditDialogUtils.showMagnificationSwitchShortcutDialog(
getPrefContext(), title, this::onSwitchShortcutDialogPositiveButtonClicked);
return mDialog;
if (mMagnificationModePreferenceController != null) {
final Dialog dialog = mMagnificationModePreferenceController.onCreateDialog(dialogId);
if (dialog != null) {
return dialog;
}
}
throw new IllegalArgumentException("Unsupported dialogId " + dialogId);
}
private Dialog createMagnificationModeDialog() {
mMagnificationModesListView = AccessibilityEditDialogUtils.createSingleChoiceListView(
getPrefContext(), mModeInfos, this::onMagnificationModeSelected);
final View headerView = LayoutInflater.from(getPrefContext()).inflate(
R.layout.accessibility_magnification_mode_header, mMagnificationModesListView,
false);
mMagnificationModesListView.addHeaderView(headerView, null, /* isSelectable= */false);
mMagnificationModesListView.setItemChecked(computeSelectedMagnificationModeIndex(), true);
final CharSequence title = getPrefContext().getString(
R.string.accessibility_magnification_mode_dialog_title);
return AccessibilityEditDialogUtils.createCustomDialog(getPrefContext(), title,
mMagnificationModesListView, this::onMagnificationModeDialogPositiveButtonClicked);
}
private int computeSelectedMagnificationModeIndex() {
final int size = mModeInfos.size();
for (int i = 0; i < size; i++) {
if (mModeInfos.get(i).mMagnificationMode == mCapabilities) {
return i + mMagnificationModesListView.getHeaderViewsCount();
}
}
Log.w(TAG, "chosen mode" + mCapabilities + "is not in the list");
return 0;
}
private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
long id) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(position);
if (modeInfo.mMagnificationMode == mCapabilities) {
return;
}
mCapabilities = modeInfo.mMagnificationMode;
if (isTripleTapEnabled() && mCapabilities != MagnificationMode.FULLSCREEN) {
showDialog(DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
}
private void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
int which) {
final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
if (selectedIndex != AdapterView.INVALID_POSITION) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
selectedIndex);
updateCapabilities(modeInfo.mMagnificationMode);
} else {
Log.w(TAG, "no checked item in the list");
}
}
private void updateCapabilities(int mode) {
mCapabilities = mode;
MagnificationCapabilities.setCapabilities(getPrefContext(), mCapabilities);
mModePreference.setSummary(
MagnificationCapabilities.getSummary(getPrefContext(), mCapabilities));
}
private void initModeInfos() {
mModeInfos.clear();
mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
R.drawable.ic_illustration_fullscreen, MagnificationMode.FULLSCREEN));
mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
R.string.accessibility_magnification_mode_dialog_option_window), null,
R.drawable.ic_illustration_window, MagnificationMode.WINDOW));
mModeInfos.add(new MagnificationModeInfo(getPrefContext().getText(
R.string.accessibility_magnification_mode_dialog_option_switch),
getPrefContext().getText(
R.string.accessibility_magnification_area_settings_mode_switch_summary),
R.drawable.ic_illustration_switch, MagnificationMode.ALL));
}
@VisibleForTesting
static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
@MagnificationMode
public final int mMagnificationMode;
MagnificationModeInfo(@NonNull CharSequence title, @Nullable CharSequence summary,
@DrawableRes int drawableId, @MagnificationMode int magnificationMode) {
super(title, summary, drawableId);
mMagnificationMode = magnificationMode;
}
}
private void initModePreference() {
mModePreference = findPreference(PREF_KEY_MODE);
mModePreference.setOnPreferenceClickListener(preference -> {
mCapabilities = MagnificationCapabilities.getCapabilities(getPrefContext());
showDialog(DIALOG_MAGNIFICATION_CAPABILITY);
return true;
});
}
private void onSwitchShortcutDialogPositiveButtonClicked(View view) {
//TODO(b/147990389): Merge this function into util until magnification change format to
// Component.
optOutMagnificationFromTripleTap();
optInMagnificationToAccessibilityButton();
mDialog.dismiss();
}
private void optOutMagnificationFromTripleTap() {
Settings.Secure.putInt(getPrefContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF);
}
private void optInMagnificationToAccessibilityButton() {
final String targetKey = Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
final String targetString = Settings.Secure.getString(getPrefContext().getContentResolver(),
targetKey);
if (targetString.contains(MAGNIFICATION_CONTROLLER_NAME)) {
return;
}
final StringJoiner joiner = new StringJoiner(String.valueOf(COMPONENT_NAME_SEPARATOR));
if (!TextUtils.isEmpty(targetString)) {
joiner.add(targetString);
}
joiner.add(MAGNIFICATION_CONTROLLER_NAME);
Settings.Secure.putString(getPrefContext().getContentResolver(), targetKey,
joiner.toString());
}
private boolean isTripleTapEnabled() {
return Settings.Secure.getInt(getPrefContext().getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.accessibility_magnification_service_settings);
}

View File

@@ -56,4 +56,11 @@ public final class MagnificationCapabilitiesTest {
R.string.accessibility_magnification_area_settings_full_screen_summary);
assertThat(actualString).isEqualTo(expectedString);
}
@Test
public void getCapabilities_unset_defaultValue() {
final int windowCapabilities = MagnificationCapabilities.getCapabilities(mContext);
assertThat(windowCapabilities).isEqualTo(
MagnificationCapabilities.MagnificationMode.FULLSCREEN);
}
}

View File

@@ -16,40 +16,143 @@
package com.android.settings.accessibility;
import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
import static com.android.settings.accessibility.AccessibilityEditDialogUtils.CustomButton;
import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
import static com.android.settings.accessibility.MagnificationPreferenceFragment.ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
public class MagnificationModePreferenceControllerTest {
private static final String PREF_KEY = "screen_magnification_mode";
private static final String KEY_CAPABILITY =
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY;
private static final int WINDOW_SCREEN_VALUE = 2;
private static final int ALL_VALUE = 3;
private static final int MAGNIFICATION_MODE_DEFAULT = MagnificationMode.ALL;
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private TestMagnificationSettingsFragment mFragment;
private MagnificationModePreferenceController mController;
private Preference mModePreference;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new MagnificationModePreferenceController(mContext, PREF_KEY);
mScreen = spy(new PreferenceScreen(mContext, null));
mModePreference = new Preference(mContext);
mFragment = spy(new TestMagnificationSettingsFragment(mController));
doReturn(mScreen).when(mFragment).getPreferenceScreen();
doReturn(mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS)).when(
mFragment).getChildFragmentManager();
mContext.setTheme(R.style.Theme_AppCompat);
doReturn(mModePreference).when(mScreen).findPreference(PREF_KEY);
MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT);
showPreferenceOnTheScreen(null);
mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
}
@Test
public void settingsModeIsDefault_checkedModeInDialogIsDefault() {
assertThat(getCheckedModeFromDialog()).isEqualTo(
MAGNIFICATION_MODE_DEFAULT);
}
@Test
public void choseModeIsDifferentFromInSettings_checkedModeInDialogIsExpected() {
performItemClickWith(MagnificationMode.WINDOW);
assertThat(getCheckedModeFromDialog()).isEqualTo(MagnificationMode.WINDOW);
}
@Test
public void dialogIsReCreated_settingsModeIsAllAndChoseWindowMode_checkedModeIsWindow() {
showPreferenceOnTheScreen(null);
performItemClickWith(MagnificationMode.WINDOW);
reshowPreferenceOnTheScreen();
mFragment.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
assertThat(getCheckedModeFromDialog()).isEqualTo(
MagnificationMode.WINDOW);
}
@Test
public void chooseWindowMode_tripleTapEnabled_showSwitchShortcutDialog() {
enableTripleTap();
performItemClickWith(MagnificationMode.WINDOW);
verify(mFragment).showDialog(
MagnificationModePreferenceController.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
@Test
public void chooseModeAll_modeAllInSettingsAndTripleTapEnabled_notShowShortcutDialog() {
enableTripleTap();
MagnificationCapabilities.setCapabilities(mContext,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
mFragment.onCreate(Bundle.EMPTY);
mFragment.onCreateDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
performItemClickWith(MagnificationMode.ALL);
verify(mFragment, never()).showDialog(
MagnificationModePreferenceController.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
@Test
public void onSwitchShortcutDialogPositiveButtonClicked_TripleTapEnabled_TripleTapDisabled() {
enableTripleTap();
mController.onSwitchShortcutDialogButtonClicked(CustomButton.POSITIVE);
assertThat(MagnificationModePreferenceController.isTripleTapEnabled(mContext)).isFalse();
}
@Test
public void getSummary_saveWindowScreen_shouldReturnWindowScreenSummary() {
Settings.Secure.putInt(mContext.getContentResolver(),
KEY_CAPABILITY, WINDOW_SCREEN_VALUE);
MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.WINDOW);
assertThat(mController.getSummary())
.isEqualTo(mContext.getString(
@@ -58,11 +161,93 @@ public class MagnificationModePreferenceControllerTest {
@Test
public void getSummary_saveAll_shouldReturnAllSummary() {
Settings.Secure.putInt(mContext.getContentResolver(),
KEY_CAPABILITY, ALL_VALUE);
MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL);
assertThat(mController.getSummary())
.isEqualTo(mContext.getString(
R.string.accessibility_magnification_area_settings_all_summary));
}
private int getCheckedModeFromDialog() {
final ListView listView = mController.mMagnificationModesListView;
assertThat(listView).isNotNull();
final int checkedPosition = listView.getCheckedItemPosition();
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) listView.getAdapter().getItem(checkedPosition);
return modeInfo.mMagnificationMode;
}
private void performItemClickWith(@MagnificationMode int mode) {
final ListView listView = mController.mMagnificationModesListView;
assertThat(listView).isNotNull();
int modeIndex = AdapterView.NO_ID;
// Index 0 is header.
for (int i = 1; i < listView.getAdapter().getCount(); i++) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) listView.getAdapter().getItem(i);
if (modeInfo.mMagnificationMode == mode) {
modeIndex = i;
break;
}
}
if (modeIndex == AdapterView.NO_ID) {
throw new RuntimeException("The mode is not in the list.");
}
listView.performItemClick(listView.getChildAt(modeIndex), modeIndex, modeIndex);
}
private void enableTripleTap() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
}
private void reshowPreferenceOnTheScreen() {
final Bundle bundle = new Bundle();
mFragment.onSaveInstanceState(bundle);
mFragment.onDetach();
showPreferenceOnTheScreen(bundle);
}
private void showPreferenceOnTheScreen(Bundle savedInstanceState) {
mFragment.onAttach(mContext);
mFragment.onCreate(savedInstanceState);
mController.displayPreference(mScreen);
}
private static class TestMagnificationSettingsFragment extends MagnificationSettingsFragment {
TestMagnificationSettingsFragment(AbstractPreferenceController... controllers) {
// Add given controllers for injection. Although controllers will be added in
// onAttach(). use(AbstractPreferenceController.class) returns the first added one.
for (int i = 0; i < controllers.length; i++) {
addPreferenceController(controllers[i]);
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Simulate the observable behaviour because ShadowDashFragment doesn't call
// super.create.
getSettingsLifecycle().onCreate(icicle);
getSettingsLifecycle().handleLifecycleEvent(ON_CREATE);
}
@Override
protected void showDialog(int dialogId) {
super.showDialog(dialogId);
// In current fragment architecture, we could assume onCreateDialog is called directly.
onCreateDialog(dialogId);
}
@Override
protected void addPreferenceController(AbstractPreferenceController controller) {
super.addPreferenceController(controller);
}
}
}

View File

@@ -16,201 +16,34 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import static com.android.settings.accessibility.MagnificationPreferenceFragment.ON;
import static com.android.settings.accessibility.MagnificationSettingsFragment.MagnificationModeInfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceManager;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settings.testutils.XmlTestUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.List;
/** Tests for {@link MagnificationSettingsFragment} */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowDashboardFragment.class)
public class MagnificationSettingsFragmentTest {
@Rule
public MockitoRule mocks = MockitoJUnit.rule();
@Mock
private PreferenceManager mPreferenceManager;
private static final String EXTRA_CAPABILITY =
MagnificationSettingsFragment.EXTRA_CAPABILITY;
private final Context mContext = ApplicationProvider.getApplicationContext();
private TestMagnificationSettingsFragment mFragment;
@Before
public void setUpFragment() {
mFragment = spy(new TestMagnificationSettingsFragment());
when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
doReturn(mock(FragmentManager.class, Answers.RETURNS_DEEP_STUBS)).when(
mFragment).getChildFragmentManager();
mContext.setTheme(R.style.Theme_AppCompat);
}
@Test
public void onCreateDialog_capabilitiesInBundle_checkedModeInDialogIsExpected() {
final Bundle windowModeSavedInstanceState = new Bundle();
windowModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mFragment.onCreate(windowModeSavedInstanceState);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.WINDOW);
}
@Test
public void onCreateDialog_capabilitiesInSetting_checkedModeInDialogIsExpected() {
MagnificationCapabilities.setCapabilities(mContext,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
mFragment.onCreate(Bundle.EMPTY);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.FULLSCREEN);
}
@Test
public void onCreateDialog_choseModeIsDifferentFromInSettings_ShowUsersChoseModeInDialog() {
final Bundle allModeSavedInstanceState = new Bundle();
allModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
MagnificationCapabilities.setCapabilities(mContext,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mFragment.onCreate(allModeSavedInstanceState);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.ALL);
}
@Test
public void onCreateDialog_emptySettingsAndBundle_checkedModeInDialogIsDefaultValue() {
mFragment.onCreate(Bundle.EMPTY);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
assertThat(getChoseModeFromDialog()).isEqualTo(MagnificationMode.FULLSCREEN);
}
@Test
public void chooseWindowMode_tripleTapEnabled_showSwitchShortcutDialog() {
enableTripleTap();
final Bundle fullScreenModeSavedInstanceState = new Bundle();
fullScreenModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
mFragment.onCreate(fullScreenModeSavedInstanceState);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
performItemClickWith(MagnificationMode.WINDOW);
verify(mFragment).showDialog(
MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
@Test
public void chooseModeAll_tripleTapEnabled_showSwitchShortcutDialog() {
enableTripleTap();
final Bundle fullScreenModeSavedInstanceState = new Bundle();
fullScreenModeSavedInstanceState.putInt(EXTRA_CAPABILITY,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
mFragment.onCreate(fullScreenModeSavedInstanceState);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
performItemClickWith(MagnificationMode.ALL);
verify(mFragment).showDialog(
MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
@Test
public void chooseWindowMode_WindowModeInSettingsAndTripleTapEnabled_notShowShortCutDialog() {
enableTripleTap();
MagnificationCapabilities.setCapabilities(mContext,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mFragment.onCreate(Bundle.EMPTY);
mFragment.onCreateDialog(MagnificationSettingsFragment.DIALOG_MAGNIFICATION_CAPABILITY);
performItemClickWith(MagnificationMode.WINDOW);
verify(mFragment, never()).showDialog(
MagnificationSettingsFragment.DIALOG_MAGNIFICATION_SWITCH_SHORTCUT);
}
private int getChoseModeFromDialog() {
final ListView listView = mFragment.mMagnificationModesListView;
assertThat(listView).isNotNull();
final int checkedPosition = listView.getCheckedItemPosition();
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) listView.getAdapter().getItem(
checkedPosition);
return modeInfo.mMagnificationMode;
}
private void performItemClickWith(@MagnificationMode int mode) {
final ListView listView = mFragment.mMagnificationModesListView;
assertThat(listView).isNotNull();
int modeIndex = AdapterView.NO_ID;
// Index 0 is header.
for (int i = 1; i < listView.getAdapter().getCount(); i++) {
final MagnificationModeInfo modeInfo =
(MagnificationModeInfo) listView.getAdapter().getItem(i);
if (modeInfo.mMagnificationMode == mode) {
modeIndex = i;
break;
}
}
if (modeIndex == AdapterView.NO_ID) {
throw new RuntimeException("The mode is not in the list.");
}
listView.performItemClick(listView.getChildAt(modeIndex), modeIndex, modeIndex);
}
private void enableTripleTap() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
}
public static class TestMagnificationSettingsFragment extends MagnificationSettingsFragment {
public TestMagnificationSettingsFragment() {}
@Override
protected void showDialog(int dialogId) {
super.showDialog(dialogId);
}
public void getNonIndexableKeys_existInXmlLayout() {
final List<String> niks =
ShortcutsSettingsFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
final List<String> keys =
XmlTestUtils.getKeysFromPreferenceXml(mContext,
R.xml.accessibility_magnification_service_settings);
assertThat(keys).containsAtLeastElementsIn(niks);
}
}