From 0377025554e748c2b30cde923d38e1bc728ca565 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 18 Feb 2021 00:49:43 +0800 Subject: [PATCH] Add the preference controller to control accessibility button size preference cherry picked from commit 04955b96aea80194ae979912f87eac1e1ec6a9d3 Bug: 173940869 Test: atest FloatingMenuSizePreferenceControllerTest Change-Id: Ic206a940abde90641442df37a634c8cb3a345597 Merged-In: Ic206a940abde90641442df37a634c8cb3a345597 --- res/xml/accessibility_button_settings.xml | 3 +- .../accessibility/AccessibilityUtil.java | 8 + .../FloatingMenuSizePreferenceController.java | 199 ++++++++++++++++++ ...atingMenuSizePreferenceControllerTest.java | 145 +++++++++++++ 4 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index 2fa2e0d0938..e348b77ffb0 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -34,7 +34,8 @@ android:key="accessibility_button_size" android:title="@string/accessibility_button_size_title" android:summary="%s" - android:persistent="false"/> + android:persistent="false" + settings:controller="com.android.settings.accessibility.FloatingMenuSizePreferenceController"/> mValueTitleMap = new ArrayMap<>(); + private int mDefaultSize; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + Size.SMALL, + Size.LARGE, + Size.EDGE + }) + @VisibleForTesting + @interface Size { + int SMALL = 0; + int LARGE = 1; + int EDGE = 2; + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + EdgeMode.FULL_CIRCLE, + EdgeMode.HALF_CIRCLE, + }) + @VisibleForTesting + @interface EdgeMode { + int FULL_CIRCLE = 0; + int HALF_CIRCLE = 1; + } + + public FloatingMenuSizePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mContentResolver = context.getContentResolver(); + mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + updateAvailabilityStatus(); + } + }; + + initValueTitleMap(); + } + + @Override + public int getAvailabilityStatus() { + return AccessibilityUtil.isFloatingMenuEnabled(mContext) + ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final ListPreference listPreference = (ListPreference) preference; + final Integer value = Ints.tryParse((String) newValue); + if (value != null) { + writeToFloatingMenuSettings(value); + updateState(listPreference); + } + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + final ListPreference listPreference = (ListPreference) preference; + + listPreference.setValue(getCurrentAccessibilityButtonSize()); + } + + @Override + public void onResume() { + mContentResolver.registerContentObserver( + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */ + false, mContentObserver); + + } + + @Override + public void onPause() { + mContentResolver.unregisterContentObserver(mContentObserver); + } + + private void updateAvailabilityStatus() { + mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext)); + } + + private void initValueTitleMap() { + if (mValueTitleMap.size() == 0) { + final String[] values = mContext.getResources().getStringArray( + R.array.accessibility_button_size_selector_values); + final String[] titles = mContext.getResources().getStringArray( + R.array.accessibility_button_size_selector_titles); + final int mapSize = values.length; + + mDefaultSize = Integer.parseInt(values[0]); + for (int i = 0; i < mapSize; i++) { + mValueTitleMap.put(values[i], titles[i]); + } + } + } + + private void writeToFloatingMenuSettings(@Size int sizeValue) { + if (sizeValue == Size.EDGE) { + putAccessibilityFloatingMenuSize(Size.SMALL); + putAccessibilityFloatingMenuIconType(EdgeMode.HALF_CIRCLE); + } else { + putAccessibilityFloatingMenuSize(sizeValue); + putAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); + } + } + + private String getCurrentAccessibilityButtonSize() { + final @EdgeMode int iconType = getAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); + final @Size int btnSize = getAccessibilityFloatingMenuSize(mDefaultSize); + + return (iconType == EdgeMode.HALF_CIRCLE) + ? String.valueOf(Size.EDGE) : String.valueOf(btnSize); + } + + @Size + private int getAccessibilityFloatingMenuSize(@Size int defaultValue) { + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, defaultValue); + } + + private void putAccessibilityFloatingMenuSize(@Size int value) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, value); + } + + @EdgeMode + private int getAccessibilityFloatingMenuIconType(@EdgeMode int defaultValue) { + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, defaultValue); + } + + private void putAccessibilityFloatingMenuIconType(@EdgeMode int value) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, value); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java new file mode 100644 index 00000000000..70257ca6931 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 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 android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.ListPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link FloatingMenuSizePreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class FloatingMenuSizePreferenceControllerTest { + + @Rule + public MockitoRule mocks = MockitoJUnit.rule(); + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private ContentResolver mContentResolver; + private final ListPreference mListPreference = new ListPreference(mContext); + private FloatingMenuSizePreferenceController mController; + + @Before + public void setUp() { + when(mContext.getContentResolver()).thenReturn(mContentResolver); + mController = new FloatingMenuSizePreferenceController(mContext, "test_key"); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void updateState_floatingMenuLargeSizeAndFullCircle_largeSizeValue() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, + FloatingMenuSizePreferenceController.Size.LARGE); + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + FloatingMenuSizePreferenceController.EdgeMode.FULL_CIRCLE); + + mController.updateState(mListPreference); + + final String largeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.LARGE); + assertThat(mListPreference.getValue()).isEqualTo(largeSize); + } + + @Test + public void updateState_floatingMenuHalfCircle_edgeSizeValue() { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + FloatingMenuSizePreferenceController.EdgeMode.HALF_CIRCLE); + + mController.updateState(mListPreference); + + final String edgeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.EDGE); + assertThat(mListPreference.getValue()).isEqualTo(edgeSize); + } + + @Test + public void onPreferenceChange_floatingMenuEdgeSize_edgeSizeValue() { + final String edgeSize = String.valueOf( + FloatingMenuSizePreferenceController.Size.EDGE); + + mController.onPreferenceChange(mListPreference, edgeSize); + + assertThat(mListPreference.getValue()).isEqualTo(edgeSize); + } + + @Test + public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() { + mController.mPreference = mListPreference; + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + mController.mContentObserver.onChange(false); + + assertThat(mController.mPreference.isEnabled()).isFalse(); + } + + @Test + public void onResume_registerSpecificContentObserver() { + mController.onResume(); + + verify(mContentResolver).registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false, + mController.mContentObserver); + } + + @Test + public void onPause_unregisterContentObserver() { + mController.onPause(); + + verify(mContentResolver).unregisterContentObserver(mController.mContentObserver); + } +}