diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java index d3217832794..bc164ab5152 100644 --- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java +++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java @@ -20,7 +20,9 @@ import android.annotation.Nullable; 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.support.v14.preference.SwitchPreference; @@ -46,6 +48,12 @@ public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePrefer private Preference mServicePreference; private SwitchPreference mOnLockScreenSwitchPreference; + private final ContentObserver mContentObserver = new ContentObserver(new Handler()) { + @Override + public void onChange(boolean selfChange) { + updatePreferences(); + } + }; @Override public int getMetricsCategory() { @@ -77,6 +85,15 @@ public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePrefer 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 @@ -120,8 +137,13 @@ public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePrefer boolean isEnabled = Settings.Secure .getInt(cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1) == 1; mSwitchBar.setChecked(isEnabled); - mOnLockScreenSwitchPreference.setChecked(Settings.Secure.getInt( - cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0) == 1); + // 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, 0); + final boolean enabledFromLockScreen = Settings.Secure.getInt( + cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, dialogShown) == 1; + mOnLockScreenSwitchPreference.setChecked(enabledFromLockScreen); // Only enable changing the service and lock screen behavior if the shortcut is on mServicePreference.setEnabled(mToggleSwitch.isChecked()); mOnLockScreenSwitchPreference.setEnabled(mToggleSwitch.isChecked()); diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml index eccbac36486..05637534858 100644 --- a/tests/unit/AndroidManifest.xml +++ b/tests/unit/AndroidManifest.xml @@ -26,6 +26,7 @@ + diff --git a/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java new file mode 100644 index 00000000000..886f4f0f004 --- /dev/null +++ b/tests/unit/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragmentTest.java @@ -0,0 +1,141 @@ +/* + * 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 org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.collection.IsIn.oneOf; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +import static android.support.test.espresso.matcher.ViewMatchers.isChecked; +import static android.support.test.espresso.matcher.ViewMatchers.isNotChecked; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static android.support.test.espresso.matcher.ViewMatchers.withParent; + +import android.app.Activity; +import android.app.Instrumentation; +import android.content.Context; +import android.os.Bundle; +import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.widget.CompoundButton; + +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_defaultBeforeDialogShown_isOff() { + setDialogShown(false); + setOnLockscreen(null); + startFragment(); + assertLockscreenSwitchIsCheckedIs(false); + } + + @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); + } + + @Test + public void lockScreenPreference_setOffAfterDialogShown_isOn() { + setDialogShown(true); + setOnLockscreen(false); + startFragment(); + assertLockscreenSwitchIsCheckedIs(false); + } + + 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)); + } +}