diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java index 1d874771517..7136172a75f 100644 --- a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java +++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; - import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; @@ -245,27 +243,21 @@ public class AccessibilityEditDialogUtils { }); } - private static boolean isGestureNavigateEnabled(Context context) { - return context.getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode) - == NAV_BAR_MODE_GESTURAL; - } - private static CharSequence retrieveTitle(Context context) { - return context.getString(isGestureNavigateEnabled(context) + return context.getString(AccessibilityUtil.isGestureNavigateEnabled(context) ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture : R.string.accessibility_shortcut_edit_dialog_title_software); } private static CharSequence retrieveSummary(Context context, int lineHeight) { - return isGestureNavigateEnabled(context) + return AccessibilityUtil.isGestureNavigateEnabled(context) ? context.getString( R.string.accessibility_shortcut_edit_dialog_summary_software_gesture) : getSummaryStringWithIcon(context, lineHeight); } private static int retrieveImageResId(Context context) { - return isGestureNavigateEnabled(context) + return AccessibilityUtil.isGestureNavigateEnabled(context) ? R.drawable.accessibility_shortcut_type_software_gesture : R.drawable.accessibility_shortcut_type_software; // TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted. diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java index 153fa192a5b..5e6eced04e2 100644 --- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java +++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; - import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; @@ -83,7 +81,7 @@ public class AccessibilityGestureNavigationTutorial { final AlertDialog alertDialog = createDialog(context, DialogType.LAUNCH_SERVICE_BY_ACCESSIBILITY_BUTTON); - if (!isGestureNavigateEnabled(context)) { + if (!AccessibilityUtil.isGestureNavigateEnabled(context)) { updateMessageWithIcon(context, alertDialog); } @@ -206,12 +204,6 @@ public class AccessibilityGestureNavigationTutorial { return colorResId; } - private static boolean isGestureNavigateEnabled(Context context) { - return context.getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode) - == NAV_BAR_MODE_GESTURAL; - } - private static boolean isTouchExploreOn(Context context) { return ((AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)) .isTouchExplorationEnabled(); diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java index a3682b2f618..4b3a3419b99 100644 --- a/src/com/android/settings/accessibility/AccessibilityUtil.java +++ b/src/com/android/settings/accessibility/AccessibilityUtil.java @@ -16,6 +16,8 @@ package com.android.settings.accessibility; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; + import android.accessibilityservice.AccessibilityServiceInfo; import android.content.Context; import android.os.Build; @@ -54,18 +56,78 @@ final class AccessibilityUtil { int INTUITIVE = 2; } + /** + * Annotation for different shortcut type UI type. + * + * {@code DEFAULT} for displaying default value. + * {@code SOFTWARE} for displaying specifying the accessibility services or features which + * choose accessibility button in the navigation bar as preferred shortcut. + * {@code HARDWARE} for displaying specifying the accessibility services or features which + * choose accessibility shortcut as preferred shortcut. + * {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly + * tapping screen 3 times as preferred shortcut. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ShortcutType.DEFAULT, + ShortcutType.SOFTWARE, + ShortcutType.HARDWARE, + ShortcutType.TRIPLETAP, + }) + + /** Denotes the shortcut type. */ + public @interface ShortcutType { + int DEFAULT = 0; + int SOFTWARE = 1; // 1 << 0 + int HARDWARE = 2; // 1 << 1 + int TRIPLETAP = 4; // 1 << 2 + } + + /** Denotes the accessibility enabled status */ + @Retention(RetentionPolicy.SOURCE) + public @interface State { + int OFF = 0; + int ON = 1; + } + /** * Return On/Off string according to the setting which specifies the integer value 1 or 0. This * setting is defined in the secure system settings {@link android.provider.Settings.Secure}. */ static CharSequence getSummary(Context context, String settingsSecureKey) { final boolean enabled = Settings.Secure.getInt(context.getContentResolver(), - settingsSecureKey, 0) == 1; + settingsSecureKey, State.OFF) == State.ON; final int resId = enabled ? R.string.accessibility_feature_state_on : R.string.accessibility_feature_state_off; return context.getResources().getText(resId); } + /** + * Capitalizes a string by capitalizing the first character and making the remaining characters + * lower case. + */ + public static String capitalize(String stringToCapitalize) { + if (stringToCapitalize == null) { + return null; + } + + StringBuilder capitalizedString = new StringBuilder(); + if (stringToCapitalize.length() > 0) { + capitalizedString.append(stringToCapitalize.substring(0, 1).toUpperCase()); + if (stringToCapitalize.length() > 1) { + capitalizedString.append(stringToCapitalize.substring(1).toLowerCase()); + } + } + return capitalizedString.toString(); + } + + /** Determines if a gesture navigation bar is being used. */ + public static boolean isGestureNavigateEnabled(Context context) { + return context.getResources().getInteger( + com.android.internal.R.integer.config_navBarInteractionMode) + == NAV_BAR_MODE_GESTURAL; + } + /** * Gets the corresponding fragment type of a given accessibility service * diff --git a/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java index a55f53a5561..4714fb39716 100644 --- a/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/LegacyAccessibilityServicePreferenceFragment.java @@ -21,6 +21,8 @@ import android.view.View; import androidx.preference.PreferenceScreen; +import com.android.settings.R; + /** For accessibility services that target SDK <= Q. */ public class LegacyAccessibilityServicePreferenceFragment extends ToggleAccessibilityServicePreferenceFragment { @@ -29,10 +31,13 @@ public class LegacyAccessibilityServicePreferenceFragment extends super.onViewCreated(view, savedInstanceState); final PreferenceScreen preferenceScreen = getPreferenceScreen(); - final ShortcutPreference preference = preferenceScreen.findPreference( + final ShortcutPreference shortcutPreference = preferenceScreen.findPreference( getShortcutPreferenceKey()); - if (preference != null) { - preference.setSettingsVisibility(View.GONE); + if (shortcutPreference != null) { + final CharSequence hardwareTitle = getPrefContext().getText( + R.string.accessibility_shortcut_edit_dialog_title_hardware); + shortcutPreference.setSummary(hardwareTitle); + shortcutPreference.setSettingsVisibility(View.GONE); } } } diff --git a/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java index 834e0c6dc8d..2b618cbb48e 100644 --- a/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; - import android.accessibilityservice.AccessibilityServiceInfo; import android.app.settings.SettingsEnums; import android.content.ComponentName; @@ -25,7 +23,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.os.Bundle; -import android.provider.SearchIndexableResource; import android.provider.Settings; import android.text.TextUtils; import android.view.accessibility.AccessibilityManager; @@ -36,12 +33,10 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.Indexable; import com.android.settings.search.actionbar.SearchMenuController; import com.android.settings.support.actionbar.HelpResourceProvider; import com.android.settingslib.search.SearchIndexable; -import java.util.Arrays; import java.util.List; @SearchIndexable @@ -134,7 +129,7 @@ public final class MagnificationPreferenceFragment extends DashboardFragment { if (info.getComponentName().equals(assignedComponentName)) { final CharSequence assignedServiceName = info.getResolveInfo().loadLabel( context.getPackageManager()); - final int messageId = isGestureNavigateEnabled(context) + final int messageId = AccessibilityUtil.isGestureNavigateEnabled(context) ? R.string.accessibility_screen_magnification_gesture_navigation_warning : R.string.accessibility_screen_magnification_navbar_configuration_warning; return context.getString(messageId, assignedServiceName); @@ -161,12 +156,6 @@ public final class MagnificationPreferenceFragment extends DashboardFragment { return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); } - private static boolean isGestureNavigateEnabled(Context context) { - return context.getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode) - == NAV_BAR_MODE_GESTURAL; - } - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.accessibility_magnification_settings) { diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 3248e009ccf..269bc0479fe 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; - import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Activity; import android.app.Dialog; @@ -43,17 +41,22 @@ import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; +import android.widget.CheckBox; import androidx.preference.PreferenceScreen; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; +import com.android.settings.accessibility.AccessibilityUtil.ShortcutType; import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.widget.SwitchBar; import com.android.settings.widget.ToggleSwitch; import com.android.settings.widget.ToggleSwitch.OnBeforeCheckedChangeListener; import com.android.settingslib.accessibility.AccessibilityUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.List; /** Fragment for providing toggle bar and basic accessibility service setup. */ @@ -61,22 +64,18 @@ public class ToggleAccessibilityServicePreferenceFragment extends ToggleFeaturePreferenceFragment implements ShortcutPreference.OnClickListener { private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; - private static final int DIALOG_ID_ENABLE_WARNING = 1; - private static final int DIALOG_ID_LAUNCH_ACCESSIBILITY_TUTORIAL = 2; - private static final int DIALOG_ID_EDIT_SHORTCUT = 3; + private static final String EXTRA_SHORTCUT_TYPE = "shortcutType"; + // TODO(b/142530063): Check the new setting key to decide which summary should be shown. + private static final String KEY_SHORTCUT_TYPE = Settings.System.MASTER_MONO; + private ShortcutPreference mShortcutPreference; + private int mShortcutType = ShortcutType.DEFAULT; + private CheckBox mSoftwareTypeCheckBox; + private CheckBox mHardwareTypeCheckBox; public static final int ACTIVITY_REQUEST_CONFIRM_CREDENTIAL_FOR_WEAKER_ENCRYPTION = 1; - private CharSequence mDialogTitle; - private LockPatternUtils mLockPatternUtils; - private final DialogInterface.OnClickListener mDialogListener = - (DialogInterface dialog, int id) -> { - if (id == DialogInterface.BUTTON_POSITIVE) { - // TODO(b/142531156): Save the shortcut type preference. - } - }; private final SettingsContentObserver mSettingsContentObserver = new SettingsContentObserver(new Handler()) { @@ -99,7 +98,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends } else { handleConfirmServiceEnabled(true); if (isServiceSupportAccessibilityButton()) { - showDialog(DIALOG_ID_LAUNCH_ACCESSIBILITY_TUTORIAL); + showDialog(DialogType.LAUNCH_ACCESSIBILITY_TUTORIAL); } } } else if (view.getId() == R.id.permission_enable_deny_button) { @@ -131,10 +130,16 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - initShortcutPreference(); + initShortcutPreference(savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(EXTRA_SHORTCUT_TYPE, mShortcutType); + super.onSaveInstanceState(outState); + } + @Override public void onResume() { mSettingsContentObserver.register(getContentResolver()); @@ -176,7 +181,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { - case DIALOG_ID_ENABLE_WARNING: { + case DialogType.ENABLE_WARNING: { final AccessibilityServiceInfo info = getAccessibilityServiceInfo(); if (info == null) { return null; @@ -185,8 +190,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends .createCapabilitiesDialog(getActivity(), info, mViewOnClickListener); break; } - case DIALOG_ID_LAUNCH_ACCESSIBILITY_TUTORIAL: { - if (isGestureNavigateEnabled()) { + case DialogType.LAUNCH_ACCESSIBILITY_TUTORIAL: { + if (AccessibilityUtil.isGestureNavigateEnabled(getContext())) { mDialog = AccessibilityGestureNavigationTutorial .showGestureNavigationTutorialDialog(getActivity()); } else { @@ -195,30 +200,129 @@ public class ToggleAccessibilityServicePreferenceFragment extends } break; } - case DIALOG_ID_EDIT_SHORTCUT: { + case DialogType.EDIT_SHORTCUT: { final CharSequence dialogTitle = getActivity().getString( R.string.accessibility_shortcut_edit_dialog_title, mDialogTitle); mDialog = AccessibilityEditDialogUtils.showEditShortcutDialog(getActivity(), - dialogTitle, mDialogListener); + dialogTitle, this::callOnAlertDialogCheckboxClicked); + initializeDialogCheckBox(mDialog); break; } default: { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Unsupported dialogId " + dialogId); } } return mDialog; } + private void initializeDialogCheckBox(Dialog dialog) { + final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut); + mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox); + final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut); + mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox); + updateAlertDialogCheckState(); + updateAlertDialogEnableState(); + } + + private void updateAlertDialogCheckState() { + updateCheckStatus(mSoftwareTypeCheckBox, ShortcutType.SOFTWARE); + updateCheckStatus(mHardwareTypeCheckBox, ShortcutType.HARDWARE); + } + + private void updateAlertDialogEnableState() { + if (!mSoftwareTypeCheckBox.isChecked()) { + mHardwareTypeCheckBox.setEnabled(false); + } else if (!mHardwareTypeCheckBox.isChecked()) { + mSoftwareTypeCheckBox.setEnabled(false); + } else { + mSoftwareTypeCheckBox.setEnabled(true); + mHardwareTypeCheckBox.setEnabled(true); + } + } + + private void updateCheckStatus(CheckBox checkBox, @ShortcutType int type) { + checkBox.setChecked((mShortcutType & type) == type); + checkBox.setOnClickListener(v -> { + updateShortcutType(false); + updateAlertDialogEnableState(); + }); + } + + private void updateShortcutType(boolean saveToDB) { + mShortcutType = ShortcutType.DEFAULT; + if (mSoftwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.SOFTWARE; + } + if (mHardwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.HARDWARE; + } + if (saveToDB) { + setShortcutType(mShortcutType); + } + } + + private void setSecureIntValue(String key, @ShortcutType int value) { + Settings.Secure.putIntForUser(getPrefContext().getContentResolver(), + key, value, getPrefContext().getContentResolver().getUserId()); + } + + private void setShortcutType(@ShortcutType int type) { + setSecureIntValue(KEY_SHORTCUT_TYPE, type); + } + + private String getShortcutTypeSummary(Context context) { + final int shortcutType = getShortcutType(context); + final CharSequence softwareTitle = + context.getText(AccessibilityUtil.isGestureNavigateEnabled(context) + ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture + : R.string.accessibility_shortcut_edit_dialog_title_software); + + List list = new ArrayList<>(); + if ((shortcutType & ShortcutType.SOFTWARE) == ShortcutType.SOFTWARE) { + list.add(softwareTitle); + } + if ((shortcutType & ShortcutType.HARDWARE) == ShortcutType.HARDWARE) { + final CharSequence hardwareTitle = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_hardware); + list.add(hardwareTitle); + } + + // Show software shortcut if first time to use. + if (list.isEmpty()) { + list.add(softwareTitle); + } + final String joinStrings = TextUtils.join(/* delimiter= */", ", list); + return AccessibilityUtil.capitalize(joinStrings); + } + + @ShortcutType + private int getShortcutType(Context context) { + return getSecureIntValue(context, KEY_SHORTCUT_TYPE, ShortcutType.SOFTWARE); + } + + @ShortcutType + private int getSecureIntValue(Context context, String key, @ShortcutType int defaultValue) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + key, defaultValue, context.getContentResolver().getUserId()); + } + + private void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) { + updateShortcutType(true); + mShortcutPreference.setSummary( + getShortcutTypeSummary(getPrefContext())); + } + @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { - case DIALOG_ID_ENABLE_WARNING: + case DialogType.ENABLE_WARNING: return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_ENABLE; - case DIALOG_ID_LAUNCH_ACCESSIBILITY_TUTORIAL: - return isGestureNavigateEnabled() + case DialogType.LAUNCH_ACCESSIBILITY_TUTORIAL: + return AccessibilityUtil.isGestureNavigateEnabled(getContext()) ? SettingsEnums.DIALOG_TOGGLE_SCREEN_GESTURE_NAVIGATION : SettingsEnums.DIALOG_TOGGLE_SCREEN_ACCESSIBILITY_BUTTON; - case DIALOG_ID_EDIT_SHORTCUT: + case DialogType.EDIT_SHORTCUT: return SettingsEnums.DIALOG_ACCESSIBILITY_SERVICE_EDIT_SHORTCUT; default: return 0; @@ -234,21 +338,29 @@ public class ToggleAccessibilityServicePreferenceFragment extends switchBar.setSwitchBarText(switchBarText, switchBarText); } - private void initShortcutPreference() { - final PreferenceScreen preferenceScreen = getPreferenceScreen(); - final ShortcutPreference shortcutPreference = new ShortcutPreference( - preferenceScreen.getContext(), null); - // Put the shortcutPreference before settingsPreference. - shortcutPreference.setPersistent(false); - shortcutPreference.setKey(getShortcutPreferenceKey()); - shortcutPreference.setOrder(-1); - shortcutPreference.setTitle(R.string.accessibility_shortcut_title); - shortcutPreference.setOnClickListener(this); + private void initShortcutPreference(Bundle savedInstanceState) { + // Restore the Shortcut type + if (savedInstanceState != null) { + mShortcutType = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, ShortcutType.DEFAULT); + } + if (mShortcutType == ShortcutType.DEFAULT) { + mShortcutType = getShortcutType(getPrefContext()); + } - // TODO(b/142530063): Check the new setting key to decide which summary should be shown. - // TODO(b/142530063): Check if gesture mode is on to decide which summary should be shown. + // Initial ShortcutPreference widget + final PreferenceScreen preferenceScreen = getPreferenceScreen(); + mShortcutPreference = new ShortcutPreference( + preferenceScreen.getContext(), null); + mShortcutPreference.setPersistent(false); + mShortcutPreference.setKey(getShortcutPreferenceKey()); + mShortcutPreference.setOrder(-1); + mShortcutPreference.setTitle(R.string.accessibility_shortcut_title); + mShortcutPreference.setOnClickListener(this); + mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); + // Put the shortcutPreference before settingsPreference. + mShortcutPreference.setOrder(-1); + preferenceScreen.addPreference(mShortcutPreference); // TODO(b/142530063): Check the new key to decide whether checkbox should be checked. - preferenceScreen.addPreference(shortcutPreference); } public String getShortcutPreferenceKey() { @@ -290,12 +402,6 @@ public class ToggleAccessibilityServicePreferenceFragment extends } } - private boolean isGestureNavigateEnabled() { - return getContext().getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode) - == NAV_BAR_MODE_GESTURAL; - } - private boolean isServiceSupportAccessibilityButton() { final AccessibilityManager ams = (AccessibilityManager) getContext().getSystemService( Context.ACCESSIBILITY_SERVICE); @@ -346,7 +452,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends if (checked) { mSwitchBar.setCheckedInternal(false); getArguments().putBoolean(AccessibilitySettings.EXTRA_CHECKED, false); - showDialog(DIALOG_ID_ENABLE_WARNING); + showDialog(DialogType.ENABLE_WARNING); } else { handleConfirmServiceEnabled(false); } @@ -366,7 +472,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public void onSettingsClicked(ShortcutPreference preference) { - showDialog(DIALOG_ID_EDIT_SHORTCUT); + mShortcutType = getShortcutType(getPrefContext()); + showDialog(DialogType.EDIT_SHORTCUT); } @Override @@ -402,4 +509,11 @@ public class ToggleAccessibilityServicePreferenceFragment extends mDialogTitle = getAccessibilityServiceInfo().getResolveInfo().loadLabel( getPackageManager()); } + + @Retention(RetentionPolicy.SOURCE) + private @interface DialogType { + int ENABLE_WARNING = 1; + int LAUNCH_ACCESSIBILITY_TUTORIAL = 2; + int EDIT_SHORTCUT = 3; + } } diff --git a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java index 880efb6d135..1c7a5f30a5a 100644 --- a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java @@ -18,26 +18,30 @@ package com.android.settings.accessibility; import android.app.Dialog; import android.app.settings.SettingsEnums; +import android.content.Context; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; import android.widget.Switch; +import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.accessibility.AccessibilityUtil.ShortcutType; +import com.android.settings.accessibility.AccessibilityUtil.State; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SwitchBar; import com.android.settingslib.search.SearchIndexable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -52,15 +56,15 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere private static final int DIALOG_ID_EDIT_SHORTCUT = 1; private static final String DISPLAY_INVERSION_ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; - private final DialogInterface.OnClickListener mDialogListener = - (DialogInterface dialog, int id) -> { - if (id == DialogInterface.BUTTON_POSITIVE) { - // TODO(b/142531156): Save the shortcut type preference. - } - }; + private static final String EXTRA_SHORTCUT_TYPE = "shortcutType"; + // TODO(b/142530063): Check the new setting key to decide which summary should be shown. + private static final String KEY_SHORTCUT_TYPE = Settings.System.MASTER_MONO; private final Handler mHandler = new Handler(); - private Dialog mDialog; + private ShortcutPreference mShortcutPreference; private SettingsContentObserver mSettingsContentObserver; + private int mShortcutType = ShortcutType.DEFAULT; + private CheckBox mSoftwareTypeCheckBox; + private CheckBox mHardwareTypeCheckBox; @Override public void onStart() { @@ -119,10 +123,10 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - initShortcutPreference(); - final List shortcutFeatureKeys = new ArrayList<>(1); - shortcutFeatureKeys.add(DISPLAY_INVERSION_ENABLED); - mSettingsContentObserver = new SettingsContentObserver(mHandler, shortcutFeatureKeys) { + initShortcutPreference(savedInstanceState); + final List enableServiceFeatureKeys = new ArrayList<>(/* initialCapacity= */ 1); + enableServiceFeatureKeys.add(DISPLAY_INVERSION_ENABLED); + mSettingsContentObserver = new SettingsContentObserver(mHandler, enableServiceFeatureKeys) { @Override public void onChange(boolean selfChange, Uri uri) { mSwitchBar.setCheckedInternal( @@ -133,16 +137,122 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere return super.onCreateView(inflater, container, savedInstanceState); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(EXTRA_SHORTCUT_TYPE, mShortcutType); + super.onSaveInstanceState(outState); + } + @Override public Dialog onCreateDialog(int dialogId) { if (dialogId == DIALOG_ID_EDIT_SHORTCUT) { final CharSequence dialogTitle = getActivity().getString( R.string.accessibility_shortcut_edit_dialog_title_daltonizer); - mDialog = AccessibilityEditDialogUtils.showEditShortcutDialog(getActivity(), - dialogTitle, mDialogListener); + final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog( + getActivity(), + dialogTitle, this::callOnAlertDialogCheckboxClicked); + initializeDialogCheckBox(dialog); + return dialog; + } + throw new IllegalArgumentException("Unsupported dialogId " + dialogId); + } + + private void initializeDialogCheckBox(AlertDialog dialog) { + final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut); + mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox); + final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut); + mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox); + updateAlertDialogCheckState(); + updateAlertDialogEnableState(); + } + + private void updateAlertDialogCheckState() { + updateCheckStatus(mSoftwareTypeCheckBox, ShortcutType.SOFTWARE); + updateCheckStatus(mHardwareTypeCheckBox, ShortcutType.HARDWARE); + } + + private void updateAlertDialogEnableState() { + if (!mSoftwareTypeCheckBox.isChecked()) { + mHardwareTypeCheckBox.setEnabled(false); + } else if (!mHardwareTypeCheckBox.isChecked()) { + mSoftwareTypeCheckBox.setEnabled(false); + } else { + mSoftwareTypeCheckBox.setEnabled(true); + mHardwareTypeCheckBox.setEnabled(true); + } + } + + private void updateCheckStatus(CheckBox checkBox, @ShortcutType int type) { + checkBox.setChecked((mShortcutType & type) == type); + checkBox.setOnClickListener(v -> { + updateShortcutType(false); + updateAlertDialogEnableState(); + }); + } + + private void updateShortcutType(boolean saveToDB) { + mShortcutType = ShortcutType.DEFAULT; + if (mSoftwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.SOFTWARE; + } + if (mHardwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.HARDWARE; + } + if (saveToDB) { + setShortcutType(mShortcutType); + } + } + + private void setSecureIntValue(String key, @ShortcutType int value) { + Settings.Secure.putIntForUser(getPrefContext().getContentResolver(), + key, value, getPrefContext().getContentResolver().getUserId()); + } + + private void setShortcutType(@ShortcutType int type) { + setSecureIntValue(KEY_SHORTCUT_TYPE, type); + } + + private String getShortcutTypeSummary(Context context) { + final int shortcutType = getShortcutType(context); + final CharSequence softwareTitle = + context.getText(AccessibilityUtil.isGestureNavigateEnabled(context) + ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture + : R.string.accessibility_shortcut_edit_dialog_title_software); + + List list = new ArrayList<>(); + if ((shortcutType & ShortcutType.SOFTWARE) == ShortcutType.SOFTWARE) { + list.add(softwareTitle); + } + if ((shortcutType & ShortcutType.HARDWARE) == ShortcutType.HARDWARE) { + final CharSequence hardwareTitle = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_hardware); + list.add(hardwareTitle); } - return mDialog; + // Show software shortcut if first time to use. + if (list.isEmpty()) { + list.add(softwareTitle); + } + final String joinStrings = TextUtils.join(/* delimiter= */", ", list); + return AccessibilityUtil.capitalize(joinStrings); + } + + @ShortcutType + private int getShortcutType(Context context) { + return getSecureIntValue(context, KEY_SHORTCUT_TYPE, ShortcutType.SOFTWARE); + } + + @ShortcutType + private int getSecureIntValue(Context context, String key, @ShortcutType int defaultValue) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + key, defaultValue, context.getContentResolver().getUserId()); + } + + private void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) { + updateShortcutType(true); + mShortcutPreference.setSummary( + getShortcutTypeSummary(getPrefContext())); } @Override @@ -153,21 +263,29 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere return 0; } - private void initShortcutPreference() { + private void initShortcutPreference(Bundle savedInstanceState) { + // Restore the Shortcut type + if (savedInstanceState != null) { + mShortcutType = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, ShortcutType.DEFAULT); + } + if (mShortcutType == ShortcutType.DEFAULT) { + mShortcutType = getShortcutType(getPrefContext()); + } + + // Initial ShortcutPreference widget final PreferenceScreen preferenceScreen = getPreferenceScreen(); - final ShortcutPreference shortcutPreference = new ShortcutPreference( + mShortcutPreference = new ShortcutPreference( preferenceScreen.getContext(), null); final Preference previewPreference = findPreference(PREVIEW_PREFERENCE_KEY); // Put the shortcutPreference before radioButtonPreference. - shortcutPreference.setPersistent(false); - shortcutPreference.setKey(getShortcutPreferenceKey()); - shortcutPreference.setOrder(previewPreference.getOrder() - 1); - shortcutPreference.setTitle(R.string.accessibility_shortcut_title); - shortcutPreference.setOnClickListener(this); - // TODO(b/142530063): Check the new setting key to decide which summary should be shown. - // TODO(b/142530063): Check if gesture mode is on to decide which summary should be shown. + mShortcutPreference.setPersistent(false); + mShortcutPreference.setKey(getShortcutPreferenceKey()); + mShortcutPreference.setTitle(R.string.accessibility_shortcut_title); + mShortcutPreference.setOnClickListener(this); + mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); + mShortcutPreference.setOrder(previewPreference.getOrder() - 1); + preferenceScreen.addPreference(mShortcutPreference); // TODO(b/142530063): Check the new key to decide whether checkbox should be checked. - preferenceScreen.addPreference(shortcutPreference); } public String getShortcutPreferenceKey() { @@ -185,15 +303,10 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere @Override public void onSettingsClicked(ShortcutPreference preference) { + mShortcutType = getShortcutType(getPrefContext()); showDialog(DIALOG_ID_EDIT_SHORTCUT); } - @Retention(RetentionPolicy.SOURCE) - private @interface State { - int OFF = 0; - int ON = 1; - } - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.accessibility_color_inversion_settings); } diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java index a4f3e62a987..7fb05da7fb0 100644 --- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java @@ -23,15 +23,20 @@ import android.content.DialogInterface; import android.content.res.Resources; import android.os.Bundle; import android.provider.Settings; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; import android.widget.Switch; +import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.accessibility.AccessibilityUtil.ShortcutType; +import com.android.settings.accessibility.AccessibilityUtil.State; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SwitchBar; import com.android.settingslib.core.AbstractPreferenceController; @@ -48,9 +53,16 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe SwitchBar.OnSwitchChangeListener, ShortcutPreference.OnClickListener { private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED; - private static final String RADIOPREFERENCE_KEY = "daltonizer_mode_deuteranomaly"; + private static final String PREFERENCE_KEY = "daltonizer_mode_deuteranomaly"; + private static final String EXTRA_SHORTCUT_TYPE = "shortcutType"; + // TODO(b/142530063): Check the new setting key to decide which summary should be shown. + private static final String KEY_SHORTCUT_TYPE = Settings.System.MASTER_MONO; private static final int DIALOG_ID_EDIT_SHORTCUT = 1; private static final List sControllers = new ArrayList<>(); + private ShortcutPreference mShortcutPreference; + private int mShortcutType = ShortcutType.DEFAULT; + private CheckBox mSoftwareTypeCheckBox; + private CheckBox mHardwareTypeCheckBox; private static List buildPreferenceControllers(Context context, Lifecycle lifecycle) { @@ -67,15 +79,6 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe return sControllers; } - private final DialogInterface.OnClickListener mDialogListener = - (DialogInterface dialog, int id) -> { - if (id == DialogInterface.BUTTON_POSITIVE) { - // TODO(b/142531156): Save the shortcut type preference. - } - }; - - private Dialog mDialog; - @Override public void onCheckedChanged(Preference preference) { for (AbstractPreferenceController controller : sControllers) { @@ -86,10 +89,16 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - initShortcutPreference(); + initShortcutPreference(savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(EXTRA_SHORTCUT_TYPE, mShortcutType); + super.onSaveInstanceState(outState); + } + @Override public void onResume() { super.onResume(); @@ -115,11 +124,111 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe if (dialogId == DIALOG_ID_EDIT_SHORTCUT) { final CharSequence dialogTitle = getActivity().getString( R.string.accessibility_shortcut_edit_dialog_title_daltonizer); - mDialog = AccessibilityEditDialogUtils.showEditShortcutDialog(getActivity(), - dialogTitle, mDialogListener); + final AlertDialog dialog = AccessibilityEditDialogUtils.showEditShortcutDialog( + getActivity(), + dialogTitle, this::callOnAlertDialogCheckboxClicked); + initializeDialogCheckBox(dialog); + return dialog; + } + throw new IllegalArgumentException("Unsupported dialogId " + dialogId); + } + + private void initializeDialogCheckBox(AlertDialog dialog) { + final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut); + mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox); + final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut); + mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox); + updateAlertDialogCheckState(); + updateAlertDialogEnableState(); + } + + private void updateAlertDialogCheckState() { + updateCheckStatus(mSoftwareTypeCheckBox, ShortcutType.SOFTWARE); + updateCheckStatus(mHardwareTypeCheckBox, ShortcutType.HARDWARE); + } + + private void updateAlertDialogEnableState() { + if (!mSoftwareTypeCheckBox.isChecked()) { + mHardwareTypeCheckBox.setEnabled(false); + } else if (!mHardwareTypeCheckBox.isChecked()) { + mSoftwareTypeCheckBox.setEnabled(false); + } else { + mSoftwareTypeCheckBox.setEnabled(true); + mHardwareTypeCheckBox.setEnabled(true); + } + } + + private void updateCheckStatus(CheckBox checkBox, @ShortcutType int type) { + checkBox.setChecked((mShortcutType & type) == type); + checkBox.setOnClickListener(v -> { + updateShortcutType(false); + updateAlertDialogEnableState(); + }); + } + + private void updateShortcutType(boolean saveToDB) { + mShortcutType = ShortcutType.DEFAULT; + if (mSoftwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.SOFTWARE; + } + if (mHardwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.HARDWARE; + } + if (saveToDB) { + setShortcutType(mShortcutType); + } + } + + private void setSecureIntValue(String key, @ShortcutType int value) { + Settings.Secure.putIntForUser(getPrefContext().getContentResolver(), + key, value, getPrefContext().getContentResolver().getUserId()); + } + + private void setShortcutType(@ShortcutType int type) { + setSecureIntValue(KEY_SHORTCUT_TYPE, type); + } + + private String getShortcutTypeSummary(Context context) { + final int shortcutType = getShortcutType(context); + final CharSequence softwareTitle = + context.getText(AccessibilityUtil.isGestureNavigateEnabled(context) + ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture + : R.string.accessibility_shortcut_edit_dialog_title_software); + + List list = new ArrayList<>(); + if ((shortcutType & ShortcutType.SOFTWARE) == ShortcutType.SOFTWARE) { + list.add(softwareTitle); + } + if ((shortcutType & ShortcutType.HARDWARE) == ShortcutType.HARDWARE) { + final CharSequence hardwareTitle = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_hardware); + list.add(hardwareTitle); } - return mDialog; + // Show software shortcut if first time to use. + if (list.isEmpty()) { + list.add(softwareTitle); + } + final String joinStrings = TextUtils.join(/* delimiter= */", ", list); + return AccessibilityUtil.capitalize(joinStrings); + } + + @ShortcutType + private int getShortcutType(Context context) { + return getSecureIntValue(context, KEY_SHORTCUT_TYPE, ShortcutType.SOFTWARE); + } + + @ShortcutType + private int getSecureIntValue(Context context, String key, @ShortcutType int defaultValue) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + key, defaultValue, context.getContentResolver().getUserId()); + } + + private void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) { + updateShortcutType(true); + mShortcutPreference.setSummary( + getShortcutTypeSummary(getPrefContext())); } @Override @@ -147,7 +256,7 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe @Override protected void onPreferenceToggled(String preferenceKey, boolean enabled) { - Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? 0 : 1); + Settings.Secure.putInt(getContentResolver(), ENABLED, enabled ? State.OFF : State.ON); } @Override @@ -165,14 +274,14 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe @Override public void onSwitchChanged(Switch switchView, boolean isChecked) { - Settings.Secure.putInt(getContentResolver(), ENABLED, isChecked ? 1 : 0); + Settings.Secure.putInt(getContentResolver(), ENABLED, isChecked ? State.ON : State.OFF); } @Override protected void onInstallSwitchBarToggleSwitch() { super.onInstallSwitchBarToggleSwitch(); mSwitchBar.setCheckedInternal( - Settings.Secure.getInt(getContentResolver(), ENABLED, 0) == 1); + Settings.Secure.getInt(getContentResolver(), ENABLED, State.OFF) == State.ON); mSwitchBar.addOnSwitchChangeListener(this); } @@ -187,22 +296,31 @@ public final class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePrefe @Override public void onSettingsClicked(ShortcutPreference preference) { + mShortcutType = getShortcutType(getPrefContext()); showDialog(DIALOG_ID_EDIT_SHORTCUT); } - private void initShortcutPreference() { + private void initShortcutPreference(Bundle savedInstanceState) { + // Restore the Shortcut type + if (savedInstanceState != null) { + mShortcutType = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, ShortcutType.DEFAULT); + } + if (mShortcutType == ShortcutType.DEFAULT) { + mShortcutType = getShortcutType(getPrefContext()); + } + + // Initial ShortcutPreference widget final PreferenceScreen preferenceScreen = getPreferenceScreen(); - final ShortcutPreference shortcutPreference = new ShortcutPreference( + mShortcutPreference = new ShortcutPreference( preferenceScreen.getContext(), null); - final RadioButtonPreference radioButtonPreference = findPreference(RADIOPREFERENCE_KEY); + mShortcutPreference.setTitle(R.string.accessibility_shortcut_title); + mShortcutPreference.setOnClickListener(this); + mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); // Put the shortcutPreference before radioButtonPreference. - shortcutPreference.setOrder(radioButtonPreference.getOrder() - 1); - shortcutPreference.setTitle(R.string.accessibility_shortcut_title); - // TODO(b/142530063): Check the new setting key to decide which summary should be shown. - // TODO(b/142530063): Check if gesture mode is on to decide which summary should be shown. + final RadioButtonPreference radioButtonPreference = findPreference(PREFERENCE_KEY); + mShortcutPreference.setOrder(radioButtonPreference.getOrder() - 1); + preferenceScreen.addPreference(mShortcutPreference); // TODO(b/142530063): Check the new key to decide whether checkbox should be checked. - shortcutPreference.setOnClickListener(this); - preferenceScreen.addPreference(shortcutPreference); } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index 2111f9ed589..515d80c35c1 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -16,15 +16,12 @@ package com.android.settings.accessibility; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; - import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; -import android.graphics.Point; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnPreparedListener; @@ -32,41 +29,43 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; -import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.view.WindowManager; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.RelativeLayout.LayoutParams; import android.widget.Switch; import android.widget.VideoView; +import androidx.appcompat.app.AlertDialog; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; +import com.android.settings.accessibility.AccessibilityUtil.ShortcutType; import com.android.settings.widget.SwitchBar; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + public class ToggleScreenMagnificationPreferenceFragment extends ToggleFeaturePreferenceFragment implements SwitchBar.OnSwitchChangeListener, ShortcutPreference.OnClickListener { private static final String SETTINGS_KEY = "screen_magnification_settings"; - private static final int DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL = 1; - private static final int DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL = 2; - private static final int DIALOG_ID_EDIT_SHORTCUT = 3; - - private final DialogInterface.OnClickListener mDialogListener = - (DialogInterface dialog, int id) -> { - if (id == DialogInterface.BUTTON_POSITIVE) { - // TODO(b/142531156): Save the shortcut type preference. - } - }; - - private Dialog mDialog; + private static final String EXTRA_SHORTCUT_TYPE = "shortcutType"; + // TODO(b/142530063): Check the new setting key to decide which summary should be shown. + private static final String KEY_SHORTCUT_TYPE = Settings.System.MASTER_MONO; + private ShortcutPreference mShortcutPreference; + private int mShortcutType = ShortcutType.DEFAULT; + private CheckBox mSoftwareTypeCheckBox; + private CheckBox mHardwareTypeCheckBox; + private CheckBox mTripleTapTypeCheckBox; protected class VideoPreference extends Preference { private ImageView mVideoBackgroundView; @@ -147,9 +146,6 @@ public class ToggleScreenMagnificationPreferenceFragment extends protected VideoPreference mVideoPreference; protected Preference mConfigWarningPreference; - private boolean mLaunchFromSuw = false; - private boolean mInitialSetting = false; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -185,10 +181,16 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - initShortcutPreference(); + initShortcutPreference(savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(EXTRA_SHORTCUT_TYPE, mShortcutType); + super.onSaveInstanceState(outState); + } + @Override public void onResume() { super.onResume(); @@ -204,25 +206,142 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public Dialog onCreateDialog(int dialogId) { switch (dialogId) { - case DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL: - mDialog = AccessibilityGestureNavigationTutorial + case DialogType.GESTURE_NAVIGATION_TUTORIAL: + return AccessibilityGestureNavigationTutorial .showGestureNavigationTutorialDialog(getActivity()); - break; - case DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL: - mDialog = AccessibilityGestureNavigationTutorial + case DialogType.ACCESSIBILITY_BUTTON_TUTORIAL: + return AccessibilityGestureNavigationTutorial .showAccessibilityButtonTutorialDialog(getActivity()); - break; - case DIALOG_ID_EDIT_SHORTCUT: + case DialogType.EDIT_SHORTCUT: final CharSequence dialogTitle = getActivity().getString( R.string.accessibility_shortcut_edit_dialog_title_magnification); - mDialog = AccessibilityEditDialogUtils.showMagnificationEditShortcutDialog( - getActivity(), dialogTitle, mDialogListener); - break; - default: - throw new IllegalArgumentException(); + final AlertDialog dialog = + AccessibilityEditDialogUtils.showMagnificationEditShortcutDialog( + getActivity(), dialogTitle, this::callOnAlertDialogCheckboxClicked); + initializeDialogCheckBox(dialog); + return dialog; + } + throw new IllegalArgumentException("Unsupported dialogId " + dialogId); + } + + private void initializeDialogCheckBox(AlertDialog dialog) { + final View dialogSoftwareView = dialog.findViewById(R.id.software_shortcut); + mSoftwareTypeCheckBox = dialogSoftwareView.findViewById(R.id.checkbox); + final View dialogHardwareView = dialog.findViewById(R.id.hardware_shortcut); + mHardwareTypeCheckBox = dialogHardwareView.findViewById(R.id.checkbox); + final View dialogTripleTapView = dialog.findViewById(R.id.triple_tap_shortcut); + mTripleTapTypeCheckBox = dialogTripleTapView.findViewById(R.id.checkbox); + final View advancedView = dialog.findViewById(R.id.advanced_shortcut); + updateAlertDialogCheckState(); + updateAlertDialogEnableState(); + + // Shows the triple tap checkbox directly if clicked. + if (mTripleTapTypeCheckBox.isChecked()) { + advancedView.setVisibility(View.GONE); + dialogTripleTapView.setVisibility(View.VISIBLE); + } + } + + private void updateAlertDialogCheckState() { + updateCheckStatus(mSoftwareTypeCheckBox, ShortcutType.SOFTWARE); + updateCheckStatus(mHardwareTypeCheckBox, ShortcutType.HARDWARE); + updateCheckStatus(mTripleTapTypeCheckBox, ShortcutType.TRIPLETAP); + } + + private void updateAlertDialogEnableState() { + if (!mSoftwareTypeCheckBox.isChecked() && !mTripleTapTypeCheckBox.isChecked()) { + mHardwareTypeCheckBox.setEnabled(false); + } else if (!mHardwareTypeCheckBox.isChecked() && !mTripleTapTypeCheckBox.isChecked()) { + mSoftwareTypeCheckBox.setEnabled(false); + } else if (!mSoftwareTypeCheckBox.isChecked() && !mHardwareTypeCheckBox.isChecked()) { + mTripleTapTypeCheckBox.setEnabled(false); + } else { + mSoftwareTypeCheckBox.setEnabled(true); + mHardwareTypeCheckBox.setEnabled(true); + mTripleTapTypeCheckBox.setEnabled(true); + } + } + + private void updateCheckStatus(CheckBox checkBox, @ShortcutType int type) { + checkBox.setChecked((mShortcutType & type) == type); + checkBox.setOnClickListener(v -> { + updateShortcutType(false); + updateAlertDialogEnableState(); + }); + } + + private void updateShortcutType(boolean saveToDB) { + mShortcutType = ShortcutType.DEFAULT; + if (mSoftwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.SOFTWARE; + } + if (mHardwareTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.HARDWARE; + } + if (mTripleTapTypeCheckBox.isChecked()) { + mShortcutType |= ShortcutType.TRIPLETAP; + } + if (saveToDB) { + setShortcutType(mShortcutType); + } + } + + private void setSecureIntValue(String key, @ShortcutType int value) { + Settings.Secure.putIntForUser(getPrefContext().getContentResolver(), + key, value, getPrefContext().getContentResolver().getUserId()); + } + + private void setShortcutType(@ShortcutType int type) { + setSecureIntValue(KEY_SHORTCUT_TYPE, type); + } + + private String getShortcutTypeSummary(Context context) { + final int shortcutType = getShortcutType(context); + final CharSequence softwareTitle = + context.getText(AccessibilityUtil.isGestureNavigateEnabled(context) + ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture + : R.string.accessibility_shortcut_edit_dialog_title_software); + + List list = new ArrayList<>(); + if ((shortcutType & ShortcutType.SOFTWARE) == ShortcutType.SOFTWARE) { + list.add(softwareTitle); + } + if ((shortcutType & ShortcutType.HARDWARE) == ShortcutType.HARDWARE) { + final CharSequence hardwareTitle = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_hardware); + list.add(hardwareTitle); } - return mDialog; + if ((shortcutType & ShortcutType.TRIPLETAP) == ShortcutType.TRIPLETAP) { + final CharSequence tripleTapTitle = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_triple_tap); + list.add(tripleTapTitle); + } + + // Show software shortcut if first time to use. + if (list.isEmpty()) { + list.add(softwareTitle); + } + final String joinStrings = TextUtils.join(/* delimiter= */", ", list); + return AccessibilityUtil.capitalize(joinStrings); + } + + @ShortcutType + private int getShortcutType(Context context) { + return getSecureIntValue(context, KEY_SHORTCUT_TYPE, ShortcutType.SOFTWARE); + } + + @ShortcutType + private int getSecureIntValue(Context context, String key, @ShortcutType int defaultValue) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + key, defaultValue, context.getContentResolver().getUserId()); + } + + private void callOnAlertDialogCheckboxClicked(DialogInterface dialog, int which) { + updateShortcutType(true); + mShortcutPreference.setSummary( + getShortcutTypeSummary(getPrefContext())); } @Override @@ -234,11 +353,11 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public int getDialogMetricsCategory(int dialogId) { switch (dialogId) { - case DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL: + case DialogType.GESTURE_NAVIGATION_TUTORIAL: return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION; - case DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL: + case DialogType.ACCESSIBILITY_BUTTON_TUTORIAL: return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_ACCESSIBILITY_BUTTON; - case DIALOG_ID_EDIT_SHORTCUT: + case DialogType.EDIT_SHORTCUT: return SettingsEnums.DIALOG_MAGNIFICATION_EDIT_SHORTCUT; default: return 0; @@ -255,8 +374,9 @@ public class ToggleScreenMagnificationPreferenceFragment extends if (enabled && TextUtils.equals( Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, preferenceKey)) { - showDialog(isGestureNavigateEnabled() ? DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL - : DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL); + showDialog(AccessibilityUtil.isGestureNavigateEnabled(getContext()) + ? DialogType.GESTURE_NAVIGATION_TUTORIAL + : DialogType.ACCESSIBILITY_BUTTON_TUTORIAL); } MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled); updateConfigurationWarningIfNeeded(); @@ -293,20 +413,10 @@ public class ToggleScreenMagnificationPreferenceFragment extends if (arguments.containsKey(AccessibilitySettings.EXTRA_VIDEO_RAW_RESOURCE_ID)) { mVideoPreference.setVisible(true); - final int resId = arguments.getInt( - AccessibilitySettings.EXTRA_VIDEO_RAW_RESOURCE_ID); } else { mVideoPreference.setVisible(false); } - if (arguments.containsKey(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW)) { - mLaunchFromSuw = arguments.getBoolean(AccessibilitySettings.EXTRA_LAUNCHED_FROM_SUW); - } - - if (arguments.containsKey(AccessibilitySettings.EXTRA_CHECKED)) { - mInitialSetting = arguments.getBoolean(AccessibilitySettings.EXTRA_CHECKED); - } - if (arguments.containsKey(AccessibilitySettings.EXTRA_TITLE_RES)) { final int titleRes = arguments.getInt(AccessibilitySettings.EXTRA_TITLE_RES); if (titleRes > 0) { @@ -326,27 +436,30 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onSettingsClicked(ShortcutPreference preference) { - showDialog(DIALOG_ID_EDIT_SHORTCUT); + mShortcutType = getShortcutType(getPrefContext()); + showDialog(DialogType.EDIT_SHORTCUT); } - private void initShortcutPreference() { + private void initShortcutPreference(Bundle savedInstanceState) { + // Restore the Shortcut type + if (savedInstanceState != null) { + mShortcutType = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, ShortcutType.DEFAULT); + } + if (mShortcutType == ShortcutType.DEFAULT) { + mShortcutType = getShortcutType(getPrefContext()); + } + + // Initial ShortcutPreference widget final PreferenceScreen preferenceScreen = getPreferenceScreen(); - final ShortcutPreference shortcutPreference = new ShortcutPreference( + mShortcutPreference = new ShortcutPreference( preferenceScreen.getContext(), null); + mShortcutPreference.setTitle(R.string.accessibility_magnification_shortcut_title); + mShortcutPreference.setOnClickListener(this); + mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); // Put the shortcutPreference before videoPreference. - shortcutPreference.setOrder(mVideoPreference.getOrder() - 1); - shortcutPreference.setTitle(R.string.accessibility_magnification_shortcut_title); - shortcutPreference.setOnClickListener(this); - // TODO(b/142530063): Check the new setting key to decide which summary should be shown. - // TODO(b/142530063): Check if gesture mode is on to decide which summary should be shown. + mShortcutPreference.setOrder(mVideoPreference.getOrder() - 1); + preferenceScreen.addPreference(mShortcutPreference); // TODO(b/142530063): Check the new key to decide whether checkbox should be checked. - preferenceScreen.addPreference(shortcutPreference); - } - - private boolean isGestureNavigateEnabled() { - return getContext().getResources().getInteger( - com.android.internal.R.integer.config_navBarInteractionMode) - == NAV_BAR_MODE_GESTURAL; } private void updateConfigurationWarningIfNeeded() { @@ -359,11 +472,11 @@ public class ToggleScreenMagnificationPreferenceFragment extends mConfigWarningPreference.setVisible(warningMessage != null); } - private static int getScreenWidth(Context context) { - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); - return size.x; + @Retention(RetentionPolicy.SOURCE) + private @interface DialogType { + int GESTURE_NAVIGATION_TUTORIAL = 1; + int ACCESSIBILITY_BUTTON_TUTORIAL = 2; + int EDIT_SHORTCUT = 3; } + } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java index 27db431ec73..2ccfd056e5f 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java @@ -53,6 +53,16 @@ public final class AccessibilityUtilTest { mContext = RuntimeEnvironment.application; } + @Test + public void capitalize_shouldReturnCapitalizedString() { + assertThat(AccessibilityUtil.capitalize(null)).isNull(); + assertThat(AccessibilityUtil.capitalize("")).isEmpty(); + assertThat(AccessibilityUtil.capitalize("Hans")).isEqualTo("Hans"); + assertThat(AccessibilityUtil.capitalize("hans")).isEqualTo("Hans"); + assertThat(AccessibilityUtil.capitalize(",hans")).isEqualTo(",hans"); + assertThat(AccessibilityUtil.capitalize("Hans, Hans")).isEqualTo("Hans, hans"); + } + @Test public void getSummary_hasValueAndEqualsToOne_shouldReturnOnString() { Settings.Secure.putInt(mContext.getContentResolver(), SECURE_TEST_KEY, ON); @@ -90,7 +100,6 @@ public final class AccessibilityUtilTest { assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( AccessibilityUtil.AccessibilityServiceFragmentType.LEGACY); - } @Test @@ -102,7 +111,6 @@ public final class AccessibilityUtilTest { assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( AccessibilityUtil.AccessibilityServiceFragmentType.INVISIBLE); - } @Test @@ -114,7 +122,6 @@ public final class AccessibilityUtilTest { assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo( AccessibilityUtil.AccessibilityServiceFragmentType.INTUITIVE); - }