From a8b9f30d11514289cbd998c28fac70a9e7e122be Mon Sep 17 00:00:00 2001 From: menghanli Date: Thu, 13 Feb 2020 14:24:04 +0800 Subject: [PATCH] =?UTF-8?q?Accessibility=20Service=20&=20Shortcut=20Redesi?= =?UTF-8?q?gn=20-=20Remove=20=E2=80=9Cvolume=20key=20shortcut=E2=80=9D=20s?= =?UTF-8?q?etting=20(2/n)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 142529032 Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityShortcutPreferenceControllerTest Change-Id: Ic55d4fd8db0678b8fccbbb6ef1d217b47a5094bd --- res/xml/accessibility_settings.xml | 13 +- res/xml/accessibility_shortcut_settings.xml | 30 --- ...ssibilityShortcutPreferenceController.java | 60 ++++++ ...cessibilityShortcutPreferenceFragment.java | 182 ------------------ .../accessibility/AccessibilityUtil.java | 1 + ...ilityShortcutPreferenceControllerTest.java | 92 +++++++++ ...ibilityShortcutPreferenceFragmentTest.java | 124 ------------ 7 files changed, 160 insertions(+), 342 deletions(-) delete mode 100644 res/xml/accessibility_shortcut_settings.xml create mode 100644 src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java delete mode 100644 src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java delete mode 100644 tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml index 914cc7ad730..c10fffc6ee0 100644 --- a/res/xml/accessibility_settings.xml +++ b/res/xml/accessibility_settings.xml @@ -20,12 +20,6 @@ android:persistent="false" android:title="@string/accessibility_settings"> - - + + - - - - - - - - diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java new file mode 100644 index 00000000000..ce3d294486f --- /dev/null +++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceController.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.accessibility; + +import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; + +import com.android.settings.core.TogglePreferenceController; + +/** + * Settings page for accessibility shortcut + */ +public class AccessibilityShortcutPreferenceController extends TogglePreferenceController { + + public AccessibilityShortcutPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public boolean isChecked() { + final ContentResolver cr = mContext.getContentResolver(); + // The shortcut is enabled by default on the lock screen as long as the user has + // enabled the shortcut with the warning dialog + final int dialogShown = Settings.Secure.getInt( + cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, OFF); + final boolean enabledFromLockScreen = Settings.Secure.getInt( + cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, dialogShown) == ON; + return enabledFromLockScreen; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, isChecked ? ON : OFF, + UserHandle.USER_CURRENT); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } +} diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java deleted file mode 100644 index ca3c2e87663..00000000000 --- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.settings.accessibility; - -import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; -import static com.android.settings.accessibility.AccessibilityUtil.State.ON; - -import android.accessibilityservice.AccessibilityServiceInfo; -import android.annotation.Nullable; -import android.app.settings.SettingsEnums; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.view.View; -import android.view.accessibility.AccessibilityManager; - -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; - -import com.android.internal.accessibility.AccessibilityShortcutController; -import com.android.settings.R; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.accessibility.AccessibilityUtils; -import com.android.settingslib.search.Indexable; -import com.android.settingslib.search.SearchIndexable; - -/** - * Settings page for accessibility shortcut - */ -@SearchIndexable -public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePreferenceFragment - implements Indexable { - - public static final String ON_LOCK_SCREEN_KEY = "accessibility_shortcut_on_lock_screen"; - - private SwitchPreference mOnLockScreenSwitchPreference; - private final ContentObserver mContentObserver = new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - updatePreferences(); - } - }; - - @Override - public int getMetricsCategory() { - return SettingsEnums.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE; - } - - @Override - public int getHelpResource() { - return R.string.help_url_accessibility_shortcut; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mOnLockScreenSwitchPreference = (SwitchPreference) findPreference(ON_LOCK_SCREEN_KEY); - mOnLockScreenSwitchPreference.setOnPreferenceChangeListener((Preference p, Object o) -> { - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, - ((Boolean) o) ? ON : OFF); - return true; - }); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - final PreferenceScreen preferenceScreen = getPreferenceScreen(); - preferenceScreen.findPreference(KEY_GENERAL_CATEGORY).setVisible(false); - - preferenceScreen.setOrderingAsAdded(false); - mToggleServiceDividerSwitchPreference.setVisible(false); - } - - @Override - public void onResume() { - super.onResume(); - updatePreferences(); - getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN), - false, mContentObserver); - } - - @Override - public void onPause() { - getContentResolver().unregisterContentObserver(mContentObserver); - super.onPause(); - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.accessibility_shortcut_settings; - } - - @Override - protected void onPreferenceToggled(String preferenceKey, boolean enabled) { - Settings.Secure.putInt(getContentResolver(), preferenceKey, enabled ? ON : OFF); - updatePreferences(); - } - - private void updatePreferences() { - ContentResolver cr = getContentResolver(); - // The shortcut is enabled by default on the lock screen as long as the user has - // enabled the shortcut with the warning dialog - final int dialogShown = Settings.Secure.getInt( - cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, OFF); - final boolean enabledFromLockScreen = Settings.Secure.getInt( - cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, dialogShown) == ON; - mOnLockScreenSwitchPreference.setChecked(enabledFromLockScreen); - } - - /** - * Get the user-visible name of the service currently selected for the shortcut. - * - * @param context The current context - * @return The name of the service or a string saying that none is selected. - */ - public static CharSequence getServiceName(Context context) { - if (!shortcutFeatureAvailable(context)) { - return context.getString(R.string.accessibility_no_service_selected); - } - AccessibilityServiceInfo shortcutServiceInfo = getServiceInfo(context); - if (shortcutServiceInfo != null) { - return shortcutServiceInfo.getResolveInfo().loadLabel(context.getPackageManager()); - } - return AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() - .get(getShortcutComponent(context)).getLabel(context); - } - - private static AccessibilityServiceInfo getServiceInfo(Context context) { - return AccessibilityManager.getInstance(context) - .getInstalledServiceInfoWithComponentName(getShortcutComponent(context)); - } - - private static boolean shortcutFeatureAvailable(Context context) { - ComponentName shortcutFeature = getShortcutComponent(context); - if (shortcutFeature == null) return false; - - if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap() - .containsKey(shortcutFeature)) { - return true; - } - return getServiceInfo(context) != null; - } - - private static @Nullable ComponentName getShortcutComponent(Context context) { - String componentNameString = AccessibilityUtils.getShortcutTargetServiceComponentNameString( - context, UserHandle.myUserId()); - if (componentNameString == null) return null; - return ComponentName.unflattenFromString(componentNameString); - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - // This fragment is for details of the shortcut. Only the shortcut itself needs - // to be indexed. - protected boolean isPageSearchEnabled(Context context) { - return false; - } - }; -} diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java index 8da6fbb920d..6159f9243f2 100644 --- a/src/com/android/settings/accessibility/AccessibilityUtil.java +++ b/src/com/android/settings/accessibility/AccessibilityUtil.java @@ -98,6 +98,7 @@ final class AccessibilityUtil { /** Denotes the accessibility enabled status */ @Retention(RetentionPolicy.SOURCE) public @interface State { + int UNKNOWN = -1; int OFF = 0; int ON = 1; } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java new file mode 100644 index 00000000000..6d0d9645750 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceControllerTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.accessibility; + +import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; +import static com.android.settings.accessibility.AccessibilityUtil.State.UNKNOWN; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.preference.SwitchPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class AccessibilityShortcutPreferenceControllerTest { + + private Context mContext; + private SwitchPreference mPreference; + private AccessibilityShortcutPreferenceController mController; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mPreference = new SwitchPreference(mContext); + mController = new AccessibilityShortcutPreferenceController(mContext, + "accessibility_shortcut_preference"); + } + + @Test + public void isChecked_enabledShortcutOnLockScreen_shouldReturnTrue() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, ON, UserHandle.USER_CURRENT); + + mController.updateState(mPreference); + + assertThat(mController.isChecked()).isTrue(); + assertThat(mPreference.isChecked()).isTrue(); + } + + @Test + public void isChecked_disabledShortcutOnLockScreen_shouldReturnFalse() { + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, OFF, + UserHandle.USER_CURRENT); + + mController.updateState(mPreference); + + assertThat(mController.isChecked()).isFalse(); + assertThat(mPreference.isChecked()).isFalse(); + } + + @Test + public void setChecked_setTrue_shouldEnableShortcutOnLockScreen() { + mController.setChecked(true); + + assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, UNKNOWN, + UserHandle.USER_CURRENT)).isEqualTo(ON); + } + + @Test + public void setChecked_setFalse_shouldDisableShortcutOnLockScreen() { + mController.setChecked(false); + + assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, UNKNOWN, + UserHandle.USER_CURRENT)).isEqualTo(OFF); + } +} diff --git a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java deleted file mode 100644 index 0c27379a0fd..00000000000 --- a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.accessibility; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; -import static androidx.test.espresso.matcher.ViewMatchers.isChecked; -import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked; -import static androidx.test.espresso.matcher.ViewMatchers.withParent; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.Matchers.allOf; - -import android.app.Instrumentation; -import android.os.Bundle; - -import android.provider.Settings; -import android.widget.CompoundButton; - -import androidx.test.InstrumentationRegistry; -import androidx.test.rule.ActivityTestRule; -import androidx.test.runner.AndroidJUnit4; - -import com.android.settings.R; -import com.android.settings.Settings.AccessibilitySettingsActivity; -import com.android.settings.core.InstrumentedPreferenceFragment; -import com.android.settings.core.SubSettingLauncher; - -import org.hamcrest.Matcher; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class AccessibilityShortcutPreferenceFragmentTest { - @Rule - public final ActivityTestRule mActivityRule = - new ActivityTestRule<>(AccessibilitySettingsActivity.class, true); - - private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); - private AccessibilityShortcutPreferenceFragment mAccessibilityShortcutPreferenceFragment; - private AccessibilitySettingsActivity mActivity; - - @Before - public void setUp() { - mActivity = mActivityRule.getActivity(); - } - - @Test - public void lockScreenPreference_setOnBeforeDialogShown_isOn() { - setDialogShown(false); - setOnLockscreen(true); - startFragment(); - assertLockscreenSwitchIsCheckedIs(true); - } - - @Test - public void lockScreenPreference_defaultAfterDialogShown_isOn() { - setDialogShown(true); - setOnLockscreen(null); - startFragment(); - assertLockscreenSwitchIsCheckedIs(true); - } - - private void startFragment() { - mInstrumentation.runOnMainSync(() -> { - new SubSettingLauncher(mActivity) - .setDestination(AccessibilityShortcutPreferenceFragment.class.getName()) - .setArguments(new Bundle()) - .setSourceMetricsCategory( - InstrumentedPreferenceFragment.METRICS_CATEGORY_UNKNOWN) - .launch(); - }); - } - - private void setDialogShown(boolean shown) { - Settings.Secure.putInt(mActivity.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, shown ? 1 : 0); - } - - private void setOnLockscreen(Boolean onLockscreen) { - if (onLockscreen == null) { - Settings.Secure.putString(mActivity.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, null); - } else { - Settings.Secure.putInt(mActivity.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, onLockscreen ? 1 : 0); - } - } - - private void assertLockscreenSwitchIsCheckedIs(boolean isChecked) { - // Identify the switch by looking for a grandparent that has a descendent with the - // switch label. To disambiguate, make sure that grandparent doesn't also have a descendant - // with the title of the main switch - final String lockScreenSwitchTitle = - mActivity.getString(R.string.accessibility_shortcut_service_on_lock_screen_title); - final String mainSwitchTitle = - mActivity.getString(R.string.accessibility_service_master_switch_title); - Matcher isCheckedMatcher = (isChecked) ? isChecked() : isNotChecked(); - Matcher hasLockScreenTitleDescendant = hasDescendant(withText(lockScreenSwitchTitle)); - Matcher noMainSwitchTitleDescendant = not(hasDescendant(withText(mainSwitchTitle))); - onView(allOf(withParent(withParent(allOf( - hasLockScreenTitleDescendant, noMainSwitchTitleDescendant))), - instanceOf(CompoundButton.class))).check(matches(isCheckedMatcher)); - } -}