Redesign roles of variable mUserShortcutTypesCache & mUserShortcutTypes

* mUserShortcutTypesCache -> get value from savedInstanceState only
* mUserShortcutTypes -> use local variables to replace its mission

Bug: 158540780
Test: atest ToggleFeaturePreferenceFragmentTest
Change-Id: I1473f89ed743261f616e8d19733bae829c9dbb02
This commit is contained in:
jasonwshsu
2020-08-25 04:27:36 +08:00
parent c79680cbae
commit 9f54ab9afa
3 changed files with 159 additions and 109 deletions

View File

@@ -313,12 +313,6 @@ public class ToggleAccessibilityServicePreferenceFragment extends
@Override
public void onSettingsClicked(ShortcutPreference preference) {
// Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off.
mUserShortcutTypesCache = mShortcutPreference.isChecked()
? retrieveUserShortcutType(getPrefContext(), mComponentName.flattenToString(),
UserShortcutType.SOFTWARE)
: UserShortcutType.EMPTY;
final boolean isServiceOnOrShortcutAdded = mShortcutPreference.isChecked()
|| mToggleServiceDividerSwitchPreference.isChecked();
showPopupDialog(isServiceOnOrShortcutAdded ? DialogEnums.EDIT_SHORTCUT

View File

@@ -16,11 +16,6 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.getScreenHeightPixels;
import static com.android.settings.accessibility.AccessibilityUtil.getScreenWidthPixels;
import static com.android.settings.accessibility.PreferredShortcuts.retrieveUserShortcutType;
import static com.android.settings.accessibility.PreferredShortcuts.saveUserShortcutType;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
@@ -92,8 +87,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
protected static final String KEY_GENERAL_CATEGORY = "general_categories";
protected static final String KEY_INTRODUCTION_CATEGORY = "introduction_categories";
private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference";
@VisibleForTesting
static final String EXTRA_SHORTCUT_TYPE = "shortcut_type";
protected static final String KEY_SAVED_USER_SHORTCUT_TYPE = "shortcut_type";
private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
private SettingsContentObserver mSettingsContentObserver;
@@ -101,9 +95,9 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
private CheckBox mSoftwareTypeCheckBox;
private CheckBox mHardwareTypeCheckBox;
// Used to restore the edit dialog status.
protected int mUserShortcutTypesCache = UserShortcutType.EMPTY;
protected int mUserShortcutTypes = UserShortcutType.EMPTY;
public static final int NOT_SET = -1;
// Save user's shortcutType value when savedInstance has value (e.g. device rotated).
protected int mSavedCheckBoxValue = NOT_SET;
// For html description of accessibility service, must follow the rule, such as
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
@@ -125,10 +119,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Restore the user shortcut type.
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_SHORTCUT_TYPE)) {
mUserShortcutTypesCache = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE,
UserShortcutType.EMPTY);
if (savedInstanceState != null && savedInstanceState.containsKey(
KEY_SAVED_USER_SHORTCUT_TYPE)) {
mSavedCheckBoxValue = savedInstanceState.getInt(KEY_SAVED_USER_SHORTCUT_TYPE, NOT_SET);
}
setupDefaultShortcutIfNecessary(getPrefContext());
@@ -188,6 +183,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override
public void onResume() {
super.onResume();
final AccessibilityManager am = getPrefContext().getSystemService(
AccessibilityManager.class);
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
@@ -207,7 +203,10 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypesCache);
final int value = getShortcutTypeCheckBoxValue();
if (value != NOT_SET) {
outState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, value);
}
super.onSaveInstanceState(outState);
}
@@ -220,7 +219,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
R.string.accessibility_shortcut_title, mPackageName);
dialog = AccessibilityEditDialogUtils.showEditShortcutDialog(
getPrefContext(), dialogTitle, this::callOnAlertDialogCheckboxClicked);
initializeDialogCheckBox(dialog);
setupEditShortcutDialog(dialog);
return dialog;
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
dialog = AccessibilityGestureNavigationTutorial
@@ -379,8 +378,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
mImageGetterCacheView.setImageURI(null);
final int imageWidth = drawable.getIntrinsicWidth();
final int imageHeight = drawable.getIntrinsicHeight();
final int screenHalfHeight = getScreenHeightPixels(getPrefContext()) / /* half */ 2;
if ((imageWidth > getScreenWidthPixels(getPrefContext()))
final int screenHalfHeight = AccessibilityUtil.getScreenHeightPixels(getPrefContext()) / 2;
if ((imageWidth > AccessibilityUtil.getScreenWidthPixels(getPrefContext()))
|| (imageHeight > screenHalfHeight)) {
return null;
}
@@ -396,7 +395,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return;
}
final int screenHalfHeight = getScreenHeightPixels(getPrefContext()) / /* half */ 2;
final int screenHalfHeight = AccessibilityUtil.getScreenHeightPixels(getPrefContext()) / 2;
final AnimatedImagePreference animatedImagePreference =
new AnimatedImagePreference(getPrefContext());
animatedImagePreference.setImageUri(mImageUri);
@@ -425,6 +424,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
getPreferenceScreen().addPreference(generalCategory);
}
protected void initShortcutPreference() {
// Initial the shortcut preference.
mShortcutPreference = new ShortcutPreference(getPrefContext(), /* attrs= */ null);
mShortcutPreference.setPersistent(false);
mShortcutPreference.setKey(getShortcutPreferenceKey());
mShortcutPreference.setOnClickCallback(this);
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
mShortcutPreference.setTitle(title);
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
generalCategory.addPreference(mShortcutPreference);
}
protected void initSettingsPreference() {
if (mSettingsTitle == null || mSettingsIntent == null) {
return;
@@ -478,16 +491,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
}
}
private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) {
final View dialogTextArea = dialogView.findViewById(R.id.container);
dialogTextArea.setOnClickListener(v -> {
checkBox.toggle();
updateUserShortcutType(/* saveChanges= */ false);
});
}
@VisibleForTesting
void initializeDialogCheckBox(Dialog dialog) {
void setupEditShortcutDialog(Dialog dialog) {
final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut);
mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox);
setDialogTextAreaClickListener(dialogSoftwareView, mSoftwareTypeCheckBox);
@@ -496,39 +501,58 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox);
setDialogTextAreaClickListener(dialogHardwareView, mHardwareTypeCheckBox);
updateAlertDialogCheckState();
updateEditShortcutDialogCheckBox();
}
private void updateAlertDialogCheckState() {
if (mUserShortcutTypesCache != UserShortcutType.EMPTY) {
updateCheckStatus(mSoftwareTypeCheckBox, UserShortcutType.SOFTWARE);
updateCheckStatus(mHardwareTypeCheckBox, UserShortcutType.HARDWARE);
private void setDialogTextAreaClickListener(View dialogView, CheckBox checkBox) {
final View dialogTextArea = dialogView.findViewById(R.id.container);
dialogTextArea.setOnClickListener(v -> checkBox.toggle());
}
private void updateEditShortcutDialogCheckBox() {
// If it is during onConfigChanged process then restore the value, or get the saved value
// when shortcutPreference is checked.
int value = restoreOnConfigChangedValue();
if (value == NOT_SET) {
final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType(
getPrefContext(), mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType
: UserShortcutType.EMPTY;
}
mSoftwareTypeCheckBox.setChecked(
hasShortcutType(value, UserShortcutType.SOFTWARE));
mHardwareTypeCheckBox.setChecked(
hasShortcutType(value, UserShortcutType.HARDWARE));
}
private void updateCheckStatus(CheckBox checkBox, @UserShortcutType int type) {
checkBox.setChecked((mUserShortcutTypesCache & type) == type);
private int restoreOnConfigChangedValue() {
final int savedValue = mSavedCheckBoxValue;
mSavedCheckBoxValue = NOT_SET;
return savedValue;
}
@VisibleForTesting
void updateUserShortcutType(boolean saveChanges) {
mUserShortcutTypesCache = UserShortcutType.EMPTY;
private boolean hasShortcutType(int value, @UserShortcutType int type) {
return (value & type) == type;
}
/**
* Returns accumulated {@link UserShortcutType} checkbox value or {@code NOT_SET} if checkboxes
* did not exist.
*/
protected int getShortcutTypeCheckBoxValue() {
if (mSoftwareTypeCheckBox == null || mHardwareTypeCheckBox == null) {
return NOT_SET;
}
int value = UserShortcutType.EMPTY;
if (mSoftwareTypeCheckBox.isChecked()) {
mUserShortcutTypesCache |= UserShortcutType.SOFTWARE;
value |= UserShortcutType.SOFTWARE;
}
if (mHardwareTypeCheckBox.isChecked()) {
mUserShortcutTypesCache |= UserShortcutType.HARDWARE;
}
if (saveChanges) {
final boolean isChanged = (mUserShortcutTypesCache != UserShortcutType.EMPTY);
if (isChanged) {
final PreferredShortcut shortcut = new PreferredShortcut(
mComponentName.flattenToString(), mUserShortcutTypesCache);
saveUserShortcutType(getPrefContext(), shortcut);
}
mUserShortcutTypes = mUserShortcutTypesCache;
value |= UserShortcutType.HARDWARE;
}
return value;
}
protected CharSequence getShortcutTypeSummary(Context context) {
@@ -540,7 +564,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return context.getText(R.string.switch_off_text);
}
final int shortcutTypes = retrieveUserShortcutType(context,
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context,
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
int resId = R.string.accessibility_shortcut_edit_summary_software;
if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
@@ -581,14 +605,13 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return;
}
updateUserShortcutType(/* saveChanges= */ true);
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), mUserShortcutTypes,
mComponentName);
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~mUserShortcutTypes,
mComponentName);
mShortcutPreference.setChecked(mUserShortcutTypes != UserShortcutType.EMPTY);
mShortcutPreference.setSummary(
getShortcutTypeSummary(getPrefContext()));
final int value = getShortcutTypeCheckBoxValue();
saveNonEmptyUserShortcutType(value);
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), value, mComponentName);
AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~value, mComponentName);
mShortcutPreference.setChecked(value != UserShortcutType.EMPTY);
mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext()));
}
protected void updateShortcutPreferenceData() {
@@ -596,40 +619,21 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return;
}
// Get the user shortcut type from settings provider.
mUserShortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
mComponentName);
if (mUserShortcutTypes != UserShortcutType.EMPTY) {
final int shortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(
getPrefContext(), mComponentName);
if (shortcutTypes != UserShortcutType.EMPTY) {
final PreferredShortcut shortcut = new PreferredShortcut(
mComponentName.flattenToString(), mUserShortcutTypes);
saveUserShortcutType(getPrefContext(), shortcut);
} else {
// Get the user shortcut type from shared_prefs if cannot get from settings provider.
mUserShortcutTypes = retrieveUserShortcutType(getPrefContext(),
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mComponentName.flattenToString(), shortcutTypes);
PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
}
}
protected void initShortcutPreference() {
// Initial the shortcut preference.
mShortcutPreference = new ShortcutPreference(getPrefContext(), null);
mShortcutPreference.setPersistent(false);
mShortcutPreference.setKey(getShortcutPreferenceKey());
mShortcutPreference.setOnClickCallback(this);
final CharSequence title = getString(R.string.accessibility_shortcut_title, mPackageName);
mShortcutPreference.setTitle(title);
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
generalCategory.addPreference(mShortcutPreference);
}
protected void updateShortcutPreference() {
if (mComponentName == null) {
return;
}
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mShortcutPreference.setChecked(
AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes,
@@ -647,7 +651,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
return;
}
final int shortcutTypes = retrieveUserShortcutType(getPrefContext(),
final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(),
mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
if (preference.isChecked()) {
AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes,
@@ -662,11 +666,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
@Override
public void onSettingsClicked(ShortcutPreference preference) {
// Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off.
mUserShortcutTypesCache = mShortcutPreference.isChecked()
? retrieveUserShortcutType(getPrefContext(),
mComponentName.flattenToString(), UserShortcutType.SOFTWARE)
: UserShortcutType.EMPTY;
showDialog(DialogEnums.EDIT_SHORTCUT);
}
@@ -703,4 +702,15 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
shortcutName.flattenToString());
}
}
@VisibleForTesting
void saveNonEmptyUserShortcutType(int type) {
if (type == UserShortcutType.EMPTY) {
return;
}
final PreferredShortcut shortcut = new PreferredShortcut(
mComponentName.flattenToString(), type);
PreferredShortcuts.saveUserShortcutType(getPrefContext(), shortcut);
}
}

