diff --git a/src/com/android/settings/accessibility/PreferredShortcuts.java b/src/com/android/settings/accessibility/PreferredShortcuts.java index 2c9840d09ec..d4e8e0cdbc3 100644 --- a/src/com/android/settings/accessibility/PreferredShortcuts.java +++ b/src/com/android/settings/accessibility/PreferredShortcuts.java @@ -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} */ @@ -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 components) { + final Map> 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> 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. diff --git a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java index 7a1dd4b3dc0..a3cbb57ba5b 100644 --- a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java +++ b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java @@ -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; @@ -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); } }; @@ -212,6 +216,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { final AccessibilityManager am = getSystemService( AccessibilityManager.class); am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); + PreferredShortcuts.updatePreferredShortcutsFromSettings(getContext(), mShortcutTargets); } @Override diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java index 53a87ba9457..7586954fcd4 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java @@ -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; @@ -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(); diff --git a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java index 95a0b836f05..e7dfb5bed9e 100644 --- a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java +++ b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java @@ -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 { @@ -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 Context mContext = ApplicationProvider.getApplicationContext(); + private final Context mContext = ApplicationProvider.getApplicationContext(); + + @Before + public void setUp() { + clearShortcuts(); + } + + @AfterClass + public static void cleanUp() { + clearShortcuts(); + } @Test public void retrieveUserShortcutType_fromSingleData_matchSavedType() { @@ -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); + } }