From e3e348b2dcfbd539d4ff0bb9c78089c53b2a7164 Mon Sep 17 00:00:00 2001 From: Evan Chen Date: Tue, 17 Sep 2024 18:08:29 +0000 Subject: [PATCH 01/14] Update AssociationInfo with deviceIcon field Test: CTS Bug: 341057668 Flag: EXEMPT bugfix Change-Id: I1398f4a225bf84ccb80438e0ce5f04f2ee844f27 --- .../bluetooth/BluetoothDetailsCompanionAppsControllerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java index faea3d8ecb1..d9054a8bf77 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java @@ -115,7 +115,8 @@ public class BluetoothDetailsCompanionAppsControllerTest extends /* pending */ false, /* timeApprovedMs */ System.currentTimeMillis(), /* lastTimeConnected */ Long.MAX_VALUE, - /* systemDataSyncFlags */ -1); + /* systemDataSyncFlags */ -1, + /* deviceIcon */ null); mAssociations.add(association); showScreen(mController); From cc3eac9b7ca9d5869874f879ec2988542f16e3d5 Mon Sep 17 00:00:00 2001 From: Alina Zaidi Date: Tue, 1 Oct 2024 18:29:14 +0000 Subject: [PATCH 02/14] [dev_option] Move DestopModeFlags out of android.windows.flags This is to maintain separation of non-generated files from generated flag values. Test: Current tests pass Flag: EXEMPT refactoring Bug: 370777204 Change-Id: I6588ebec59519b4e0d6c83057b8106c20a3df8fa --- .../development/DesktopModePreferenceController.java | 10 +++++----- .../DesktopModePreferenceControllerTest.java | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/development/DesktopModePreferenceController.java b/src/com/android/settings/development/DesktopModePreferenceController.java index f43e17cca86..492686ead65 100644 --- a/src/com/android/settings/development/DesktopModePreferenceController.java +++ b/src/com/android/settings/development/DesktopModePreferenceController.java @@ -17,14 +17,14 @@ package com.android.settings.development; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; -import static android.window.flags.DesktopModeFlags.ToggleOverride.fromSetting; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; +import static android.window.DesktopModeFlags.ToggleOverride.fromSetting; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; import android.content.Context; import android.provider.Settings; -import android.window.flags.DesktopModeFlags.ToggleOverride; +import android.window.DesktopModeFlags.ToggleOverride; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java index 7fe937729b6..b9f56215de1 100644 --- a/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/DesktopModePreferenceControllerTest.java @@ -17,9 +17,9 @@ package com.android.settings.development; import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; -import static android.window.flags.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_ON; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF; +import static android.window.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET; import static com.google.common.truth.Truth.assertThat; From 92ada7e3a53429fad702069c0da20f59ee7ee6ca Mon Sep 17 00:00:00 2001 From: Tetiana Meronyk Date: Thu, 3 Oct 2024 17:25:55 +0000 Subject: [PATCH 03/14] Remove "Add supervised user" from search result if such user type is not allowed on the device Bug: 371202325 Test: manual: 1. Open settings 2. Search "Add user" 3. Verify "Add supervised user" does not come up Flag: EXEMPT bugfix Change-Id: Iaf96bd8d7ffde4f9d09f14af1de422e1b1d39eda --- src/com/android/settings/users/UserSettings.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 31882408fd7..0881b29a3b3 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -1860,6 +1860,10 @@ public class UserSettings extends SettingsPreferenceFragment boolean suppressAllPage) { final List niks = super.getNonIndexableKeysFromXml(context, xmlResId, suppressAllPage); + if (TextUtils.isEmpty(context.getString( + com.android.internal.R.string.config_supervisedUserCreationPackage))) { + niks.add(KEY_ADD_SUPERVISED_USER); + } AddUserWhenLockedPreferenceController controller = new AddUserWhenLockedPreferenceController( context, KEY_ADD_USER_WHEN_LOCKED); From ea5832e174b8ada0924c274b7cac492955a42e58 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Sun, 29 Sep 2024 19:00:57 +0800 Subject: [PATCH 04/14] [Audiosharing] Update audio sharing section title in call In call mode, change title "Active media devices" to "Call devices", also allow device click to switch active. Test: atest Bug: 355222285 Flag: com.android.settingslib.flags.enable_le_audio_sharing Change-Id: I8195934f19de534d07f5a655aac17d6966ae6f32 --- .../AudioSharingBluetoothDeviceUpdater.java | 6 +- ...udioSharingDevicePreferenceController.java | 129 ++++++++++++------ ...udioSharingBluetoothDeviceUpdaterTest.java | 6 +- ...SharingDevicePreferenceControllerTest.java | 65 ++++++++- 4 files changed, 157 insertions(+), 49 deletions(-) diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java index 60a8a1329f7..6fd6f18bc24 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java @@ -16,7 +16,6 @@ package com.android.settings.connecteddevice.audiosharing; -import android.app.settings.SettingsEnums; import android.content.Context; import android.util.Log; @@ -30,6 +29,7 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.utils.ThreadUtils; public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater implements Preference.OnPreferenceClickListener { @@ -73,7 +73,9 @@ public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater @Override public boolean onPreferenceClick(Preference preference) { mMetricsFeatureProvider.logClickedPreference(preference, mMetricsCategory); - mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK); + var unused = + ThreadUtils.postOnBackgroundThread( + () -> mDevicePreferenceCallback.onDeviceClick(preference)); return true; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java index 8b4c7f267bb..db2c7b21b1b 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.connecteddevice.audiosharing; +import static com.android.settingslib.Utils.isAudioModeOngoingCall; import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE; import android.app.settings.SettingsEnums; @@ -39,7 +40,9 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; +import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.Utils; import com.android.settings.connecteddevice.DevicePreferenceCallback; @@ -91,6 +94,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro @Nullable private DashboardFragment mFragment; @Nullable private AudioSharingDialogHandler mDialogHandler; private AtomicBoolean mIntentHandled = new AtomicBoolean(false); + private AtomicBoolean mIsAudioModeOngoingCall = new AtomicBoolean(false); @VisibleForTesting BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback = @@ -201,51 +205,57 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro @Override public void onStart(@NonNull LifecycleOwner owner) { - if (!isAvailable()) { - Log.d(TAG, "Skip onStart(), feature is not supported."); - return; - } - if (!AudioSharingUtils.isAudioSharingProfileReady(mProfileManager) - && mProfileManager != null) { - Log.d(TAG, "Register profile service listener"); - mProfileManager.addServiceListener(this); - } - if (mEventManager == null - || mAssistant == null - || mDialogHandler == null - || mBluetoothDeviceUpdater == null) { - Log.d(TAG, "Skip onStart(), profile is not ready."); - return; - } - Log.d(TAG, "onStart() Register callbacks."); - mEventManager.registerCallback(this); - mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback); - mDialogHandler.registerCallbacks(mExecutor); - mBluetoothDeviceUpdater.registerCallback(); - mBluetoothDeviceUpdater.refreshPreference(); + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStart(), feature is not supported."); + return; + } + if (!AudioSharingUtils.isAudioSharingProfileReady(mProfileManager) + && mProfileManager != null) { + Log.d(TAG, "Register profile service listener"); + mProfileManager.addServiceListener(this); + } + if (mEventManager == null + || mAssistant == null + || mDialogHandler == null + || mBluetoothDeviceUpdater == null) { + Log.d(TAG, "Skip onStart(), profile is not ready."); + return; + } + Log.d(TAG, "onStart() Register callbacks."); + mEventManager.registerCallback(this); + mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback); + mDialogHandler.registerCallbacks(mExecutor); + mBluetoothDeviceUpdater.registerCallback(); + mBluetoothDeviceUpdater.refreshPreference(); + mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext)); + updateTitle(); + }); } @Override public void onStop(@NonNull LifecycleOwner owner) { - if (!isAvailable()) { - Log.d(TAG, "Skip onStop(), feature is not supported."); - return; - } - if (mProfileManager != null) { - mProfileManager.removeServiceListener(this); - } - if (mEventManager == null - || mAssistant == null - || mDialogHandler == null - || mBluetoothDeviceUpdater == null) { - Log.d(TAG, "Skip onStop(), profile is not ready."); - return; - } - Log.d(TAG, "onStop() Unregister callbacks."); - mEventManager.unregisterCallback(this); - mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback); - mDialogHandler.unregisterCallbacks(); - mBluetoothDeviceUpdater.unregisterCallback(); + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStop(), feature is not supported."); + return; + } + if (mProfileManager != null) { + mProfileManager.removeServiceListener(this); + } + if (mEventManager == null + || mAssistant == null + || mDialogHandler == null + || mBluetoothDeviceUpdater == null) { + Log.d(TAG, "Skip onStop(), profile is not ready."); + return; + } + Log.d(TAG, "onStop() Unregister callbacks."); + mEventManager.unregisterCallback(this); + mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback); + mDialogHandler.unregisterCallbacks(); + mBluetoothDeviceUpdater.unregisterCallback(); + }); } @Override @@ -367,6 +377,25 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro handleOnProfileStateChanged(cachedDevice, bluetoothProfile); } + @Override + public void onAudioModeChanged() { + mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext)); + updateTitle(); + } + + @Override + public void onDeviceClick(@NonNull Preference preference) { + boolean isCallMode = mIsAudioModeOngoingCall.get(); + if (isCallMode) { + Log.d(TAG, "onDeviceClick, set active in call mode"); + CachedBluetoothDevice cachedDevice = + ((BluetoothDevicePreference) preference).getBluetoothDevice(); + cachedDevice.setActive(); + } + mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK, + isCallMode); + } + /** * Initialize the controller. * @@ -499,4 +528,22 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro mDialogHandler.handleDeviceConnected(cachedDevice, /* userTriggered= */ true); } } + + private void updateTitle() { + if (mPreferenceGroup == null) return; + int titleResId; + if (mIsAudioModeOngoingCall.get()) { + // in phone call + titleResId = R.string.connected_device_call_device_title; + } else { + // without phone call + titleResId = R.string.audio_sharing_device_group_title; + } + AudioSharingUtils.postOnMainThread(mContext, + () -> { + if (mPreferenceGroup != null) { + mPreferenceGroup.setTitle(titleResId); + } + }); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java index 879c6a4d0ab..11e31b6fa03 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; -import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastReceiveState; @@ -271,8 +270,9 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onPreferenceClick_logClick() { Preference preference = new Preference(mContext); mDeviceUpdater.onPreferenceClick(preference); - verify(mFeatureFactory.metricsFeatureProvider) - .action(mContext, SettingsEnums.ACTION_AUDIO_SHARING_DEVICE_CLICK); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceClick(preference); } private void setupPreferenceMapWithDevice() { diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java index 03f13037d62..61bc8aaa055 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceControllerTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -44,10 +45,14 @@ import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothStatusCodes; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; import android.os.Bundle; import android.os.Looper; import android.platform.test.flag.junit.SetFlagsRule; +import android.util.Pair; +import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; @@ -56,10 +61,13 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowFragment; @@ -99,14 +107,16 @@ import java.util.concurrent.Executor; @RunWith(RobolectricTestRunner.class) @Config( shadows = { - ShadowBluetoothAdapter.class, - ShadowBluetoothUtils.class, - ShadowFragment.class, + ShadowBluetoothAdapter.class, + ShadowBluetoothUtils.class, + ShadowFragment.class, + ShadowAudioManager.class, }) public class AudioSharingDevicePreferenceControllerTest { private static final String KEY = "audio_sharing_device_list"; private static final String KEY_AUDIO_SHARING_SETTINGS = "connected_device_audio_sharing_settings"; + private static final String TEST_DEVICE_NAME = "test"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -140,6 +150,7 @@ public class AudioSharingDevicePreferenceControllerTest { private PreferenceCategory mPreferenceGroup; private Preference mAudioSharingPreference; private FakeFeatureFactory mFeatureFactory; + private AudioManager mAudioManager; @Before public void setUp() { @@ -153,6 +164,7 @@ public class AudioSharingDevicePreferenceControllerTest { mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); mFeatureFactory = FakeFeatureFactory.setupForTest(); + mAudioManager = mContext.getSystemService(AudioManager.class); ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; mLocalBtManager = Utils.getLocalBtManager(mContext); when(mLocalBtManager.getEventManager()).thenReturn(mEventManager); @@ -571,4 +583,51 @@ public class AudioSharingDevicePreferenceControllerTest { verify(mBluetoothDeviceUpdater, never()).forceUpdate(); verifyNoMoreInteractions(mFeatureFactory.metricsFeatureProvider); } + + @Test + public void testInCallState_showCallStateTitleAndSetActiveOnDeviceClick() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mController.displayPreference(mScreen); + + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mController.onAudioModeChanged(); + shadowOf(Looper.getMainLooper()).idle(); + + assertThat(mPreferenceGroup.getTitle().toString()) + .isEqualTo(mContext.getString(R.string.connected_device_call_device_title)); + + BluetoothDevicePreference preference = createBluetoothDevicePreference(); + mController.onDeviceClick(preference); + verify(mCachedDevice).setActive(); + } + + @Test + public void testInNormalState_showNormalStateTitleAndDoNothingOnDeviceClick() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mController.displayPreference(mScreen); + + mAudioManager.setMode(AudioManager.MODE_NORMAL); + mController.onAudioModeChanged(); + shadowOf(Looper.getMainLooper()).idle(); + + assertThat(mPreferenceGroup.getTitle().toString()) + .isEqualTo(mContext.getString(R.string.audio_sharing_device_group_title)); + + BluetoothDevicePreference preference = createBluetoothDevicePreference(); + mController.onDeviceClick(preference); + + verify(mCachedDevice, never()).setActive(); + } + + @NonNull + private BluetoothDevicePreference createBluetoothDevicePreference() { + Drawable drawable = mock(Drawable.class); + Pair pairs = new Pair<>(drawable, TEST_DEVICE_NAME); + when(mCachedDevice.getDrawableWithDescription()).thenReturn(pairs); + return new BluetoothDevicePreference( + mContext, + mCachedDevice, + /* showDeviceWithoutNames= */ false, + BluetoothDevicePreference.SortType.TYPE_DEFAULT); + } } From 31d82a02883d3add9b229985ace89b12eb4188f0 Mon Sep 17 00:00:00 2001 From: shaoweishen Date: Mon, 26 Aug 2024 09:41:09 +0000 Subject: [PATCH 05/14] [Physical Keyboard][A11y Page] Add custom slider add slider for setting custom value under bounce key dialog. demo video: b/346949547#comment26 Bug: 346949547 Test: atest SettingsRoboTests Flag: com.android.settings.keyboard.keyboard_and_touchpad_a11y_new_page_enabled Change-Id: I3b7f08ebe5ebc287e61713749c193c8b1cf71b99 --- res/layout/dialog_a11y_bounce_key.xml | 67 +++++++++++-- ...oardAccessibilityBounceKeysController.java | 98 ++++++++++++++++--- 2 files changed, 144 insertions(+), 21 deletions(-) diff --git a/res/layout/dialog_a11y_bounce_key.xml b/res/layout/dialog_a11y_bounce_key.xml index 7e236925e18..da3ebde933d 100644 --- a/res/layout/dialog_a11y_bounce_key.xml +++ b/res/layout/dialog_a11y_bounce_key.xml @@ -56,28 +56,79 @@ android:id="@+id/bounce_key_value_200" android:text="@string/bounce_keys_dialog_option_200" android:paddingStart="12dp" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" + android:layout_gravity="start|center_vertical" android:background="@null"/> + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java index 559b2e40fb0..1652f00d1e2 100644 --- a/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java +++ b/src/com/android/settings/inputmethod/KeyboardAccessibilityBounceKeysController.java @@ -21,7 +21,11 @@ import android.hardware.input.InputSettings; import android.net.Uri; import android.provider.Settings; import android.text.TextUtils; +import android.view.View; +import android.widget.RadioButton; import android.widget.RadioGroup; +import android.widget.SeekBar; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,9 +37,13 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settingslib.PrimarySwitchPreference; +import java.util.concurrent.TimeUnit; + public class KeyboardAccessibilityBounceKeysController extends InputSettingPreferenceController implements LifecycleObserver { + private static final int CUSTOM_PROGRESS_INTERVAL = 100; + private static final long MILLISECOND_IN_SECONDS = TimeUnit.SECONDS.toMillis(1); public static final int BOUNCE_KEYS_THRESHOLD = 500; private AlertDialog mAlertDialog; @@ -62,7 +70,7 @@ public class KeyboardAccessibilityBounceKeysController extends } @Override - public boolean handlePreferenceTreeClick(Preference preference) { + public boolean handlePreferenceTreeClick(@NonNull Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { return false; } @@ -105,23 +113,87 @@ public class KeyboardAccessibilityBounceKeysController extends (dialog, which) -> { RadioGroup radioGroup = mAlertDialog.findViewById(R.id.bounce_key_value_group); - int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); - int threshold = checkedRadioButtonId == R.id.bounce_key_value_600 ? 600 - : checkedRadioButtonId == R.id.bounce_key_value_400 ? 400 - : checkedRadioButtonId == R.id.bounce_key_value_200 - ? 200 : 0; + SeekBar seekbar = mAlertDialog.findViewById( + R.id.bounce_key_value_custom_slider); + RadioButton customRadioButton = mAlertDialog.findViewById( + R.id.bounce_key_value_custom); + int threshold; + if (customRadioButton.isChecked()) { + threshold = seekbar.getProgress() * CUSTOM_PROGRESS_INTERVAL; + } else { + int checkedRadioButtonId = radioGroup.getCheckedRadioButtonId(); + threshold = checkedRadioButtonId == R.id.bounce_key_value_600 ? 600 + : checkedRadioButtonId == R.id.bounce_key_value_400 ? 400 + : checkedRadioButtonId == R.id.bounce_key_value_200 + ? 200 : 0; + } InputSettings.setAccessibilityBounceKeysThreshold(context, threshold); }) .setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss()) .create(); mAlertDialog.setOnShowListener(dialog -> { - RadioGroup radioGroup = mAlertDialog.findViewById(R.id.bounce_key_value_group); - int bounceKeysThreshold = InputSettings.getAccessibilityBounceKeysThreshold(context); - switch (bounceKeysThreshold) { - case 600 -> radioGroup.check(R.id.bounce_key_value_600); - case 400 -> radioGroup.check(R.id.bounce_key_value_400); - default -> radioGroup.check(R.id.bounce_key_value_200); - } + RadioGroup cannedValueRadioGroup = mAlertDialog.findViewById( + R.id.bounce_key_value_group); + RadioButton customRadioButton = mAlertDialog.findViewById(R.id.bounce_key_value_custom); + TextView customValueTextView = mAlertDialog.findViewById( + R.id.bounce_key_value_custom_value); + SeekBar customProgressBar = mAlertDialog.findViewById( + R.id.bounce_key_value_custom_slider); + customProgressBar.incrementProgressBy(CUSTOM_PROGRESS_INTERVAL); + customProgressBar.setProgress(1); + View customValueView = mAlertDialog.findViewById(R.id.custom_value_option); + customValueView.setOnClickListener(l -> customRadioButton.performClick()); + customRadioButton.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + cannedValueRadioGroup.clearCheck(); + } + customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE); + customValueTextView.setText( + progressToThresholdInSecond(customProgressBar.getProgress())); + customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE); + buttonView.setChecked(isChecked); + }); + cannedValueRadioGroup.setOnCheckedChangeListener( + (group, checkedId) -> customRadioButton.setChecked(false)); + customProgressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + customValueTextView.setText(progressToThresholdInSecond(progress)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton, customValueTextView, + customProgressBar); }); } + + private static String progressToThresholdInSecond(int progress) { + return String.valueOf((double) progress * CUSTOM_PROGRESS_INTERVAL + / MILLISECOND_IN_SECONDS); + } + + private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup, + RadioButton customRadioButton, TextView customValueTextView, + SeekBar customProgressBar) { + int bounceKeysThreshold = InputSettings.getAccessibilityBounceKeysThreshold(mContext); + switch (bounceKeysThreshold) { + case 600 -> cannedValueRadioGroup.check(R.id.bounce_key_value_600); + case 400 -> cannedValueRadioGroup.check(R.id.bounce_key_value_400); + case 0, 200 -> cannedValueRadioGroup.check(R.id.bounce_key_value_200); + default -> { + customValueTextView.setText( + String.valueOf( + (double) bounceKeysThreshold / MILLISECOND_IN_SECONDS)); + customProgressBar.setProgress(bounceKeysThreshold / CUSTOM_PROGRESS_INTERVAL); + customRadioButton.setChecked(true); + } + } + } } From 012ba80c507aee6dacfa5a9180ca020c84210463 Mon Sep 17 00:00:00 2001 From: chenjean Date: Tue, 8 Oct 2024 16:57:33 +0800 Subject: [PATCH 06/14] Create a method to allow child classes to define it's main switch toggle's pref key We'd like to make the main switch toggle's preference searchable. Since we construct the preference programmatically, this would allow the preference to be automatically scrolled to when the user is brought to this page from a search result. Bug: 372171003 Flag: EXEMPT refactor Test: manual Test: atest ToggleColorInversionPreferenceFragmentTest atest ToggleDaltonizerPreferenceFragmentTest atest ToggleFeaturePreferenceFragmentTest Change-Id: I6eed7598ad296a758573318cf4bde5de30c7005c --- ...chAccessibilityActivityPreferenceFragment.java | 2 +- .../ToggleDaltonizerPreferenceFragment.java | 2 +- .../ToggleFeaturePreferenceFragment.java | 9 ++++++--- ...oggleColorInversionPreferenceFragmentTest.java | 7 +++---- .../ToggleDaltonizerPreferenceFragmentTest.java | 3 +-- .../ToggleFeaturePreferenceFragmentTest.java | 15 +++++---------- 6 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java b/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java index 80d1ce0cdd0..91e65b1d4ec 100644 --- a/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java +++ b/src/com/android/settings/accessibility/LaunchAccessibilityActivityPreferenceFragment.java @@ -67,7 +67,7 @@ public class LaunchAccessibilityActivityPreferenceFragment extends ToggleFeature initLaunchPreference(); final View view = super.onCreateView(inflater, container, savedInstanceState); - removePreference(KEY_USE_SERVICE_PREFERENCE); + removePreference(getUseServicePreferenceKey()); return view; } diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java index 86ddd71e262..d2fc6cc01c1 100644 --- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java @@ -106,7 +106,7 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF final List lists = new ArrayList<>(); lists.add(KEY_TOP_INTRO_PREFERENCE); lists.add(KEY_PREVIEW); - lists.add(KEY_USE_SERVICE_PREFERENCE); + lists.add(getUseServicePreferenceKey()); // Putting saturation level close to the preview so users can see what is changing. lists.add(KEY_SATURATION); lists.add(KEY_DEUTERANOMALY); diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 6649cf48354..a9f422e3749 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -83,7 +83,6 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment public static final String KEY_GENERAL_CATEGORY = "general_categories"; public static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; protected static final String KEY_TOP_INTRO_PREFERENCE = "top_intro"; - protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service"; protected static final String KEY_HTML_DESCRIPTION_PREFERENCE = "html_description"; protected static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow"; protected static final String KEY_SAVED_QS_TOOLTIP_TYPE = "qs_tooltip_type"; @@ -325,6 +324,10 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment switchPreference.setTitle(title); } + protected String getUseServicePreferenceKey() { + return "use_service"; + } + protected CharSequence getShortcutTitle() { return getString(R.string.accessibility_shortcut_title, mPackageName); } @@ -411,7 +414,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment final List lists = new ArrayList<>(); lists.add(KEY_TOP_INTRO_PREFERENCE); lists.add(KEY_ANIMATED_IMAGE); - lists.add(KEY_USE_SERVICE_PREFERENCE); + lists.add(getUseServicePreferenceKey()); lists.add(KEY_GENERAL_CATEGORY); lists.add(KEY_HTML_DESCRIPTION_PREFERENCE); return lists; @@ -476,7 +479,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment private void initToggleServiceSwitchPreference() { mToggleServiceSwitchPreference = new SettingsMainSwitchPreference(getPrefContext()); - mToggleServiceSwitchPreference.setKey(KEY_USE_SERVICE_PREFERENCE); + mToggleServiceSwitchPreference.setKey(getUseServicePreferenceKey()); if (getArguments().containsKey(AccessibilitySettings.EXTRA_CHECKED)) { final boolean enabled = getArguments().getBoolean(AccessibilitySettings.EXTRA_CHECKED); mToggleServiceSwitchPreference.setChecked(enabled); diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java index 1a82a25b2f7..eb2e6fd78c1 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java @@ -18,7 +18,6 @@ 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.ToggleColorInversionPreferenceFragment.KEY_USE_SERVICE_PREFERENCE; import static com.google.common.truth.Truth.assertThat; @@ -93,10 +92,10 @@ public class ToggleColorInversionPreferenceFragmentTest { when(mActivity.getContentResolver()).thenReturn(mContext.getContentResolver()); mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null)); - when(mScreen.findPreference(KEY_USE_SERVICE_PREFERENCE)) + when(mScreen.findPreference(mFragment.getUseServicePreferenceKey())) .thenReturn(mFragment.mToggleServiceSwitchPreference); doReturn(mScreen).when(mFragment).getPreferenceScreen(); - mSwitchPreference = mScreen.findPreference(KEY_USE_SERVICE_PREFERENCE); + mSwitchPreference = mScreen.findPreference(mFragment.getUseServicePreferenceKey()); } @Test @@ -220,7 +219,7 @@ public class ToggleColorInversionPreferenceFragmentTest { mComponentName = PLACEHOLDER_COMPONENT_NAME; final SettingsMainSwitchPreference switchPreference = new SettingsMainSwitchPreference(context); - switchPreference.setKey(KEY_USE_SERVICE_PREFERENCE); + switchPreference.setKey(getUseServicePreferenceKey()); mToggleServiceSwitchPreference = switchPreference; setArguments(new Bundle()); } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java index a5bfec2f0db..fd82994123d 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java @@ -18,7 +18,6 @@ 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.ToggleDaltonizerPreferenceFragment.KEY_USE_SERVICE_PREFERENCE; import static com.google.common.truth.Truth.assertThat; @@ -189,6 +188,6 @@ public class ToggleDaltonizerPreferenceFragmentTest { private SettingsMainSwitchPreference getMainFeatureToggle( ToggleDaltonizerPreferenceFragment fragment) { - return fragment.findPreference(KEY_USE_SERVICE_PREFERENCE); + return fragment.findPreference(fragment.getUseServicePreferenceKey()); } } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java index 71855e023d0..844fabe2647 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java @@ -235,8 +235,7 @@ public class ToggleFeaturePreferenceFragmentTest { @Test @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnDisabledService_notShowTooltipView() { - mFragment.onPreferenceToggled( - ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ false); + mFragment.onPreferenceToggled(mFragment.getUseServicePreferenceKey(), /* enabled= */ false); assertThat(getLatestPopupWindow()).isNull(); } @@ -245,8 +244,7 @@ public class ToggleFeaturePreferenceFragmentTest { @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnEnabledService_showTooltipView() { - mFragment.onPreferenceToggled( - ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true); + mFragment.onPreferenceToggled(mFragment.getUseServicePreferenceKey(), /* enabled= */ true); assertThat(getLatestPopupWindow().isShowing()).isTrue(); } @@ -258,8 +256,7 @@ public class ToggleFeaturePreferenceFragmentTest { suwIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true); when(mActivity.getIntent()).thenReturn(suwIntent); - mFragment.onPreferenceToggled( - ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true); + mFragment.onPreferenceToggled(mFragment.getUseServicePreferenceKey(), /* enabled= */ true); assertThat(getLatestPopupWindow()).isNull(); } @@ -268,12 +265,10 @@ public class ToggleFeaturePreferenceFragmentTest { @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) @Config(shadows = ShadowFragment.class) public void onPreferenceToggledOnEnabledService_tooltipViewShown_notShowTooltipView() { - mFragment.onPreferenceToggled( - ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true); + mFragment.onPreferenceToggled(mFragment.getUseServicePreferenceKey(), /* enabled= */ true); getLatestPopupWindow().dismiss(); - mFragment.onPreferenceToggled( - ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true); + mFragment.onPreferenceToggled(mFragment.getUseServicePreferenceKey(), /* enabled= */ true); assertThat(getLatestPopupWindow().isShowing()).isFalse(); } From 9b62541d801f409b1e998296b35ceb9ffa41fec6 Mon Sep 17 00:00:00 2001 From: alukin Date: Tue, 8 Oct 2024 14:49:41 +0000 Subject: [PATCH 07/14] Remove Android %s from search results Currently when "Android" is entered in Settings search, "Android %s" appears in search results. Removing it from the search results to fix the issue. Bug: 356111486 Bug: 359689134 Bug: 365040064 Test: manually verified Test: atest StorageItemPreferenceControllerTest Change-Id: I4f8c1fb9d94fb585ed4e84654d8a9b335cd5f748 --- res/xml/storage_dashboard_fragment.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index f14f4adad0d..6c2b8d48b66 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -101,7 +101,8 @@ android:key="pref_system" android:title="@string/storage_os_name" android:icon="@drawable/ic_android_vd_theme_24" - android:order="202"/> + android:order="202" + settings:searchable="false"/> Date: Tue, 8 Oct 2024 19:24:35 +0000 Subject: [PATCH 08/14] Don't show default payment component in search if Wallet role is enabled Bug: 372254720 Test: atest PaymentSettingsTest Flag: android.permission.flags.wallet_role_enabled Change-Id: I4044d8fcd95db215d4a06b335b3cb96f8a5e3697 --- .../android/settings/nfc/PaymentSettings.java | 4 ++++ .../settings/nfc/PaymentSettingsTest.java | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java index a1f75bc63d2..28df8ed5989 100644 --- a/src/com/android/settings/nfc/PaymentSettings.java +++ b/src/com/android/settings/nfc/PaymentSettings.java @@ -30,6 +30,7 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import com.android.internal.hidden_from_bootclasspath.android.permission.flags.Flags; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; @@ -120,6 +121,9 @@ public class PaymentSettings extends DashboardFragment { @Override protected boolean isPageSearchEnabled(Context context) { + if (Flags.walletRoleEnabled()) { + return false; + } final UserManager userManager = context.getSystemService(UserManager.class); final UserInfo myUserInfo = userManager.getUserInfo(UserHandle.myUserId()); if (myUserInfo.isGuest()) { diff --git a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java index 458bc93d38c..7380c6688e4 100644 --- a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java +++ b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java @@ -28,6 +28,10 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.preference.Preference; import androidx.preference.PreferenceManager; @@ -36,6 +40,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.testutils.shadow.ShadowNfcAdapter; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -58,6 +63,9 @@ public class PaymentSettingsTest { private Context mContext; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Mock private PackageManager mPackageManager; @@ -98,7 +106,19 @@ public class PaymentSettingsTest { } @Test - public void getNonIndexableKey_primaryUser_returnsTrue() { + @RequiresFlagsEnabled(android.permission.flags.Flags.FLAG_WALLET_ROLE_ENABLED) + public void getNonIndexableKey_primaryUser_returnsFalse_walletRoleEnabled() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + + final List niks = + PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(niks).containsAtLeast(FOREGROUND_KEY, PAYMENT_KEY); + } + + @Test + @RequiresFlagsDisabled(android.permission.flags.Flags.FLAG_WALLET_ROLE_ENABLED) + public void getNonIndexableKey_primaryUser_returnsTrue_walletRoleDisabled() { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); final List niks = From 3079b2d108a39c8bd257e4ad8a1dadf9f4b2713d Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Fri, 6 Sep 2024 22:00:39 +0000 Subject: [PATCH 09/14] Makes Settings > Accessibility > Magnification prefs searchable. All preferences are searchable except for "Keep on while switching apps" which is only searchable if the user already has a magnification shortcut enabled, to minimize user confusion from that generically-named preference. NO_IFTTT=adding IFTTT Fix: 353772926 Test: atest ToggleScreenMagnificationPreferenceFragmentTest Flag: com.android.settings.accessibility.fix_a11y_settings_search Test: adb shell pm clear com.google.android.settings.intelligence; search Settings for the items in the bug Change-Id: I01c7e5586ec0ea432cb2df80f156141683b97522 --- ...ScreenMagnificationPreferenceFragment.java | 248 +++++++++++++----- ...enMagnificationPreferenceFragmentTest.java | 109 +++++++- 2 files changed, 288 insertions(+), 69 deletions(-) diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index bc14288f335..ee49450f82d 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -54,7 +54,6 @@ import androidx.annotation.StringRes; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.SwitchPreferenceCompat; -import androidx.preference.TwoStatePreference; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; @@ -64,7 +63,11 @@ import com.android.settings.DialogCreatable; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment; +import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.search.Indexable; +import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.widget.IllustrationPreference; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -73,16 +76,20 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.StringJoiner; +import java.util.stream.Stream; /** * Fragment that shows the actual UI for providing basic magnification accessibility service setup * and does not have toggle bar to turn on service to use. */ +@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class ToggleScreenMagnificationPreferenceFragment extends ToggleFeaturePreferenceFragment implements MagnificationModePreferenceController.DialogHelper { private static final String TAG = "ToggleScreenMagnificationPreferenceFragment"; + @VisibleForTesting + static final String KEY_MAGNIFICATION_SHORTCUT_PREFERENCE = "magnification_shortcut_preference"; private static final char COMPONENT_NAME_SEPARATOR = ':'; private static final TextUtils.SimpleStringSplitter sStringColonSplitter = new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); @@ -181,38 +188,29 @@ public class ToggleScreenMagnificationPreferenceFragment extends } } + private static boolean isWindowMagnificationSupported(Context context) { + return context.getResources().getBoolean( + com.android.internal.R.bool.config_magnification_area) + && context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WINDOW_MAGNIFICATION); + } + @Override protected void initSettingsPreference() { // If the device doesn't support window magnification feature, it should hide the // settings preference. - final boolean supportWindowMagnification = - getContext().getResources().getBoolean( - com.android.internal.R.bool.config_magnification_area) - && getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WINDOW_MAGNIFICATION); - if (!supportWindowMagnification) { + if (!isWindowMagnificationSupported(getContext())) { return; } - mSettingsPreference = new Preference(getPrefContext()); - mSettingsPreference.setTitle(R.string.accessibility_magnification_mode_title); - mSettingsPreference.setKey(MagnificationModePreferenceController.PREF_KEY); - mSettingsPreference.setPersistent(false); final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); - generalCategory.addPreference(mSettingsPreference); - - final MagnificationModePreferenceController magnificationModePreferenceController = - new MagnificationModePreferenceController(getContext(), - MagnificationModePreferenceController.PREF_KEY); - magnificationModePreferenceController.setDialogHelper(this); - getSettingsLifecycle().addObserver(magnificationModePreferenceController); - magnificationModePreferenceController.displayPreference(getPreferenceScreen()); - addPreferenceController(magnificationModePreferenceController); - + // LINT.IfChange(:preference_list) + addMagnificationModeSetting(generalCategory); addFollowTypingSetting(generalCategory); addOneFingerPanningSetting(generalCategory); addAlwaysOnSetting(generalCategory); addJoystickSetting(generalCategory); + // LINT.ThenChange(:search_data) } @Override @@ -233,22 +231,44 @@ public class ToggleScreenMagnificationPreferenceFragment extends && !Flags.enableMagnificationOneFingerPanningGesture()) { String summary = MessageFormat.format( context.getString(R.string.accessibility_screen_magnification_summary), - new Object[]{1, 2, 3, 4, 5}); + new Object[]{1, 2, 3, 4, 5}); arguments.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary); } super.onProcessArguments(arguments); } + private static Preference createMagnificationModePreference(Context context) { + final Preference pref = new Preference(context); + pref.setTitle(R.string.accessibility_magnification_mode_title); + pref.setKey(MagnificationModePreferenceController.PREF_KEY); + pref.setPersistent(false); + return pref; + } + + private void addMagnificationModeSetting(PreferenceCategory generalCategory) { + mSettingsPreference = createMagnificationModePreference(getPrefContext()); + generalCategory.addPreference(mSettingsPreference); + + final MagnificationModePreferenceController magnificationModePreferenceController = + new MagnificationModePreferenceController(getContext(), + MagnificationModePreferenceController.PREF_KEY); + magnificationModePreferenceController.setDialogHelper(this); + getSettingsLifecycle().addObserver(magnificationModePreferenceController); + magnificationModePreferenceController.displayPreference(getPreferenceScreen()); + addPreferenceController(magnificationModePreferenceController); + } + + private static Preference createFollowTypingPreference(Context context) { + final Preference pref = new SwitchPreferenceCompat(context); + pref.setTitle(R.string.accessibility_screen_magnification_follow_typing_title); + pref.setSummary(R.string.accessibility_screen_magnification_follow_typing_summary); + pref.setKey(MagnificationFollowTypingPreferenceController.PREF_KEY); + return pref; + } + private void addFollowTypingSetting(PreferenceCategory generalCategory) { - var followingTypingSwitchPreference = new SwitchPreferenceCompat(getPrefContext()); - followingTypingSwitchPreference.setTitle( - R.string.accessibility_screen_magnification_follow_typing_title); - followingTypingSwitchPreference.setSummary( - R.string.accessibility_screen_magnification_follow_typing_summary); - followingTypingSwitchPreference.setKey( - MagnificationFollowTypingPreferenceController.PREF_KEY); - generalCategory.addPreference(followingTypingSwitchPreference); + generalCategory.addPreference(createFollowTypingPreference(getPrefContext())); var followTypingPreferenceController = new MagnificationFollowTypingPreferenceController( getContext(), MagnificationFollowTypingPreferenceController.PREF_KEY); @@ -257,8 +277,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends addPreferenceController(followTypingPreferenceController); } - private boolean isAlwaysOnSettingEnabled() { - final boolean defaultValue = getContext().getResources().getBoolean( + private static boolean isAlwaysOnSupported(Context context) { + final boolean defaultValue = context.getResources().getBoolean( com.android.internal.R.bool.config_magnification_always_on_enabled); return DeviceConfig.getBoolean( @@ -268,19 +288,21 @@ public class ToggleScreenMagnificationPreferenceFragment extends ); } + private static Preference createAlwaysOnPreference(Context context) { + final Preference pref = new SwitchPreferenceCompat(context); + pref.setTitle(R.string.accessibility_screen_magnification_always_on_title); + pref.setSummary(R.string.accessibility_screen_magnification_always_on_summary); + pref.setKey(MagnificationAlwaysOnPreferenceController.PREF_KEY); + return pref; + } + private void addAlwaysOnSetting(PreferenceCategory generalCategory) { - if (!isAlwaysOnSettingEnabled()) { + if (!isAlwaysOnSupported(getContext())) { return; } - var alwaysOnPreference = new SwitchPreferenceCompat(getPrefContext()); - alwaysOnPreference.setTitle( - R.string.accessibility_screen_magnification_always_on_title); - alwaysOnPreference.setSummary( - R.string.accessibility_screen_magnification_always_on_summary); - alwaysOnPreference.setKey( - MagnificationAlwaysOnPreferenceController.PREF_KEY); - generalCategory.addPreference(alwaysOnPreference); + final Preference pref = createAlwaysOnPreference(getPrefContext()); + generalCategory.addPreference(pref); var alwaysOnPreferenceController = new MagnificationAlwaysOnPreferenceController( getContext(), MagnificationAlwaysOnPreferenceController.PREF_KEY); @@ -290,17 +312,24 @@ public class ToggleScreenMagnificationPreferenceFragment extends addPreferenceController(alwaysOnPreferenceController); } + private static Preference createOneFingerPanningPreference(Context context) { + final Preference pref = new SwitchPreferenceCompat(context); + pref.setTitle(R.string.accessibility_magnification_one_finger_panning_title); + pref.setKey(MagnificationOneFingerPanningPreferenceController.PREF_KEY); + return pref; + } + + private static boolean isOneFingerPanningSupported() { + return Flags.enableMagnificationOneFingerPanningGesture(); + } + private void addOneFingerPanningSetting(PreferenceCategory generalCategory) { - if (!Flags.enableMagnificationOneFingerPanningGesture()) { + if (!isOneFingerPanningSupported()) { return; } - var oneFingerPanningPreference = new SwitchPreferenceCompat(getPrefContext()); - oneFingerPanningPreference.setTitle( - R.string.accessibility_magnification_one_finger_panning_title); - oneFingerPanningPreference.setKey( - MagnificationOneFingerPanningPreferenceController.PREF_KEY); - generalCategory.addPreference(oneFingerPanningPreference); + final Preference pref = createOneFingerPanningPreference(getPrefContext()); + generalCategory.addPreference(pref); mOneFingerPanningPreferenceController = new MagnificationOneFingerPanningPreferenceController(getContext()); @@ -310,23 +339,28 @@ public class ToggleScreenMagnificationPreferenceFragment extends addPreferenceController(mOneFingerPanningPreferenceController); } - private void addJoystickSetting(PreferenceCategory generalCategory) { - if (!DeviceConfig.getBoolean( + private static Preference createJoystickPreference(Context context) { + final Preference pref = new SwitchPreferenceCompat(context); + pref.setTitle(R.string.accessibility_screen_magnification_joystick_title); + pref.setSummary(R.string.accessibility_screen_magnification_joystick_summary); + pref.setKey(MagnificationJoystickPreferenceController.PREF_KEY); + return pref; + } + + private static boolean isJoystickSupported() { + return DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_WINDOW_MANAGER, "MagnificationJoystick__enable_magnification_joystick", - false - )) { + false); + } + + private void addJoystickSetting(PreferenceCategory generalCategory) { + if (!isJoystickSupported()) { return; } - TwoStatePreference joystickPreference = new SwitchPreferenceCompat(getPrefContext()); - joystickPreference.setTitle( - R.string.accessibility_screen_magnification_joystick_title); - joystickPreference.setSummary( - R.string.accessibility_screen_magnification_joystick_summary); - joystickPreference.setKey( - MagnificationJoystickPreferenceController.PREF_KEY); - generalCategory.addPreference(joystickPreference); + final Preference pref = createJoystickPreference(getPrefContext()); + generalCategory.addPreference(pref); MagnificationJoystickPreferenceController joystickPreferenceController = new MagnificationJoystickPreferenceController( @@ -354,9 +388,9 @@ public class ToggleScreenMagnificationPreferenceFragment extends super.registerKeysToObserverCallback(contentObserver); var keysToObserve = List.of( - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, - Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, + Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED ); contentObserver.registerKeysToObserverCallback(keysToObserve, key -> updatePreferencesState()); @@ -409,7 +443,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends return getShortcutSummaryList(context, PreferredShortcuts.retrieveUserShortcutType(context, - MAGNIFICATION_CONTROLLER_NAME)); + MAGNIFICATION_CONTROLLER_NAME)); } @Override @@ -517,6 +551,11 @@ public class ToggleScreenMagnificationPreferenceFragment extends generalCategory.addPreference(mShortcutPreference); } + @Override + protected String getShortcutPreferenceKey() { + return KEY_MAGNIFICATION_SHORTCUT_PREFERENCE; + } + @Override protected CharSequence getShortcutTitle() { return getText(R.string.accessibility_screen_magnification_shortcut_title); @@ -777,8 +816,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends final int userShortcutType = getUserShortcutTypeFromSettings(context); final CharSequence featureState = (userShortcutType != DEFAULT) - ? context.getText(R.string.accessibility_summary_shortcut_enabled) - : context.getText(R.string.generic_accessibility_feature_shortcut_off); + ? context.getText(R.string.accessibility_summary_shortcut_enabled) + : context.getText(R.string.generic_accessibility_feature_shortcut_off); final CharSequence featureSummary = context.getText(R.string.magnification_feature_summary); return context.getString( com.android.settingslib.R.string.preference_summary_default_combination, @@ -790,4 +829,81 @@ public class ToggleScreenMagnificationPreferenceFragment extends return PreferredShortcuts.retrieveUserShortcutType( getPrefContext(), MAGNIFICATION_CONTROLLER_NAME); } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + // LINT.IfChange(:search_data) + @Override + public List getRawDataToIndex(Context context, + boolean enabled) { + final List rawData = + super.getRawDataToIndex(context, enabled); + + if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) { + return rawData; + } + + rawData.add(createShortcutPreferenceSearchData(context)); + Stream.of( + createMagnificationModePreference(context), + createFollowTypingPreference(context), + createOneFingerPanningPreference(context), + createAlwaysOnPreference(context), + createJoystickPreference(context) + ) + .forEach(pref -> + rawData.add(createPreferenceSearchData(context, pref))); + return rawData; + } + + @Override + public List getNonIndexableKeys(Context context) { + final List niks = super.getNonIndexableKeys(context); + + if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) { + return niks; + } + + if (!isWindowMagnificationSupported(context)) { + niks.add(MagnificationModePreferenceController.PREF_KEY); + niks.add(MagnificationFollowTypingPreferenceController.PREF_KEY); + niks.add(MagnificationOneFingerPanningPreferenceController.PREF_KEY); + niks.add(MagnificationAlwaysOnPreferenceController.PREF_KEY); + niks.add(MagnificationJoystickPreferenceController.PREF_KEY); + } else { + if (!isAlwaysOnSupported(context) + // This preference's title "Keep on while switching apps" does not + // mention magnification so it may confuse users who search a term + // like "Keep on". + // So we hide it if the user has no magnification shortcut enabled. + || getUserShortcutTypeFromSettings(context) == DEFAULT) { + niks.add(MagnificationAlwaysOnPreferenceController.PREF_KEY); + } + if (!isOneFingerPanningSupported()) { + niks.add(MagnificationOneFingerPanningPreferenceController.PREF_KEY); + } + if (!isJoystickSupported()) { + niks.add(MagnificationJoystickPreferenceController.PREF_KEY); + } + } + return niks; + } + // LINT.ThenChange(:preference_list) + + private SearchIndexableRaw createPreferenceSearchData( + Context context, Preference pref) { + final SearchIndexableRaw raw = new SearchIndexableRaw(context); + raw.key = pref.getKey(); + raw.title = pref.getTitle().toString(); + return raw; + } + + private SearchIndexableRaw createShortcutPreferenceSearchData(Context context) { + final SearchIndexableRaw raw = new SearchIndexableRaw(context); + raw.key = KEY_MAGNIFICATION_SHORTCUT_PREFERENCE; + raw.title = context.getString( + R.string.accessibility_screen_magnification_shortcut_title); + return raw; + } + }; } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java index 038672fc198..87632ae8a64 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java @@ -24,6 +24,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; import static com.android.settings.accessibility.AccessibilityUtil.State.ON; import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode; +import static com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment.KEY_MAGNIFICATION_SHORTCUT_PREFERENCE; import static com.google.common.truth.Truth.assertThat; @@ -70,6 +71,7 @@ import com.android.settings.testutils.shadow.ShadowDeviceConfig; import com.android.settings.testutils.shadow.ShadowStorageManager; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.search.SearchIndexableRaw; import com.google.common.truth.Correspondence; @@ -539,7 +541,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { @Test public void optInAllValuesToSettings_software_sizeValueIsNotNull_sizeValueIsNotChanged() { - for (int size : new int[] {FloatingMenuSizePreferenceController.Size.LARGE, + for (int size : new int[]{FloatingMenuSizePreferenceController.Size.LARGE, FloatingMenuSizePreferenceController.Size.SMALL}) { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size); @@ -557,7 +559,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { @Test public void optInAllValuesToSettings_hardware_sizeValueIsNotChanged() { - for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN, + for (int size : new int[]{FloatingMenuSizePreferenceController.Size.UNKNOWN, FloatingMenuSizePreferenceController.Size.LARGE, FloatingMenuSizePreferenceController.Size.SMALL}) { Settings.Secure.putInt(mContext.getContentResolver(), @@ -575,7 +577,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { @Test public void optInAllValuesToSettings_tripletap_sizeValueIsNotChanged() { - for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN, + for (int size : new int[]{FloatingMenuSizePreferenceController.Size.UNKNOWN, FloatingMenuSizePreferenceController.Size.LARGE, FloatingMenuSizePreferenceController.Size.SMALL}) { Settings.Secure.putInt(mContext.getContentResolver(), @@ -1025,6 +1027,107 @@ public class ToggleScreenMagnificationPreferenceFragmentTest { .isEqualTo(collectionInfo.getImportantForAccessibilityItemCount() + 1); } + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getRawDataToIndex_returnsAllPreferenceKeys() { + List expectedSearchKeys = List.of( + KEY_MAGNIFICATION_SHORTCUT_PREFERENCE, + MagnificationModePreferenceController.PREF_KEY, + MagnificationFollowTypingPreferenceController.PREF_KEY, + MagnificationOneFingerPanningPreferenceController.PREF_KEY, + MagnificationAlwaysOnPreferenceController.PREF_KEY, + MagnificationJoystickPreferenceController.PREF_KEY); + + final List rawData = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true); + final List actualSearchKeys = rawData.stream().map(raw -> raw.key).toList(); + + assertThat(actualSearchKeys).containsExactlyElementsIn(expectedSearchKeys); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void + getNonIndexableKeys_windowMagnificationNotSupported_onlyShortcutPreferenceSearchable() { + setWindowMagnificationSupported(false, false); + + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + final List rawData = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true); + // Expect all search data, except the shortcut preference, to be in NIKs. + final List expectedNiks = rawData.stream().map(raw -> raw.key) + .filter(key -> !key.equals(KEY_MAGNIFICATION_SHORTCUT_PREFERENCE)).toList(); + + // In NonIndexableKeys == not searchable + assertThat(niks).containsExactlyElementsIn(expectedNiks); + } + + @Test + @EnableFlags({ + com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH, + Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE}) + public void getNonIndexableKeys_hasShortcutAndAllFeaturesEnabled_allItemsSearchable() { + setMagnificationTripleTapEnabled(true); + setAlwaysOnSupported(true); + setJoystickSupported(true); + + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + // Empty NonIndexableKeys == all indexed items are searchable + assertThat(niks).isEmpty(); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getNonIndexableKeys_noShortcut_alwaysOnSupported_notSearchable() { + setMagnificationTripleTapEnabled(false); + setAlwaysOnSupported(true); + + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + // In NonIndexableKeys == not searchable + assertThat(niks).contains(MagnificationAlwaysOnPreferenceController.PREF_KEY); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getNonIndexableKeys_hasShortcut_alwaysOnNotSupported_notSearchable() { + setMagnificationTripleTapEnabled(true); + setAlwaysOnSupported(false); + + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + // In NonIndexableKeys == not searchable + assertThat(niks).contains(MagnificationAlwaysOnPreferenceController.PREF_KEY); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + @DisableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE) + public void getNonIndexableKeys_oneFingerPanningNotSupported_notSearchable() { + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + // In NonIndexableKeys == not searchable + assertThat(niks).contains(MagnificationOneFingerPanningPreferenceController.PREF_KEY); + } + + @Test + @EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getNonIndexableKeys_joystickNotSupported_notSearchable() { + setJoystickSupported(false); + + final List niks = ToggleScreenMagnificationPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + // In NonIndexableKeys == not searchable + assertThat(niks).contains(MagnificationJoystickPreferenceController.PREF_KEY); + } + private void putStringIntoSettings(String key, String componentName) { Settings.Secure.putString(mContext.getContentResolver(), key, componentName); } From 806b91414d221ec98472a9be261f9d02063912dd Mon Sep 17 00:00:00 2001 From: chenjean Date: Mon, 7 Oct 2024 15:24:57 +0800 Subject: [PATCH 10/14] Makes Use Color inversion searchable. Fix: 354773587 Flag: com.android.settings.accessibility.fix_a11y_settings_search Test: atest ToggleColorInversionPreferenceFragmentTest Test: adb shell pm clear com.google.android.settings.intelligence; search Settings for 'use color inversion', observe 'use color inversion' present; Change-Id: Iad13fbe163002af6e84a79fdeafb8517d53e2b09 --- ...oggleColorInversionPreferenceFragment.java | 38 ++++++++++++---- ...eColorInversionPreferenceFragmentTest.java | 43 ++++++++++++++++++- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java index ccba9e7f68a..24aae3f521c 100644 --- a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java @@ -33,6 +33,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.VisibleForTesting; + import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; import com.android.settings.search.BaseSearchIndexProvider; @@ -52,7 +54,10 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere private static final String TAG = "ToggleColorInversionPreferenceFragment"; private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED; - private static final String KEY_SHORTCUT_PREFERENCE = "color_inversion_shortcut_key"; + @VisibleForTesting + static final String KEY_SHORTCUT_PREFERENCE = "color_inversion_shortcut_key"; + @VisibleForTesting + static final String KEY_SWITCH_PREFERENCE = "color_inversion_switch_preference_key"; @Override protected void registerKeysToObserverCallback( @@ -73,9 +78,9 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere mHtmlDescription = getText(R.string.accessibility_display_inversion_preference_subtitle); mTopIntroTitle = getText(R.string.accessibility_display_inversion_preference_intro_text); mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) - .authority(getPrefContext().getPackageName()) - .appendPath(String.valueOf(R.raw.a11y_color_inversion_banner)) - .build(); + .authority(getPrefContext().getPackageName()) + .appendPath(String.valueOf(R.raw.a11y_color_inversion_banner)) + .build(); final View view = super.onCreateView(inflater, container, savedInstanceState); updateFooterPreference(); return view; @@ -131,6 +136,11 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere switchPreference.setTitle(R.string.accessibility_display_inversion_switch_title); } + @Override + protected String getUseServicePreferenceKey() { + return KEY_SWITCH_PREFERENCE; + } + @Override protected CharSequence getShortcutTitle() { return getText(R.string.accessibility_display_inversion_shortcut_title); @@ -165,7 +175,7 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere @Override int getUserShortcutTypes() { return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), - mComponentName); + mComponentName); } @Override @@ -176,8 +186,8 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere @Override CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) { return getText(type == QuickSettingsTooltipType.GUIDE_TO_EDIT - ? R.string.accessibility_color_inversion_qs_tooltip_content - : R.string.accessibility_color_inversion_auto_added_qs_tooltip_content); + ? R.string.accessibility_color_inversion_qs_tooltip_content + : R.string.accessibility_color_inversion_auto_added_qs_tooltip_content); } @Override @@ -194,12 +204,22 @@ public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePrefere @Override public List getRawDataToIndex(Context context, boolean enabled) { - final List rawData = new ArrayList<>(); + final List rawData = + super.getRawDataToIndex(context, enabled); + SearchIndexableRaw raw = new SearchIndexableRaw(context); raw.key = KEY_SHORTCUT_PREFERENCE; raw.title = context.getString( - R.string.accessibility_display_inversion_shortcut_title); + R.string.accessibility_display_inversion_shortcut_title); rawData.add(raw); + + if (Flags.fixA11ySettingsSearch()) { + SearchIndexableRaw mainPreferenceRaw = new SearchIndexableRaw(context); + mainPreferenceRaw.key = KEY_SWITCH_PREFERENCE; + mainPreferenceRaw.title = context.getString( + R.string.accessibility_display_inversion_switch_title); + rawData.add(mainPreferenceRaw); + } return rawData; } }; diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java index eb2e6fd78c1..e9711864909 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java @@ -18,6 +18,8 @@ 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.ToggleColorInversionPreferenceFragment.KEY_SHORTCUT_PREFERENCE; +import static com.android.settings.accessibility.ToggleColorInversionPreferenceFragment.KEY_SWITCH_PREFERENCE; import static com.google.common.truth.Truth.assertThat; @@ -31,12 +33,12 @@ import android.content.ComponentName; import android.content.Context; import android.os.Bundle; import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.Flags; import android.widget.PopupWindow; import androidx.fragment.app.FragmentActivity; @@ -49,6 +51,7 @@ import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltip import com.android.settings.testutils.XmlTestUtils; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.widget.SettingsMainSwitchPreference; +import com.android.settingslib.search.SearchIndexableRaw; import org.junit.Before; import org.junit.Rule; @@ -62,6 +65,7 @@ import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowApplication; +import java.util.ArrayList; import java.util.List; /** Tests for {@link ToggleColorInversionPreferenceFragment} */ @@ -136,7 +140,7 @@ public class ToggleColorInversionPreferenceFragmentTest { } @Test - @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, OFF); @@ -198,6 +202,41 @@ public class ToggleColorInversionPreferenceFragmentTest { assertThat(keys).containsAtLeastElementsIn(niks); } + @Test + @DisableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getRawDataToIndex_flagOff_returnShortcutIndexablePreferences() { + List rawData = ToggleColorInversionPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, /* enabled= */ true); + + assertThat(rawData).hasSize(1); + assertThat(rawData.get(0).key).isEqualTo(KEY_SHORTCUT_PREFERENCE); + assertThat(rawData.get(0).title).isEqualTo(mContext.getString( + R.string.accessibility_display_inversion_shortcut_title)); + + } + + @Test + @EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getRawDataToIndex_flagOn_returnAllIndexablePreferences() { + String[] expectedKeys = {KEY_SHORTCUT_PREFERENCE, KEY_SWITCH_PREFERENCE}; + String[] expectedTitles = { + mContext.getString(R.string.accessibility_display_inversion_shortcut_title), + mContext.getString(R.string.accessibility_display_inversion_switch_title)}; + List keysResultList = new ArrayList<>(); + List titlesResultList = new ArrayList<>(); + List rawData = ToggleColorInversionPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, /* enabled= */ true); + + for (SearchIndexableRaw rawDataItem : rawData) { + keysResultList.add(rawDataItem.key); + titlesResultList.add(rawDataItem.title); + } + + assertThat(rawData).hasSize(2); + assertThat(keysResultList).containsExactly(expectedKeys); + assertThat(titlesResultList).containsExactly(expectedTitles); + } + private static PopupWindow getLatestPopupWindow() { final ShadowApplication shadowApplication = Shadow.extract(ApplicationProvider.getApplicationContext()); From f3095002811d1930b5c7f459dd28f075eb86811a Mon Sep 17 00:00:00 2001 From: yomna Date: Tue, 8 Oct 2024 20:35:40 +0000 Subject: [PATCH 11/14] Handle IllegalStateExceptions in CellularSecurityPreferenceController Bug: b/354833801, b/369941495, b/371447524, b/371689932 Flag: EXEMPT bug fix Test: m Change-Id: Ic21021016dcfe7fcc9cf2314117ab0e3cc84757e --- .../network/CellularSecurityPreferenceController.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/network/CellularSecurityPreferenceController.java b/src/com/android/settings/network/CellularSecurityPreferenceController.java index f43805ef83a..0b0c2a7e948 100644 --- a/src/com/android/settings/network/CellularSecurityPreferenceController.java +++ b/src/com/android/settings/network/CellularSecurityPreferenceController.java @@ -88,10 +88,10 @@ public class CellularSecurityPreferenceController extends BasePreferenceControll } catch (UnsupportedOperationException e) { Log.i(LOG_TAG, "Null cipher enablement is unsupported, hiding divider: " + e.getMessage()); - } catch (Exception e) { + } catch (IllegalStateException e) { Log.e(LOG_TAG, "Failed isNullCipherAndIntegrityEnabled. Setting availability to " - + "CONDITIONALLY_UNAVAILABLE. Exception: " + + "UNSUPPORTED_ON_DEVICE. Exception: " + e.getMessage()); } @@ -104,6 +104,12 @@ public class CellularSecurityPreferenceController extends BasePreferenceControll } catch (UnsupportedOperationException e) { Log.i(LOG_TAG, "Cellular security notifications are unsupported, hiding divider: " + e.getMessage()); + } catch (IllegalStateException e) { + Log.e(LOG_TAG, + "Failed isNullCipherNotificationsEnabled, " + + "isCellularIdentifierDisclosureNotificationsEnabled. " + + "Setting availability to UNSUPPORTED_ON_DEVICE. Exception: " + + e.getMessage()); } if (isNullCipherDisablementAvailable || areCellSecNotificationsAvailable) { From c3b20d3a316cee8b482776dc43b235565749f3e1 Mon Sep 17 00:00:00 2001 From: mxyyiyi Date: Wed, 9 Oct 2024 13:31:18 +0800 Subject: [PATCH 12/14] Also clear the foreground service usage time for BatteryDiffEntry should hide background usage time. - Usage time in background is the sum{bg + fgs} usage time Bug: 371919020 Fix: 371919020 Test: atest DataProcessorTest Flag: EXEMPT for simple fix Change-Id: I058d8511eac7510e2df6d9ac1713824cd8dbf3ba --- .../batteryusage/BatteryDiffData.java | 1 + .../batteryusage/DataProcessorTest.java | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java index b5d50994ed7..fb5a9f36dbd 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java @@ -169,6 +169,7 @@ public class BatteryDiffData { } if (packageName != null && hideBackgroundUsageTimeSet.contains(packageName)) { entry.mBackgroundUsageTimeInMs = 0; + entry.mForegroundServiceUsageTimeInMs = 0; } } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java index ae4c56d035a..1f3067e81ce 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java @@ -903,6 +903,7 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, + 0L, false)), batteryHistoryKeys[1], Map.of( @@ -920,6 +921,7 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, + 0L, false)), batteryHistoryKeys[2], Map.of( @@ -937,6 +939,7 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, + 0L, false))); final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys); final Map>>>> @@ -993,6 +996,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); // Adds the index = 0 data. @@ -1010,6 +1014,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1034,6 +1039,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 15L, + /* foregroundServiceUsageTimeInMs= */ 20L, /* backgroundUsageTimeInMs= */ 25L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1054,6 +1060,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 25L, + /* foregroundServiceUsageTimeInMs= */ 30L, /* backgroundUsageTimeInMs= */ 35L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1070,6 +1077,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /* foregroundUsageTimeInMs= */ 40L, + /* foregroundServiceUsageTimeInMs= */ 45L, /* backgroundUsageTimeInMs= */ 50L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1086,6 +1094,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 5L, + /* foregroundServiceUsageTimeInMs= */ 5L, /* backgroundUsageTimeInMs= */ 5L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1106,6 +1115,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 30L, + /* foregroundServiceUsageTimeInMs= */ 35L, /* backgroundUsageTimeInMs= */ 40L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1122,6 +1132,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /* foregroundUsageTimeInMs= */ 50L, + /* foregroundServiceUsageTimeInMs= */ 55L, /* backgroundUsageTimeInMs= */ 60L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1138,6 +1149,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 5L, + /* foregroundServiceUsageTimeInMs= */ 5L, /* backgroundUsageTimeInMs= */ 5L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1195,6 +1207,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 9, /* cachedUsageConsumePower= */ 8, /* foregroundUsageTimeInMs= */ 30, + /* foregroundServiceUsageTimeInMs= */ 35, /* backgroundUsageTimeInMs= */ 40, /* screenOnTimeInMs= */ 12); assertBatteryDiffEntry( @@ -1208,6 +1221,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 8, /* cachedUsageConsumePower= */ 8, /* foregroundUsageTimeInMs= */ 5, + /* foregroundServiceUsageTimeInMs= */ 5, /* backgroundUsageTimeInMs= */ 5, /* screenOnTimeInMs= */ 0); assertBatteryDiffEntry( @@ -1221,6 +1235,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 5, /* cachedUsageConsumePower= */ 5, /* foregroundUsageTimeInMs= */ 16, + /* foregroundServiceUsageTimeInMs= */ 55, /* backgroundUsageTimeInMs= */ 60, /* screenOnTimeInMs= */ 9); resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL); @@ -1235,6 +1250,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 5, /* cachedUsageConsumePower= */ 5, /* foregroundUsageTimeInMs= */ 15, + /* foregroundServiceUsageTimeInMs= */ 20, /* backgroundUsageTimeInMs= */ 25, /* screenOnTimeInMs= */ 5); resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL); @@ -1249,6 +1265,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 8, /* cachedUsageConsumePower= */ 8, /* foregroundUsageTimeInMs= */ 5, + /* foregroundServiceUsageTimeInMs= */ 5, /* backgroundUsageTimeInMs= */ 5, /* screenOnTimeInMs= */ 0); assertBatteryDiffEntry( @@ -1262,6 +1279,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 4, /* cachedUsageConsumePower= */ 3, /* foregroundUsageTimeInMs= */ 15, + /* foregroundServiceUsageTimeInMs= */ 15, /* backgroundUsageTimeInMs= */ 15, /* screenOnTimeInMs= */ 7); assertBatteryDiffEntry( @@ -1275,6 +1293,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 5, /* cachedUsageConsumePower= */ 5, /* foregroundUsageTimeInMs= */ 16, + /* foregroundServiceUsageTimeInMs= */ 55, /* backgroundUsageTimeInMs= */ 60, /* screenOnTimeInMs= */ 9); } @@ -1308,6 +1327,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1324,6 +1344,7 @@ public final class DataProcessorTest { currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1340,6 +1361,7 @@ public final class DataProcessorTest { currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 20L, + /* foregroundServiceUsageTimeInMs= */ 25L, /* backgroundUsageTimeInMs= */ 30L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1359,6 +1381,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 20L, + /* foregroundServiceUsageTimeInMs= */ 25L, /* backgroundUsageTimeInMs= */ 30L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1375,6 +1398,7 @@ public final class DataProcessorTest { currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1391,6 +1415,7 @@ public final class DataProcessorTest { currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 30L, + /* foregroundServiceUsageTimeInMs= */ 30L, /* backgroundUsageTimeInMs= */ 30L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1410,6 +1435,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 20L, + /* foregroundServiceUsageTimeInMs= */ 25L, /* backgroundUsageTimeInMs= */ 30L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1426,6 +1452,7 @@ public final class DataProcessorTest { currentUserId + 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 20L, + /* foregroundServiceUsageTimeInMs= */ 20L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1442,6 +1469,7 @@ public final class DataProcessorTest { currentUserId + 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 30L, + /* foregroundServiceUsageTimeInMs= */ 30L, /* backgroundUsageTimeInMs= */ 30L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1477,6 +1505,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 5, /* cachedUsageConsumePower= */ 5, /* foregroundUsageTimeInMs= */ 10, + /* foregroundServiceUsageTimeInMs= */ 10, /* backgroundUsageTimeInMs= */ 10, /* screenOnTimeInMs= */ 0); assertThat(resultDiffData.getSystemDiffEntryList()).isEmpty(); @@ -1509,6 +1538,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1528,6 +1558,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1547,6 +1578,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 3600000L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 7200000L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1587,6 +1619,7 @@ public final class DataProcessorTest { final BatteryDiffEntry resultEntry = resultDiffData.getAppDiffEntryList().get(0); assertThat(resultEntry.mForegroundUsageTimeInMs) .isEqualTo(Math.round(entry.mForegroundUsageTimeInMs * ratio)); + assertThat(resultEntry.mForegroundServiceUsageTimeInMs).isEqualTo(0); assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0); assertThat(resultEntry.mConsumePower).isEqualTo(entry.mConsumePower * ratio); assertThat(resultEntry.mForegroundUsageConsumePower) @@ -1627,6 +1660,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1643,6 +1677,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1662,6 +1697,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1678,6 +1714,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1697,6 +1734,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1713,6 +1751,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1748,6 +1787,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 5, /* cachedUsageConsumePower= */ 5, /* foregroundUsageTimeInMs= */ 10, + /* foregroundServiceUsageTimeInMs= */ 15, /* backgroundUsageTimeInMs= */ 20, /* screenOnTimeInMs= */ 0); } @@ -1777,6 +1817,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1793,6 +1834,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1812,6 +1854,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1828,6 +1871,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 0L, + /* foregroundServiceUsageTimeInMs= */ 0L, /* backgroundUsageTimeInMs= */ 0L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1847,6 +1891,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1863,6 +1908,7 @@ public final class DataProcessorTest { currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /* foregroundUsageTimeInMs= */ 10L, + /* foregroundServiceUsageTimeInMs= */ 15L, /* backgroundUsageTimeInMs= */ 20L, /* isHidden= */ false); entryMap.put(entry.getKey(), entry); @@ -1892,6 +1938,7 @@ public final class DataProcessorTest { assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(20); resultEntry = resultDiffData.getAppDiffEntryList().get(1); assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0); + assertThat(resultEntry.mForegroundServiceUsageTimeInMs).isEqualTo(0); } @Test @@ -1921,6 +1968,7 @@ public final class DataProcessorTest { doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInBackground(); doReturn(0.0).when(mMockBatteryEntry1).getConsumedPowerInCached(); doReturn(30L).when(mMockBatteryEntry1).getTimeInForegroundMs(); + doReturn(35L).when(mMockBatteryEntry1).getTimeInForegroundServiceMs(); doReturn(40L).when(mMockBatteryEntry1).getTimeInBackgroundMs(); doReturn(1).when(mMockBatteryEntry1).getUid(); doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry1).getConsumerType(); @@ -1930,6 +1978,7 @@ public final class DataProcessorTest { doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInBackground(); doReturn(0.0).when(mMockBatteryEntry2).getConsumedPowerInCached(); doReturn(20L).when(mMockBatteryEntry2).getTimeInForegroundMs(); + doReturn(20L).when(mMockBatteryEntry2).getTimeInForegroundServiceMs(); doReturn(20L).when(mMockBatteryEntry2).getTimeInBackgroundMs(); doReturn(2).when(mMockBatteryEntry2).getUid(); doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry2).getConsumerType(); @@ -1939,6 +1988,7 @@ public final class DataProcessorTest { doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInBackground(); doReturn(0.0).when(mMockBatteryEntry3).getConsumedPowerInCached(); doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundMs(); + doReturn(0L).when(mMockBatteryEntry3).getTimeInForegroundServiceMs(); doReturn(0L).when(mMockBatteryEntry3).getTimeInBackgroundMs(); doReturn(3).when(mMockBatteryEntry3).getUid(); doReturn(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).when(mMockBatteryEntry3).getConsumerType(); @@ -1948,6 +1998,7 @@ public final class DataProcessorTest { doReturn(0.3).when(mMockBatteryEntry4).getConsumedPowerInBackground(); doReturn(0.1).when(mMockBatteryEntry4).getConsumedPowerInCached(); doReturn(10L).when(mMockBatteryEntry4).getTimeInForegroundMs(); + doReturn(10L).when(mMockBatteryEntry4).getTimeInForegroundServiceMs(); doReturn(10L).when(mMockBatteryEntry4).getTimeInBackgroundMs(); doReturn(4).when(mMockBatteryEntry4).getUid(); doReturn(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY) @@ -1978,6 +2029,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 0, /* cachedUsageConsumePower= */ 0, /* foregroundUsageTimeInMs= */ 20, + /* foregroundServiceUsageTimeInMs= */ 20, /* backgroundUsageTimeInMs= */ 20, /* screenOnTimeInMs= */ 0); assertBatteryDiffEntry( @@ -1991,6 +2043,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 0, /* cachedUsageConsumePower= */ 0, /* foregroundUsageTimeInMs= */ 30, + /* foregroundServiceUsageTimeInMs= */ 35, /* backgroundUsageTimeInMs= */ 40, /* screenOnTimeInMs= */ 0); assertBatteryDiffEntry( @@ -2004,6 +2057,7 @@ public final class DataProcessorTest { /* backgroundUsageConsumePower= */ 0.3, /* cachedUsageConsumePower= */ 0.1, /* foregroundUsageTimeInMs= */ 10, + /* foregroundServiceUsageTimeInMs= */ 10, /* backgroundUsageTimeInMs= */ 10, /* screenOnTimeInMs= */ 0); } @@ -2390,6 +2444,7 @@ public final class DataProcessorTest { final long userId, final int consumerType, final long foregroundUsageTimeInMs, + final long foregroundServiceUsageTimeInMs, final long backgroundUsageTimeInMs, final boolean isHidden) { // Only insert required fields. @@ -2402,6 +2457,7 @@ public final class DataProcessorTest { .setBackgroundUsageConsumePower(backgroundUsageConsumePower) .setCachedUsageConsumePower(cachedUsageConsumePower) .setForegroundUsageTimeInMs(foregroundUsageTimeInMs) + .setForegroundServiceUsageTimeInMs(foregroundServiceUsageTimeInMs) .setBackgroundUsageTimeInMs(backgroundUsageTimeInMs) .setIsHidden(isHidden) .build(); @@ -2531,6 +2587,7 @@ public final class DataProcessorTest { final double backgroundUsageConsumePower, final double cachedUsageConsumePower, final long foregroundUsageTimeInMs, + final long foregroundServiceUsageTimeInMs, final long backgroundUsageTimeInMs, final long screenOnTimeInMs) { assertThat(entry.mUserId).isEqualTo(userId); @@ -2543,6 +2600,8 @@ public final class DataProcessorTest { assertThat(entry.mBackgroundUsageConsumePower).isEqualTo(backgroundUsageConsumePower); assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower); assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs); + assertThat(entry.mForegroundServiceUsageTimeInMs) + .isEqualTo(foregroundServiceUsageTimeInMs); assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs); assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs); } From 0ac1ba59202332ce21509d2b73f888a9e6b13901 Mon Sep 17 00:00:00 2001 From: chenjean Date: Mon, 7 Oct 2024 15:14:57 +0800 Subject: [PATCH 13/14] Makes Use Color correction and Color correction shortcut searchable. Fix: 354079305 Flag: com.android.settings.accessibility.fix_a11y_settings_search Test: atest ToggleDaltonizerPreferenceFragmentTest Test: adb shell pm clear com.google.android.settings.intelligence; search Settings for 'use color correction' & 'color correction shortcut', observe 'use color correction' & 'color correction shortcut' present; Change-Id: I0fd1885c1e82ac14290dfe40636e652a624e003a --- .../ToggleDaltonizerPreferenceFragment.java | 36 ++++++++++++++++- ...oggleDaltonizerPreferenceFragmentTest.java | 39 ++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java index d2fc6cc01c1..747efaa60db 100644 --- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java @@ -25,6 +25,7 @@ import static com.android.settings.accessibility.DaltonizerPreferenceUtil.isSecu import android.app.settings.SettingsEnums; import android.content.ComponentName; +import android.content.Context; import android.os.Bundle; import android.provider.Settings; import android.view.LayoutInflater; @@ -38,6 +39,7 @@ import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltip import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SettingsMainSwitchPreference; import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.search.SearchIndexableRaw; import java.util.ArrayList; import java.util.List; @@ -53,6 +55,11 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF private static final String KEY_PROTANOMALY = "daltonizer_mode_protanomaly"; private static final String KEY_TRITANOMEALY = "daltonizer_mode_tritanomaly"; private static final String KEY_GRAYSCALE = "daltonizer_mode_grayscale"; + + @VisibleForTesting + static final String KEY_SHORTCUT_PREFERENCE = "daltonizer_shortcut_key"; + @VisibleForTesting + static final String KEY_SWITCH_PREFERENCE = "daltonizer_switch_preference_key"; @VisibleForTesting static final String KEY_SATURATION = "daltonizer_saturation"; @@ -170,6 +177,11 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF switchPreference.setTitle(R.string.accessibility_daltonizer_primary_switch_title); } + @Override + protected String getUseServicePreferenceKey() { + return KEY_SWITCH_PREFERENCE; + } + @Override protected CharSequence getShortcutTitle() { return getText(R.string.accessibility_daltonizer_shortcut_title); @@ -203,5 +215,27 @@ public class ToggleDaltonizerPreferenceFragment extends ToggleFeaturePreferenceF } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings); + new BaseSearchIndexProvider(R.xml.accessibility_daltonizer_settings) { + @Override + public List getRawDataToIndex(Context context, + boolean enabled) { + final List rawData = + super.getRawDataToIndex(context, enabled); + + if (Flags.fixA11ySettingsSearch()) { + SearchIndexableRaw shortcutRaw = new SearchIndexableRaw(context); + shortcutRaw.key = KEY_SHORTCUT_PREFERENCE; + shortcutRaw.title = context.getString( + R.string.accessibility_daltonizer_shortcut_title); + rawData.add(shortcutRaw); + + SearchIndexableRaw mainSwitchRaw = new SearchIndexableRaw(context); + mainSwitchRaw.key = KEY_SWITCH_PREFERENCE; + mainSwitchRaw.title = context.getString( + R.string.accessibility_daltonizer_primary_switch_title); + rawData.add(mainSwitchRaw); + } + return rawData; + } + }; } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java index fd82994123d..a33fefbb404 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragmentTest.java @@ -18,6 +18,8 @@ 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.ToggleDaltonizerPreferenceFragment.KEY_SHORTCUT_PREFERENCE; +import static com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.KEY_SWITCH_PREFERENCE; import static com.google.common.truth.Truth.assertThat; @@ -26,9 +28,9 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; -import android.view.accessibility.Flags; import android.widget.PopupWindow; import androidx.fragment.app.Fragment; @@ -38,6 +40,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.testutils.XmlTestUtils; import com.android.settings.widget.SettingsMainSwitchPreference; +import com.android.settingslib.search.SearchIndexableRaw; import org.junit.Before; import org.junit.Rule; @@ -48,6 +51,7 @@ import org.robolectric.android.controller.ActivityController; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowApplication; +import java.util.ArrayList; import java.util.List; /** Tests for {@link ToggleDaltonizerPreferenceFragment} */ @@ -103,7 +107,7 @@ public class ToggleDaltonizerPreferenceFragmentTest { } @Test - @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) public void onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView() { Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF); @@ -168,6 +172,37 @@ public class ToggleDaltonizerPreferenceFragmentTest { assertThat(keys).containsAtLeastElementsIn(niks); } + @Test + @DisableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getRawDataToIndex_flagOff_returnEmptyData() { + List rawData = ToggleDaltonizerPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, /* enabled= */ true); + + assertThat(rawData).isEmpty(); + } + + @Test + @EnableFlags(Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH) + public void getRawDataToIndex_flagOn_returnAllIndexablePreferences() { + String[] expectedKeys = {KEY_SHORTCUT_PREFERENCE, KEY_SWITCH_PREFERENCE}; + String[] expectedTitles = { + mContext.getString(R.string.accessibility_daltonizer_shortcut_title), + mContext.getString(R.string.accessibility_daltonizer_primary_switch_title)}; + List keysResultList = new ArrayList<>(); + List titlesResultList = new ArrayList<>(); + List rawData = ToggleDaltonizerPreferenceFragment + .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, /* enabled= */ true); + + for (SearchIndexableRaw rawDataItem : rawData) { + keysResultList.add(rawDataItem.key); + titlesResultList.add(rawDataItem.title); + } + + assertThat(rawData).hasSize(2); + assertThat(keysResultList).containsExactly(expectedKeys); + assertThat(titlesResultList).containsExactly(expectedTitles); + } + private static PopupWindow getLatestPopupWindow() { final ShadowApplication shadowApplication = Shadow.extract(ApplicationProvider.getApplicationContext()); From cffb21b17fe3e44c97f761f2d75433149b0df22d Mon Sep 17 00:00:00 2001 From: shaoweishen Date: Sun, 6 Oct 2024 09:28:59 +0000 Subject: [PATCH 14/14] [Physical Keyboard] Add Repeat key toggle Add repeat key toggle under Physical keybaord setting. Bug: 345399212 Test: atest SettingsRoboTests Flag: com.android.input.flags.keyboard_repeat_keys Change-Id: Ib986301d108b1ad30d96d7309189e9507d38c25a --- res/values/strings.xml | 4 + res/xml/physical_keyboard_settings.xml | 9 ++ .../KeyboardRepeatKeysController.java | 76 +++++++++++++++++ .../inputmethod/PhysicalKeyboardFragment.java | 16 +++- .../KeyboardRepeatKeysControllerTest.java | 83 +++++++++++++++++++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/com/android/settings/inputmethod/KeyboardRepeatKeysController.java create mode 100644 tests/robotests/src/com/android/settings/inputmethod/KeyboardRepeatKeysControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 5326fa5d7a9..97a7e232304 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4696,6 +4696,10 @@ Physical keyboard accessibility Sticky keys, Bounce keys, Mouse keys + + Repeat Keys + + Hold down a key to repeat its character until the key is released %s layout diff --git a/res/xml/physical_keyboard_settings.xml b/res/xml/physical_keyboard_settings.xml index 1527ff52866..5d2c5fcd99b 100644 --- a/res/xml/physical_keyboard_settings.xml +++ b/res/xml/physical_keyboard_settings.xml @@ -15,6 +15,7 @@ --> @@ -31,6 +32,14 @@ android:title="@string/modifier_keys_settings" android:summary="@string/modifier_keys_settings_summary" android:fragment="com.android.settings.inputmethod.ModifierKeysSettings" /> + + +