Merge "Save the user preferred shortcut on Edit A11yShortcut screen" into main
This commit is contained in:
@@ -19,10 +19,17 @@ package com.android.settings.accessibility;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
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 com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/** Static utility methods relating to {@link PreferredShortcut} */
|
/** Static utility methods relating to {@link PreferredShortcut} */
|
||||||
@@ -80,6 +87,41 @@ public final class PreferredShortcuts {
|
|||||||
saveToSharedPreferences(context, info);
|
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
|
* Returns a immutable set of {@link PreferredShortcut#toString()} list from
|
||||||
* SharedPreferences.
|
* SharedPreferences.
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SetupWizardUtils;
|
import com.android.settings.SetupWizardUtils;
|
||||||
import com.android.settings.accessibility.AccessibilitySetupWizardUtils;
|
import com.android.settings.accessibility.AccessibilitySetupWizardUtils;
|
||||||
|
import com.android.settings.accessibility.PreferredShortcuts;
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
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)) {
|
} else if (TWO_FINGERS_DOUBLE_TAP_SHORTCUT_SETTING.equals(uri)) {
|
||||||
refreshPreferenceController(TwoFingersDoubleTapShortcutOptionController.class);
|
refreshPreferenceController(TwoFingersDoubleTapShortcutOptionController.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PreferredShortcuts.updatePreferredShortcutsFromSettings(
|
||||||
|
getContext(), mShortcutTargets);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -212,6 +216,7 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment {
|
|||||||
final AccessibilityManager am = getSystemService(
|
final AccessibilityManager am = getSystemService(
|
||||||
AccessibilityManager.class);
|
AccessibilityManager.class);
|
||||||
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
am.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener);
|
||||||
|
PreferredShortcuts.updatePreferredShortcutsFromSettings(getContext(), mShortcutTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SubSettings;
|
import com.android.settings.SubSettings;
|
||||||
import com.android.settings.accessibility.AccessibilityUtil;
|
import com.android.settings.accessibility.AccessibilityUtil;
|
||||||
|
import com.android.settings.accessibility.PreferredShortcuts;
|
||||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
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(
|
private void assertLaunchSubSettingWithCurrentTargetComponents(
|
||||||
String componentName, boolean isInSuw) {
|
String componentName, boolean isInSuw) {
|
||||||
Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity();
|
Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity();
|
||||||
|
|||||||
@@ -16,17 +16,30 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
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.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/** Tests for {@link PreferredShortcuts} */
|
/** Tests for {@link PreferredShortcuts} */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class PreferredShortcutsTest {
|
public class PreferredShortcutsTest {
|
||||||
@@ -39,8 +52,20 @@ public class PreferredShortcutsTest {
|
|||||||
private static final String CLASS_NAME_2 = PACKAGE_NAME_2 + ".test2";
|
private static final String CLASS_NAME_2 = PACKAGE_NAME_2 + ".test2";
|
||||||
private static final ComponentName COMPONENT_NAME_2 = new ComponentName(PACKAGE_NAME_2,
|
private static final ComponentName COMPONENT_NAME_2 = new ComponentName(PACKAGE_NAME_2,
|
||||||
CLASS_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
|
@Test
|
||||||
public void retrieveUserShortcutType_fromSingleData_matchSavedType() {
|
public void retrieveUserShortcutType_fromSingleData_matchSavedType() {
|
||||||
@@ -71,4 +96,88 @@ public class PreferredShortcutsTest {
|
|||||||
|
|
||||||
assertThat(retrieveType).isEqualTo(type1);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user