Loading src/com/android/settings/accessibility/PreferredShortcuts.java +42 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,17 @@ package com.android.settings.accessibility; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; import android.os.UserHandle; import android.util.ArrayMap; import androidx.annotation.NonNull; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; import java.util.HashSet; import java.util.Map; import java.util.Set; /** Static utility methods relating to {@link PreferredShortcut} */ Loading Loading @@ -80,6 +87,41 @@ public final class PreferredShortcuts { saveToSharedPreferences(context, info); } /** * Update the user preferred shortcut from Settings data * * @param context {@link Context} to access the {@link SharedPreferences} * @param components contains a set of {@link ComponentName} the service or activity. The * string * representation of the ComponentName should be in the format of * {@link ComponentName#flattenToString()}. */ public static void updatePreferredShortcutsFromSettings( @NonNull Context context, @NonNull Set<String> components) { final Map<Integer, Set<String>> shortcutTypeToTargets = new ArrayMap<>(); for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) { shortcutTypeToTargets.put( shortcutType, ShortcutUtils.getShortcutTargetsFromSettings( context, shortcutType, UserHandle.myUserId())); } for (String target : components) { int shortcutTypes = ShortcutConstants.UserShortcutType.DEFAULT; for (Map.Entry<Integer, Set<String>> entry : shortcutTypeToTargets.entrySet()) { if (entry.getValue().contains(target)) { shortcutTypes |= entry.getKey(); } } if (shortcutTypes != ShortcutConstants.UserShortcutType.DEFAULT) { final PreferredShortcut shortcut = new PreferredShortcut( target, shortcutTypes); PreferredShortcuts.saveUserShortcutType(context, shortcut); } } } /** * Returns a immutable set of {@link PreferredShortcut#toString()} list from * SharedPreferences. Loading src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java +5 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.accessibility.AccessibilitySetupWizardUtils; import com.android.settings.accessibility.PreferredShortcuts; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.core.AbstractPreferenceController; Loading Loading @@ -161,6 +162,9 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { } else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) { refreshPreferenceController(TwoFingersDoubleTapShortcutOptionController.class); } PreferredShortcuts.updatePreferredShortcutsFromSettings( getContext(), mShortcutTargets); } }; Loading Loading @@ -212,6 +216,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { final AccessibilityManager am = getSystemService( AccessibilityManager.class); am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); PreferredShortcuts.updatePreferredShortcutsFromSettings(getContext(), mShortcutTargets); } @Override Loading tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java +45 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.accessibility.AccessibilityUtil; import com.android.settings.accessibility.PreferredShortcuts; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; Loading Loading @@ -369,6 +370,50 @@ public class EditShortcutsPreferenceFragmentTest { }); } @Test public void fragmentResumed_preferredShortcutsUpdated() { mFragmentScenario = createFragScenario(/* isInSuw= */ false); mFragmentScenario.moveToState(Lifecycle.State.RESUMED); // Move the fragment to the background mFragmentScenario.moveToState(Lifecycle.State.CREATED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); // Update the chosen shortcut type to Volume keys while the fragment is in the background ShortcutUtils.optInValueToSettings( mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET); mFragmentScenario.moveToState(Lifecycle.State.RESUMED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE); } @Test public void onVolumeKeysShortcutSettingChanged_preferredShortcutsUpdated() { mFragmentScenario = createFragScenario(/* isInSuw= */ false); mFragmentScenario.moveToState(Lifecycle.State.CREATED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); ShortcutUtils.optInValueToSettings( mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET); // Calls onFragment so that the change to Setting is notified to its observer mFragmentScenario.onFragment(fragment -> assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE) ); } private void assertLaunchSubSettingWithCurrentTargetComponents( String componentName, boolean isInSuw) { Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity(); Loading tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java +110 −1 Original line number Diff line number Diff line Loading @@ -16,17 +16,30 @@ package com.android.settings.accessibility; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.google.common.truth.Truth.assertThat; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Set; /** Tests for {@link PreferredShortcuts} */ @RunWith(AndroidJUnit4.class) public class PreferredShortcutsTest { Loading @@ -39,8 +52,20 @@ public class PreferredShortcutsTest { private static final String CLASS_NAME_2 = PACKAGE_NAME_2 + ".test2"; private static final ComponentName COMPONENT_NAME_2 = new ComponentName(PACKAGE_NAME_2, CLASS_NAME_2); private static final ContentResolver sContentResolver = ApplicationProvider.getApplicationContext().getContentResolver(); private final Context mContext = ApplicationProvider.getApplicationContext(); private Context mContext = ApplicationProvider.getApplicationContext(); @Before public void setUp() { clearShortcuts(); } @AfterClass public static void cleanUp() { clearShortcuts(); } @Test public void retrieveUserShortcutType_fromSingleData_matchSavedType() { Loading Loading @@ -71,4 +96,88 @@ public class PreferredShortcutsTest { assertThat(retrieveType).isEqualTo(type1); } @Test public void updatePreferredShortcutsFromSetting_magnificationWithTripleTapAndVolumeKeyShortcuts_preferredShortcutsMatches() { ShortcutUtils.optInValueToSettings(mContext, ShortcutConstants.UserShortcutType.HARDWARE, MAGNIFICATION_CONTROLLER_NAME); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, AccessibilityUtil.State.ON); PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(MAGNIFICATION_CONTROLLER_NAME)); int expectedShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.TRIPLETAP; assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, MAGNIFICATION_CONTROLLER_NAME, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(expectedShortcutTypes); } @Test public void updatePreferredShortcutsFromSetting_magnificationWithNoActiveShortcuts_noChangesOnPreferredShortcutTypes() { int expectedShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.SOFTWARE; PreferredShortcuts.saveUserShortcutType(mContext, new PreferredShortcut(MAGNIFICATION_CONTROLLER_NAME, expectedShortcutTypes)); PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(MAGNIFICATION_CONTROLLER_NAME)); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, MAGNIFICATION_CONTROLLER_NAME, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(expectedShortcutTypes); } @Test public void updatePreferredShortcutsFromSetting_multipleComponents_preferredShortcutsMatches() { String target1 = COLOR_INVERSION_COMPONENT_NAME.flattenToString(); String target2 = DALTONIZER_COMPONENT_NAME.flattenToString(); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, target1); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, target1 + ShortcutConstants.SERVICES_SEPARATOR + target2); int target1ShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.SOFTWARE; int target2ShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE; PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(target1, target2)); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, target1, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(target1ShortcutTypes); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, target2, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(target2ShortcutTypes); } private static void clearShortcuts() { Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, AccessibilityUtil.State.OFF); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, AccessibilityUtil.State.OFF); } } Loading
src/com/android/settings/accessibility/PreferredShortcuts.java +42 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,17 @@ package com.android.settings.accessibility; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; import android.os.UserHandle; import android.util.ArrayMap; import androidx.annotation.NonNull; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; import java.util.HashSet; import java.util.Map; import java.util.Set; /** Static utility methods relating to {@link PreferredShortcut} */ Loading Loading @@ -80,6 +87,41 @@ public final class PreferredShortcuts { saveToSharedPreferences(context, info); } /** * Update the user preferred shortcut from Settings data * * @param context {@link Context} to access the {@link SharedPreferences} * @param components contains a set of {@link ComponentName} the service or activity. The * string * representation of the ComponentName should be in the format of * {@link ComponentName#flattenToString()}. */ public static void updatePreferredShortcutsFromSettings( @NonNull Context context, @NonNull Set<String> components) { final Map<Integer, Set<String>> shortcutTypeToTargets = new ArrayMap<>(); for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) { shortcutTypeToTargets.put( shortcutType, ShortcutUtils.getShortcutTargetsFromSettings( context, shortcutType, UserHandle.myUserId())); } for (String target : components) { int shortcutTypes = ShortcutConstants.UserShortcutType.DEFAULT; for (Map.Entry<Integer, Set<String>> entry : shortcutTypeToTargets.entrySet()) { if (entry.getValue().contains(target)) { shortcutTypes |= entry.getKey(); } } if (shortcutTypes != ShortcutConstants.UserShortcutType.DEFAULT) { final PreferredShortcut shortcut = new PreferredShortcut( target, shortcutTypes); PreferredShortcuts.saveUserShortcutType(context, shortcut); } } } /** * Returns a immutable set of {@link PreferredShortcut#toString()} list from * SharedPreferences. Loading
src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java +5 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.accessibility.AccessibilitySetupWizardUtils; import com.android.settings.accessibility.PreferredShortcuts; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.core.AbstractPreferenceController; Loading Loading @@ -161,6 +162,9 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { } else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) { refreshPreferenceController(TwoFingersDoubleTapShortcutOptionController.class); } PreferredShortcuts.updatePreferredShortcutsFromSettings( getContext(), mShortcutTargets); } }; Loading Loading @@ -212,6 +216,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { final AccessibilityManager am = getSystemService( AccessibilityManager.class); am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); PreferredShortcuts.updatePreferredShortcutsFromSettings(getContext(), mShortcutTargets); } @Override Loading
tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java +45 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.accessibility.AccessibilityUtil; import com.android.settings.accessibility.PreferredShortcuts; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; Loading Loading @@ -369,6 +370,50 @@ public class EditShortcutsPreferenceFragmentTest { }); } @Test public void fragmentResumed_preferredShortcutsUpdated() { mFragmentScenario = createFragScenario(/* isInSuw= */ false); mFragmentScenario.moveToState(Lifecycle.State.RESUMED); // Move the fragment to the background mFragmentScenario.moveToState(Lifecycle.State.CREATED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); // Update the chosen shortcut type to Volume keys while the fragment is in the background ShortcutUtils.optInValueToSettings( mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET); mFragmentScenario.moveToState(Lifecycle.State.RESUMED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE); } @Test public void onVolumeKeysShortcutSettingChanged_preferredShortcutsUpdated() { mFragmentScenario = createFragScenario(/* isInSuw= */ false); mFragmentScenario.moveToState(Lifecycle.State.CREATED); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); ShortcutUtils.optInValueToSettings( mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET); // Calls onFragment so that the change to Setting is notified to its observer mFragmentScenario.onFragment(fragment -> assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, TARGET, ShortcutConstants.UserShortcutType.SOFTWARE) ).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE) ); } private void assertLaunchSubSettingWithCurrentTargetComponents( String componentName, boolean isInSuw) { Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity(); Loading
tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java +110 −1 Original line number Diff line number Diff line Loading @@ -16,17 +16,30 @@ package com.android.settings.accessibility; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.google.common.truth.Truth.assertThat; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.util.ShortcutUtils; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Set; /** Tests for {@link PreferredShortcuts} */ @RunWith(AndroidJUnit4.class) public class PreferredShortcutsTest { Loading @@ -39,8 +52,20 @@ public class PreferredShortcutsTest { private static final String CLASS_NAME_2 = PACKAGE_NAME_2 + ".test2"; private static final ComponentName COMPONENT_NAME_2 = new ComponentName(PACKAGE_NAME_2, CLASS_NAME_2); private static final ContentResolver sContentResolver = ApplicationProvider.getApplicationContext().getContentResolver(); private final Context mContext = ApplicationProvider.getApplicationContext(); private Context mContext = ApplicationProvider.getApplicationContext(); @Before public void setUp() { clearShortcuts(); } @AfterClass public static void cleanUp() { clearShortcuts(); } @Test public void retrieveUserShortcutType_fromSingleData_matchSavedType() { Loading Loading @@ -71,4 +96,88 @@ public class PreferredShortcutsTest { assertThat(retrieveType).isEqualTo(type1); } @Test public void updatePreferredShortcutsFromSetting_magnificationWithTripleTapAndVolumeKeyShortcuts_preferredShortcutsMatches() { ShortcutUtils.optInValueToSettings(mContext, ShortcutConstants.UserShortcutType.HARDWARE, MAGNIFICATION_CONTROLLER_NAME); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, AccessibilityUtil.State.ON); PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(MAGNIFICATION_CONTROLLER_NAME)); int expectedShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.TRIPLETAP; assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, MAGNIFICATION_CONTROLLER_NAME, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(expectedShortcutTypes); } @Test public void updatePreferredShortcutsFromSetting_magnificationWithNoActiveShortcuts_noChangesOnPreferredShortcutTypes() { int expectedShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.SOFTWARE; PreferredShortcuts.saveUserShortcutType(mContext, new PreferredShortcut(MAGNIFICATION_CONTROLLER_NAME, expectedShortcutTypes)); PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(MAGNIFICATION_CONTROLLER_NAME)); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, MAGNIFICATION_CONTROLLER_NAME, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(expectedShortcutTypes); } @Test public void updatePreferredShortcutsFromSetting_multipleComponents_preferredShortcutsMatches() { String target1 = COLOR_INVERSION_COMPONENT_NAME.flattenToString(); String target2 = DALTONIZER_COMPONENT_NAME.flattenToString(); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, target1); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, target1 + ShortcutConstants.SERVICES_SEPARATOR + target2); int target1ShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE | ShortcutConstants.UserShortcutType.SOFTWARE; int target2ShortcutTypes = ShortcutConstants.UserShortcutType.HARDWARE; PreferredShortcuts.updatePreferredShortcutsFromSettings(mContext, Set.of(target1, target2)); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, target1, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(target1ShortcutTypes); assertThat( PreferredShortcuts.retrieveUserShortcutType( mContext, target2, ShortcutConstants.UserShortcutType.SOFTWARE)) .isEqualTo(target2ShortcutTypes); } private static void clearShortcuts() { Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, ""); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, AccessibilityUtil.State.OFF); Settings.Secure.putInt( sContentResolver, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, AccessibilityUtil.State.OFF); } }