From 4ace76e6c25bea4a687fcc82e40ba08bc757c820 Mon Sep 17 00:00:00 2001 From: Lucas Silva Date: Thu, 9 Mar 2023 14:55:25 -0500 Subject: [PATCH 01/14] Add home controls button to screensaver settings Toggle will allow users to disable showing home controls over their screensaver. Bug: 271330583 Test: make -j64 RunSettingsRoboTests Change-Id: I9600cdb85d85253c859c88f12c1d074e1082bf97 --- res/values/strings.xml | 4 + res/xml/dream_fragment_overview.xml | 6 + ...DreamHomeControlsPreferenceController.java | 68 ++++++++++ ...mHomeControlsPreferenceControllerTest.java | 116 ++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 src/com/android/settings/dream/DreamHomeControlsPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/dream/DreamHomeControlsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index c01f4b987b6..1df5dad4fc0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14461,6 +14461,10 @@ Show additional information Display things like the time, weather, or other information on the screen saver + + Show home controls + + Show home controls button from the screen saver More settings diff --git a/res/xml/dream_fragment_overview.xml b/res/xml/dream_fragment_overview.xml index 3321fd1dda1..8377a0685c2 100644 --- a/res/xml/dream_fragment_overview.xml +++ b/res/xml/dream_fragment_overview.xml @@ -46,6 +46,12 @@ android:summary="@string/dream_complications_toggle_summary" settings:controller="com.android.settings.dream.DreamComplicationPreferenceController"/> + + diff --git a/src/com/android/settings/dream/DreamHomeControlsPreferenceController.java b/src/com/android/settings/dream/DreamHomeControlsPreferenceController.java new file mode 100644 index 00000000000..b39f3b1ace6 --- /dev/null +++ b/src/com/android/settings/dream/DreamHomeControlsPreferenceController.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 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.dream; + +import android.content.Context; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.dream.DreamBackend; + +/** + * Controller for the {@link androidx.preference.SwitchPreference} which controls if dream + * overlays should be enabled. + */ +public class DreamHomeControlsPreferenceController extends TogglePreferenceController { + private final DreamBackend mBackend; + + public DreamHomeControlsPreferenceController(Context context, String key) { + this(context, key, DreamBackend.getInstance(context)); + } + + @VisibleForTesting + public DreamHomeControlsPreferenceController(Context context, String key, + DreamBackend dreamBackend) { + super(context, key); + mBackend = dreamBackend; + } + + @Override + public int getAvailabilityStatus() { + final boolean supported = + mBackend.getSupportedComplications() + .contains(DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS); + return supported ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public boolean isChecked() { + return mBackend.getEnabledComplications().contains( + DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS); + } + + @Override + public boolean setChecked(boolean isChecked) { + mBackend.setHomeControlsEnabled(isChecked); + return true; + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_display; + } +} diff --git a/tests/robotests/src/com/android/settings/dream/DreamHomeControlsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/dream/DreamHomeControlsPreferenceControllerTest.java new file mode 100644 index 00000000000..452604c8012 --- /dev/null +++ b/tests/robotests/src/com/android/settings/dream/DreamHomeControlsPreferenceControllerTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023 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.dream; + +import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.util.ArraySet; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settingslib.dream.DreamBackend; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowContentResolver; +import org.robolectric.shadows.ShadowSettings; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowSettings.ShadowSecure.class}) +public class DreamHomeControlsPreferenceControllerTest { + + private Context mContext; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PreferenceScreen mScreen; + private DreamHomeControlsPreferenceController mController; + private SwitchPreference mPreference; + private DreamBackend mBackend; + private ShadowContentResolver mShadowContentResolver; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = ApplicationProvider.getApplicationContext(); + mShadowContentResolver = Shadow.extract(mContext.getContentResolver()); + mBackend = new DreamBackend(mContext); + mController = new DreamHomeControlsPreferenceController(mContext, "key", mBackend); + mPreference = new SwitchPreference(mContext); + mPreference.setKey(mController.getPreferenceKey()); + when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + + // Make home controls supported by default + mBackend.setSupportedComplications( + new ArraySet<>(new Integer[]{COMPLICATION_TYPE_HOME_CONTROLS})); + } + + @After + public void tearDown() { + ShadowSettings.ShadowSecure.reset(); + } + + @Test + public void testSetChecked_setTrue_enablesSetting() { + mBackend.setHomeControlsEnabled(false); + assertThat(mBackend.getEnabledComplications()) + .doesNotContain(COMPLICATION_TYPE_HOME_CONTROLS); + + mController.setChecked(true); + assertThat(mBackend.getEnabledComplications()) + .contains(COMPLICATION_TYPE_HOME_CONTROLS); + } + + @Test + public void testSetChecked_setFalse_disablesSetting() { + mBackend.setHomeControlsEnabled(true); + assertThat(mBackend.getEnabledComplications()) + .contains(COMPLICATION_TYPE_HOME_CONTROLS); + + mController.setChecked(false); + assertThat(mBackend.getEnabledComplications()) + .doesNotContain(COMPLICATION_TYPE_HOME_CONTROLS); + } + + @Test + public void testIsChecked_returnsFalse() { + mBackend.setHomeControlsEnabled(false); + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void testIsChecked_returnsTrue() { + mBackend.setHomeControlsEnabled(true); + assertThat(mBackend.getEnabledComplications()) + .contains(COMPLICATION_TYPE_HOME_CONTROLS); + assertThat(mController.isChecked()).isTrue(); + } +} From a6b78f6d01a6a0ed2ab9bd574e128bfbf43a70ca Mon Sep 17 00:00:00 2001 From: danielwbhuang Date: Tue, 7 Mar 2023 21:43:33 +0800 Subject: [PATCH 02/14] The PK settings UI should show subtype labels instead of the subtype's language names. 1. Use InputMethodSubtype#getDisplayName() 2. Sorting by label Video: https://screencast.googleplex.com/cast/NjEzMjM3OTI0OTgwMzI2NHxiODBhNjQzZi1kZA Bug: 271504879 Test: manual Change-Id: Ia2be6f3a007c678e62bdda21fe20d95a2b304d70 --- ...wKeyboardLayoutEnabledLocalesFragment.java | 70 +++++++++++-------- .../NewKeyboardLayoutPickerContent.java | 2 +- .../inputmethod/NewKeyboardSettingsUtils.java | 14 ++-- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java index 2db338254e4..0f49ee18bc4 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java @@ -37,10 +37,10 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; -import java.util.Locale; -import java.util.Map; public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment implements InputManager.InputDeviceListener { @@ -53,7 +53,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment private int mUserId; private int mInputDeviceId; private Context mContext; - private Map mKeyboardLanguageLayouts = new HashMap<>(); + private ArrayList mKeyboardInfoList = new ArrayList<>(); @Override public void onActivityCreated(final Bundle icicle) { @@ -74,8 +74,16 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment PreferenceScreen preferenceScreen = getPreferenceScreen(); preferenceScreen.removeAll(); List infoList = mImm.getEnabledInputMethodListAsUser(mUserId); + Collections.sort(infoList, new Comparator() { + public int compare(InputMethodInfo o1, InputMethodInfo o2) { + String s1 = o1.loadLabel(mContext.getPackageManager()).toString(); + String s2 = o2.loadLabel(mContext.getPackageManager()).toString(); + return s1.compareTo(s2); + } + }); + for (InputMethodInfo info : infoList) { - mKeyboardLanguageLayouts.clear(); + mKeyboardInfoList.clear(); List subtypes = mImm.getEnabledInputMethodSubtypeList(info, true); for (InputMethodSubtype subtype : subtypes) { @@ -88,51 +96,58 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment } private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) { + CharSequence subtypeLabel = getSubtypeLabel(mContext, info, subtype); KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype); String layout = getKeyboardLayout(info, subtype); - String language = getLanguage(info, subtype); + if (layout != null) { for (int i = 0; i < keyboardLayouts.length; i++) { if (keyboardLayouts[i].getDescriptor().equals(layout)) { KeyboardInfo keyboardInfo = new KeyboardInfo( - language, + subtypeLabel, keyboardLayouts[i].getLabel(), info, subtype); - mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo); + mKeyboardInfoList.add(keyboardInfo); break; } } } else { // if there is no auto-selected layout, we should show "Default" KeyboardInfo keyboardInfo = new KeyboardInfo( - language, + subtypeLabel, mContext.getString(R.string.keyboard_default_layout), info, subtype); - mKeyboardLanguageLayouts.put(subtype.getLanguageTag(), keyboardInfo); + mKeyboardInfoList.add(keyboardInfo); } } private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) { - if (mKeyboardLanguageLayouts.isEmpty()) { + if (mKeyboardInfoList.isEmpty()) { return; } PreferenceCategory preferenceCategory = new PreferenceCategory(mContext); - preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()).toString()); + preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager())); preferenceCategory.setKey(info.getPackageName()); preferenceScreen.addPreference(preferenceCategory); - for (Map.Entry entry : mKeyboardLanguageLayouts.entrySet()) { + Collections.sort(mKeyboardInfoList, new Comparator() { + public int compare(KeyboardInfo o1, KeyboardInfo o2) { + String s1 = o1.getSubtypeLabel().toString(); + String s2 = o2.getSubtypeLabel().toString(); + return s1.compareTo(s2); + } + }); + + for (KeyboardInfo keyboardInfo : mKeyboardInfoList) { final Preference pref = new Preference(mContext); - String key = "keyboard_language_" + entry.getKey(); - NewKeyboardSettingsUtils.KeyboardInfo keyboardInfo = entry.getValue(); - pref.setKey(key); - pref.setTitle(keyboardInfo.getLanguage()); + pref.setKey(keyboardInfo.getPrefId()); + pref.setTitle(keyboardInfo.getSubtypeLabel()); pref.setSummary(keyboardInfo.getLayout()); pref.setOnPreferenceClickListener( preference -> { showKeyboardLayoutPicker( - keyboardInfo.getLanguage(), + keyboardInfo.getSubtypeLabel(), keyboardInfo.getLayout(), mInputDeviceIdentifier, mUserId, @@ -215,7 +230,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment } private void showKeyboardLayoutPicker( - String language, + CharSequence subtypeLabel, String layout, InputDeviceIdentifier inputDeviceIdentifier, int userId, @@ -229,7 +244,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment arguments.putParcelable( NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype); arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId); - arguments.putString(NewKeyboardSettingsUtils.EXTRA_TITLE, language); + arguments.putCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE, subtypeLabel); arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout); new SubSettingLauncher(mContext) .setSourceMetricsCategory(getMetricsCategory()) @@ -248,16 +263,9 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment mInputDeviceIdentifier, mUserId, info, subtype); } - private String getLanguage(InputMethodInfo info, InputMethodSubtype subtype) { - String language; - if (subtype.getLanguageTag().isEmpty()) { - language = subtype.getDisplayName( - mContext, - info.getPackageName(), - info.getServiceInfo().applicationInfo).toString(); - } else { - language = Locale.forLanguageTag(subtype.getLanguageTag()).getDisplayName(); - } - return language; + private CharSequence getSubtypeLabel( + Context context, InputMethodInfo info, InputMethodSubtype subtype) { + return subtype.getDisplayName( + context, info.getPackageName(), info.getServiceInfo().applicationInfo); } } diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java index 605095f103b..761e95e17c5 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java @@ -36,7 +36,7 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment { super.onAttach(context); InputManager inputManager = getContext().getSystemService(InputManager.class); Bundle arguments = getArguments(); - final String title = arguments.getString(NewKeyboardSettingsUtils.EXTRA_TITLE); + final CharSequence title = arguments.getCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE); final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT); final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID); final InputDeviceIdentifier identifier = diff --git a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java index dda5500bc98..506d1e77710 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java +++ b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java @@ -72,24 +72,28 @@ public class NewKeyboardSettingsUtils { } static class KeyboardInfo { - String mLanguage; + CharSequence mSubtypeLabel; String mLayout; InputMethodInfo mInputMethodInfo; InputMethodSubtype mInputMethodSubtype; KeyboardInfo( - String language, + CharSequence subtypeLabel, String layout, InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) { - mLanguage = language; + mSubtypeLabel = subtypeLabel; mLayout = layout; mInputMethodInfo = inputMethodInfo; mInputMethodSubtype = inputMethodSubtype; } - String getLanguage() { - return mLanguage; + String getPrefId() { + return mInputMethodInfo.getId() + "_" + mInputMethodSubtype.hashCode(); + } + + CharSequence getSubtypeLabel() { + return mSubtypeLabel; } String getLayout() { From 806297f85ce2ef198888dc82c2a5d3ea9e55093a Mon Sep 17 00:00:00 2001 From: Behnam Heydarshahi Date: Mon, 27 Feb 2023 19:39:25 +0000 Subject: [PATCH 03/14] Extend settings panel under navigation bar The panel used to sit above the navigation bar. Now it extends down all the way to the edge of the screen. Bug: b/250484565 Test: make ROBOTEST_FILTER=SettingsPanelActivityTest RunSettingsRoboTests -j40 Test: Manual. When volume panel is opened, verify that it extends all the way to the bottom of the window, instead of sitting on navigation bar. Panel can be opened with: adb shell am start -a android.settings.panel.action.VOLUME Substitute VOLUME with NFC and WIFI for the other settings panels. Change-Id: Ibae5d3602231e2309b5ff847c630a1f8c82ea355 --- res/layout/panel_layout.xml | 1 + res/values/themes.xml | 1 + .../settings/panel/SettingsPanelActivity.java | 27 +++++++++++++ .../panel/SettingsPanelActivityTest.java | 39 +++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/res/layout/panel_layout.xml b/res/layout/panel_layout.xml index f154abc40cb..fd8d55f1356 100644 --- a/res/layout/panel_layout.xml +++ b/res/layout/panel_layout.xml @@ -20,6 +20,7 @@ android:id="@+id/panel_container" android:layout_width="@dimen/settings_panel_width" android:layout_height="wrap_content" + android:fitsSystemWindows="true" android:layout_gravity="center_horizontal" android:background="@drawable/settings_panel_rounded_top_corner_background" > diff --git a/res/values/themes.xml b/res/values/themes.xml index ff56e7edca9..e6c0510dbb1 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -229,6 +229,7 @@