View File

@@ -16,7 +16,7 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.EXTRA_SHORTCUT_TYPE;
import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE;
import static com.google.common.truth.Truth.assertThat;
@@ -62,6 +62,7 @@ public class ToggleFeaturePreferenceFragmentTest {
private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder";
private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME);
private static final String PLACEHOLDER_DIALOG_TITLE = "title";
private static final String SOFTWARE_SHORTCUT_KEY =
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
@@ -88,7 +89,7 @@ public class ToggleFeaturePreferenceFragmentTest {
@Test
public void createFragment_shouldOnlyAddPreferencesOnce() {
FragmentController.setupFragment(mFragment, FragmentActivity.class,
/* containerViewId= */ 0, /* bundle= */null);
/* containerViewId= */ 0, /* bundle= */ null);
// execute exactly once
verify(mFragment).addPreferencesFromResource(R.xml.placeholder_prefs);
@@ -100,8 +101,10 @@ public class ToggleFeaturePreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
// Compare to default UserShortcutType
assertThat(mFragment.mUserShortcutTypes).isEqualTo(UserShortcutType.SOFTWARE);
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
}
@Test
@@ -112,8 +115,9 @@ public class ToggleFeaturePreferenceFragmentTest {
putStringIntoSettings(HARDWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString());
mFragment.updateShortcutPreferenceData();
assertThat(mFragment.mUserShortcutTypes).isEqualTo(
UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}
@Test
@@ -125,28 +129,70 @@ public class ToggleFeaturePreferenceFragmentTest {
putUserShortcutTypeIntoSharedPreference(mContext, hardwareShortcut);
mFragment.updateShortcutPreferenceData();
assertThat(mFragment.mUserShortcutTypes).isEqualTo(UserShortcutType.HARDWARE);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE);
}
@Test
public void setupEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue() {
mContext.setTheme(R.style.Theme_AppCompat);
final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog(
mContext, PLACEHOLDER_DIALOG_TITLE, this::callEmptyOnClicked);
final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
null);
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
mFragment.mShortcutPreference = shortcutPreference;
mFragment.mShortcutPreference.setChecked(false);
mFragment.setupEditShortcutDialog(dialog);
final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue();
assertThat(checkboxValue).isEqualTo(UserShortcutType.EMPTY);
}
@Test
public void setupEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue() {
mContext.setTheme(R.style.Theme_AppCompat);
final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog(
mContext, PLACEHOLDER_DIALOG_TITLE, this::callEmptyOnClicked);
final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
null);
final PreferredShortcut hardwareShortcut = new PreferredShortcut(
PLACEHOLDER_COMPONENT_NAME.flattenToString(), UserShortcutType.HARDWARE);
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
mFragment.mShortcutPreference = shortcutPreference;
PreferredShortcuts.saveUserShortcutType(mContext, hardwareShortcut);
mFragment.mShortcutPreference.setChecked(true);
mFragment.setupEditShortcutDialog(dialog);
final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue();
assertThat(checkboxValue).isEqualTo(UserShortcutType.HARDWARE);
}
@Test
@Config(shadows = ShadowFragment.class)
public void restoreValueFromSavedInstanceState_assignToVariable() {
mContext.setTheme(R.style.Theme_AppCompat);
final String dialogTitle = "title";
final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog(
mContext, dialogTitle, this::callEmptyOnClicked);
mContext, PLACEHOLDER_DIALOG_TITLE, this::callEmptyOnClicked);
final Bundle savedInstanceState = new Bundle();
final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
null);
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
mFragment.mShortcutPreference = shortcutPreference;
savedInstanceState.putInt(EXTRA_SHORTCUT_TYPE,
savedInstanceState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE,
UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
mFragment.onCreate(savedInstanceState);
mFragment.initializeDialogCheckBox(dialog);
mFragment.updateUserShortcutType(true);
assertThat(mFragment.mUserShortcutTypes).isEqualTo(
UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
mFragment.setupEditShortcutDialog(dialog);
final int value = mFragment.getShortcutTypeCheckBoxValue();
mFragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}
private void putStringIntoSettings(String key, String componentName) {