From 77ecdc7c0427d706e9c43d062c0340f022493bbd Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Tue, 12 Mar 2024 16:22:33 +0800 Subject: [PATCH 01/11] Enforce BaseUserRestriction for DISALLOW_CONFIG_SCREEN_TIMEOUT Fix: 329202191 Test: pm set-user-restriction --user 0 no_config_screen_timeout 1 Change-Id: Icd35365f446296fb53b1068d278d4cf5fd25939e --- .../display/ScreenTimeoutPreferenceController.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/display/ScreenTimeoutPreferenceController.java b/src/com/android/settings/display/ScreenTimeoutPreferenceController.java index 125411678fe..5809c79bbcf 100644 --- a/src/com/android/settings/display/ScreenTimeoutPreferenceController.java +++ b/src/com/android/settings/display/ScreenTimeoutPreferenceController.java @@ -23,6 +23,7 @@ import static com.android.settings.display.ScreenTimeoutSettings.FALLBACK_SCREEN import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -67,9 +68,13 @@ public class ScreenTimeoutPreferenceController extends BasePreferenceController .getString(DISABLED_BY_IT_ADMIN_TITLE, () -> mContext.getString(R.string.disabled_by_policy_title))); ((RestrictedPreference) preference).setDisabledByAdmin(admin); - } else { - preference.setSummary(getTimeoutSummary(maxTimeout)); + return; } + if (UserManager.get(mContext).hasBaseUserRestriction( + UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, Process.myUserHandle())) { + preference.setEnabled(false); + } + preference.setSummary(getTimeoutSummary(maxTimeout)); } private CharSequence getTimeoutSummary(long maxTimeout) { From 41ceecda99a98f9945b33700c2bc0b1a7c9ad54f Mon Sep 17 00:00:00 2001 From: alukin Date: Tue, 12 Mar 2024 16:59:29 +0000 Subject: [PATCH 02/11] Add strings for System split Adding strings that are used for System category split in Settings > Storage Bug: 309801699 Test: atest StorageItemPreferenceControllerTest Test: atest StorageCacheHelperTest Change-Id: I60cee85fe773380b35699b46a2a93ea3188bb13b --- res/values/strings.xml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 46b7e868321..5c4b809bf8d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3174,9 +3174,18 @@ All the apps, photos, and data stored on this ^1 will be lost forever. - + System includes files used to run Android version %s + + This includes your operating system and the files that are needed to keep your phone running smoothly. To protect their integrity, these files can\u2019t be accessed. + + + This includes cache and other temporary files that are needed by your operating system. You may notice changes to the amount of storage used over time. + + + System + Guest mode users cannot format SD cards @@ -10768,9 +10777,15 @@ Documents & other - + System + + Android %s + + + Temporary system files + Trash From 89612e53d74c59342de52837a64ba385722fab07 Mon Sep 17 00:00:00 2001 From: Jakub Rotkiewicz Date: Wed, 22 Nov 2023 10:11:25 +0000 Subject: [PATCH 03/11] Refactor Bluetooth Codec settings to dynamic ListPreference Fetch supported codecs from native and present to user using ListPreference. Bug: 305779598 Bug: 311451118 Bug: 323319530 Tag: #feature Test: atest SettingsRoboTests:com.android.settings.development.bluetooth.AbstractBluetoothListPreferenceController Test: atest SettingsRoboTests:com.android.settings.development.bluetooth.BluetoothCodecListPreferenceControllerTest Change-Id: Iedbfd01c0d1b59df8a073f4e9aedca3913e6d45f --- .../settings_core_flag_declarations.aconfig | 7 + res/values/strings.xml | 3 + res/xml/development_settings.xml | 5 + .../development/BluetoothA2dpConfigStore.java | 35 ++- .../DevelopmentSettingsDashboardFragment.java | 8 + ...ractBluetoothListPreferenceController.java | 268 ++++++++++++++++++ ...AbstractBluetoothPreferenceController.java | 9 +- ...etoothCodecDialogPreferenceController.java | 6 + ...luetoothCodecListPreferenceController.java | 265 +++++++++++++++++ ...BluetoothListPreferenceControllerTest.java | 240 ++++++++++++++++ ...oothCodecListPreferenceControllerTest.java | 267 +++++++++++++++++ 11 files changed, 1105 insertions(+), 8 deletions(-) create mode 100644 src/com/android/settings/development/bluetooth/AbstractBluetoothListPreferenceController.java create mode 100644 src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/development/bluetooth/AbstractBluetoothListPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceControllerTest.java diff --git a/aconfig/development/settings_core_flag_declarations.aconfig b/aconfig/development/settings_core_flag_declarations.aconfig index b73b0268009..fec67f6b782 100644 --- a/aconfig/development/settings_core_flag_declarations.aconfig +++ b/aconfig/development/settings_core_flag_declarations.aconfig @@ -1,6 +1,13 @@ package: "com.android.settings.development" container: "system" +flag { + name: "a2dp_offload_codec_extensibility_settings" + namespace: "bluetooth" + description: "Feature flag for Bluetooth Audio Codec extensibility in Settings" + bug: "323319530" +} + flag { name: "deprecate_list_activity" namespace: "android_settings" diff --git a/res/values/strings.xml b/res/values/strings.xml index d5fd6214b1e..d3c5e8d060c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -178,6 +178,9 @@ By default, audio output is determined by individual apps + + Use System Selection (Default) + Unnamed Bluetooth device diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index 23eb1f25241..682a9c23dae 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -430,6 +430,11 @@ android:positiveButtonText="" android:negativeButtonText="@string/dlg_ok"/> + + entries, + List entryValues, + String selectedEntry, + String selectedValue) { + if (entries.size() != entryValues.size()) { + Log.e( + TAG, + ("setupListPreference: size of entries: " + entries.size()) + + (", size of entryValues" + entryValues.size())); + setupDefaultListPreference(); + return; + } + if (entries.isEmpty() || entryValues.isEmpty()) { + Log.e(TAG, "setupListPreference: entries or entryValues empty"); + setupDefaultListPreference(); + return; + } + entries.add(0, mDefaultEntry); + entryValues.add(0, mDefaultValue); + + if (mListPreference == null) { + Log.e(TAG, "setupListPreference: List preference is null"); + return; + } + mListPreference.setEntries(entries.toArray(new String[entries.size()])); + mListPreference.setEntryValues(entryValues.toArray(new String[entryValues.size()])); + mListPreference.setValue(selectedValue); + mListPreference.setSummary(selectedEntry); + } + + /** + * Check HD Audio enabled. + * + * @return true if HD Audio is enabled. + */ + protected boolean isHDAudioEnabled() { + final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp; + if (bluetoothA2dp == null) { + Log.e(TAG, "isHDAudioEnabled: Unable to get codec status. BluetoothA2dp is null."); + return false; + } + BluetoothDevice activeDevice = getA2dpActiveDevice(); + if (activeDevice == null) { + Log.e(TAG, "isHDAudioEnabled: Unable to get codec status. No active device."); + return false; + } + return (bluetoothA2dp.isOptionalCodecsEnabled(activeDevice) + == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED); + } + + private void setupDefaultListPreference() { + if (DEBUG) { + Log.d( + TAG, + "setupDefaultListPreference: mDefaultEntry=" + + mDefaultEntry + + ", mDefaultValue=" + + mDefaultValue); + } + if (mListPreference == null) { + Log.e(TAG, "setupListPreference: List preference is null"); + return; + } + mListPreference.setEntries(new String[] {mDefaultEntry}); + mListPreference.setEntryValues(new String[] {mDefaultValue}); + mListPreference.setValue(mDefaultValue); + mListPreference.setSummary(mDefaultEntry); + } + + private void initConfigStore() { + final BluetoothCodecConfig config = getCurrentCodecConfig(); + if (config == null) { + Log.e(TAG, "initConfigStore: Current codec config is null."); + return; + } + if (mBluetoothA2dpConfigStore == null) { + Log.e(TAG, "initConfigStore: Bluetooth A2dp Config Store is null."); + return; + } + mBluetoothA2dpConfigStore.setCodecType(config.getExtendedCodecType()); + mBluetoothA2dpConfigStore.setSampleRate(config.getSampleRate()); + mBluetoothA2dpConfigStore.setBitsPerSample(config.getBitsPerSample()); + mBluetoothA2dpConfigStore.setChannelMode(config.getChannelMode()); + mBluetoothA2dpConfigStore.setCodecPriority(CODEC_PRIORITY_HIGHEST); + mBluetoothA2dpConfigStore.setCodecSpecific1Value(config.getCodecSpecific1()); + } +} diff --git a/src/com/android/settings/development/bluetooth/AbstractBluetoothPreferenceController.java b/src/com/android/settings/development/bluetooth/AbstractBluetoothPreferenceController.java index d3fab674a92..14bc27573bb 100644 --- a/src/com/android/settings/development/bluetooth/AbstractBluetoothPreferenceController.java +++ b/src/com/android/settings/development/bluetooth/AbstractBluetoothPreferenceController.java @@ -23,6 +23,7 @@ import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.settings.core.PreferenceControllerMixin; @@ -42,13 +43,15 @@ public abstract class AbstractBluetoothPreferenceController extends DeveloperOptionsPreferenceController implements BluetoothServiceConnectionListener, LifecycleObserver, OnDestroy, PreferenceControllerMixin { - protected volatile BluetoothA2dp mBluetoothA2dp; + @Nullable protected volatile BluetoothA2dp mBluetoothA2dp; @VisibleForTesting BluetoothAdapter mBluetoothAdapter; - public AbstractBluetoothPreferenceController(Context context, Lifecycle lifecycle, - BluetoothA2dpConfigStore store) { + public AbstractBluetoothPreferenceController( + @Nullable Context context, + @Nullable Lifecycle lifecycle, + @Nullable BluetoothA2dpConfigStore store) { super(context); if (lifecycle != null) { lifecycle.addObserver(this); diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java index 2f0d27c2fef..b7b557464fb 100644 --- a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java +++ b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java @@ -26,6 +26,7 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; import com.android.settings.development.BluetoothA2dpConfigStore; +import com.android.settings.development.Flags; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; @@ -49,6 +50,11 @@ public class BluetoothCodecDialogPreferenceController extends mCallback = callback; } + @Override + public boolean isAvailable() { + return !Flags.a2dpOffloadCodecExtensibilitySettings(); + } + @Override public String getPreferenceKey() { return KEY; diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceController.java new file mode 100644 index 00000000000..79b629efcb6 --- /dev/null +++ b/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceController.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.development.bluetooth; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothCodecType; +import android.bluetooth.BluetoothDevice; +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.development.BluetoothA2dpConfigStore; +import com.android.settings.development.Flags; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** List preference controller to set the Bluetooth A2DP codec */ +public class BluetoothCodecListPreferenceController + extends AbstractBluetoothListPreferenceController { + + private static final String KEY = "bluetooth_audio_codec_settings_list"; + private static final String TAG = "BtExtCodecCtr"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + @Nullable private final Callback mCallback; + + public BluetoothCodecListPreferenceController( + @NonNull Context context, + @Nullable Lifecycle lifecycle, + @Nullable BluetoothA2dpConfigStore store, + @Nullable Callback callback) { + super(context, lifecycle, store); + mCallback = callback; + } + + @Override + public boolean isAvailable() { + boolean available = Flags.a2dpOffloadCodecExtensibilitySettings(); + if (DEBUG) { + Log.d(TAG, "isAvailable: " + available); + } + return available; + } + + @Override + public @NonNull String getPreferenceKey() { + return KEY; + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + mListPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public boolean onPreferenceChange(@Nullable Preference preference, @NonNull Object newValue) { + if (DEBUG) { + Log.d(TAG, "onPreferenceChange: newValue=" + (String) newValue); + } + final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp; + if (bluetoothA2dp == null) { + Log.e(TAG, "onPreferenceChange: bluetoothA2dp is null"); + return false; + } + + writeConfigurationValues((String) newValue); + + if (mBluetoothA2dpConfigStore == null) { + Log.e(TAG, "onPreferenceChange: Bluetooth A2dp Config Store is null"); + return false; + } + BluetoothCodecConfig codecConfig; + if (Flags.a2dpOffloadCodecExtensibilitySettings()) { + codecConfig = mBluetoothA2dpConfigStore.createCodecConfigFromCodecType(); + } else { + codecConfig = mBluetoothA2dpConfigStore.createCodecConfig(); + } + + final BluetoothDevice activeDevice = getA2dpActiveDevice(); + if (activeDevice == null) { + Log.e(TAG, "onPreferenceChange: active device is null"); + return false; + } + + if (DEBUG) { + Log.d(TAG, "onPreferenceChange: setCodecConfigPreference: " + codecConfig.toString()); + } + bluetoothA2dp.setCodecConfigPreference(activeDevice, codecConfig); + if (mCallback != null) { + mCallback.onBluetoothCodecChanged(); + } + + return true; + } + + @Override + public void updateState(@Nullable Preference preference) { + super.updateState(preference); + final List codecIds = new ArrayList<>(); + final List labels = new ArrayList<>(); + String selectedCodecId = mDefaultValue; + String selectedLabel = mDefaultEntry; + + if (isHDAudioEnabled()) { + final BluetoothCodecStatus codecStatus = getBluetoothCodecStatus(); + if (codecStatus == null) { + Log.e(TAG, "updateState: Bluetooth Codec Status is null"); + return; + } + + final BluetoothCodecConfig currentCodecConfig = codecStatus.getCodecConfig(); + if (currentCodecConfig == null) { + Log.e(TAG, "updateState: currentCodecConfig is null"); + return; + } + + final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp; + if (bluetoothA2dp == null) { + Log.e(TAG, "updateState: bluetoothA2dp is null"); + return; + } + + final Collection codecTypes = + bluetoothA2dp.getSupportedCodecTypes(); + for (BluetoothCodecType codecType : codecTypes) { + labels.add(codecType.getCodecName()); + codecIds.add(String.valueOf(codecType.getCodecId())); + if (currentCodecConfig != null + && currentCodecConfig.getExtendedCodecType().equals(codecType)) { + selectedCodecId = codecIds.get(codecIds.size() - 1); + selectedLabel = labels.get(labels.size() - 1); + if (DEBUG) { + Log.d( + TAG, + "updateState: Current config: " + + selectedLabel + + ", id: " + + selectedCodecId); + } + } + } + + setupListPreference(labels, codecIds, selectedLabel, selectedCodecId); + } + } + + @Override + public void onHDAudioEnabled(boolean enabled) { + if (DEBUG) { + Log.d(TAG, "onHDAudioEnabled: enabled=" + enabled); + } + if (mListPreference == null) { + Log.e(TAG, "onHDAudioEnabled: List preference is null"); + return; + } + mListPreference.setEnabled(enabled); + } + + @Override + protected void writeConfigurationValues(String entryValue) { + long codecIdValue = getCodecIdFromEntryValue(entryValue); + BluetoothCodecType selectedCodecType = null; + BluetoothCodecConfig selectedCodecConfig = null; + + final BluetoothA2dp bluetoothA2dp = mBluetoothA2dp; + if (bluetoothA2dp == null) { + Log.e(TAG, "writeConfigurationValues: bluetoothA2dp is null"); + return; + } + + final Collection codecTypes = bluetoothA2dp.getSupportedCodecTypes(); + for (BluetoothCodecType codecType : codecTypes) { + if (codecType.getCodecId() == codecIdValue) { + selectedCodecType = codecType; + } + } + + if (selectedCodecType == null) { + Log.e( + TAG, + "writeConfigurationValues: No selectable codec ID: " + + codecIdValue + + " found. Unable to change codec"); + return; + } + + if (DEBUG) { + Log.d(TAG, "writeConfigurationValues: Selected codec: " + selectedCodecType.toString()); + } + final BluetoothCodecStatus codecStatus = getBluetoothCodecStatus(); + if (codecStatus == null) { + Log.e(TAG, "writeConfigurationValues: Bluetooth Codec Status is null"); + return; + } + + final List codecConfigs = + codecStatus.getCodecsSelectableCapabilities(); + for (BluetoothCodecConfig config : codecConfigs) { + BluetoothCodecType codecType = config.getExtendedCodecType(); + if (codecType == null) { + Log.e(TAG, "codec type for config:" + config + " is null"); + } + if (codecType != null && codecType.equals(selectedCodecType)) { + selectedCodecConfig = config; + } + } + + if (selectedCodecConfig == null) { + Log.e( + TAG, + "writeConfigurationValues: No selectable codec config for codec: " + + selectedCodecType.toString()); + return; + } + + if (mBluetoothA2dpConfigStore == null) { + Log.e(TAG, "writeConfigurationValues: Bluetooth A2dp Config Store is null"); + return; + } + + mBluetoothA2dpConfigStore.setCodecType(selectedCodecType); + mBluetoothA2dpConfigStore.setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST); + mBluetoothA2dpConfigStore.setSampleRate( + AbstractBluetoothDialogPreferenceController.getHighestSampleRate( + selectedCodecConfig)); + mBluetoothA2dpConfigStore.setBitsPerSample( + AbstractBluetoothDialogPreferenceController.getHighestBitsPerSample( + selectedCodecConfig)); + mBluetoothA2dpConfigStore.setChannelMode( + AbstractBluetoothDialogPreferenceController.getHighestChannelMode( + selectedCodecConfig)); + } + + private long getCodecIdFromEntryValue(String entryValue) { + long codecType = BluetoothCodecType.CODEC_ID_SBC; + if (entryValue.isEmpty() || Long.valueOf(entryValue) == DEFAULT_VALUE_INT) { + return codecType; + } + return Long.valueOf(entryValue); + } +} diff --git a/tests/robotests/src/com/android/settings/development/bluetooth/AbstractBluetoothListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/bluetooth/AbstractBluetoothListPreferenceControllerTest.java new file mode 100644 index 00000000000..8abc633f84d --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/bluetooth/AbstractBluetoothListPreferenceControllerTest.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.development.bluetooth; + +import static android.bluetooth.BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.development.BluetoothA2dpConfigStore; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class AbstractBluetoothListPreferenceControllerTest { + + private static final String DEVICE_ADDRESS = "00:11:22:33:44:55"; + + private static String DEFAULT_ENTRY; + private static final String DEFAULT_ENTRY_VALUE = "1000"; + + @Mock private BluetoothA2dp mBluetoothA2dp; + @Mock private BluetoothAdapter mBluetoothAdapter; + @Mock private PreferenceScreen mScreen; + + private AbstractBluetoothListPreferenceController mController; + private ListPreference mPreference; + private BluetoothA2dpConfigStore mBluetoothA2dpConfigStore; + private BluetoothCodecStatus mCodecStatus; + private BluetoothCodecConfig mCodecConfigAAC; + private BluetoothCodecConfig mCodecConfigSBC; + private BluetoothCodecConfig[] mCodecConfigs = new BluetoothCodecConfig[2]; + private BluetoothDevice mActiveDevice; + private Context mContext; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + mBluetoothA2dpConfigStore = spy(new BluetoothA2dpConfigStore()); + mActiveDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(DEVICE_ADDRESS); + mController = + spy( + new AbstractBluetoothListPreferenceControllerImpl( + mContext, mLifecycle, mBluetoothA2dpConfigStore)); + mController.mBluetoothAdapter = mBluetoothAdapter; + mPreference = spy(new ListPreference(mContext)); + + mCodecConfigAAC = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC) + .build(); + mCodecConfigSBC = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) + .build(); + mCodecConfigs[0] = mCodecConfigAAC; + mCodecConfigs[1] = mCodecConfigSBC; + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP))) + .thenReturn(Arrays.asList(mActiveDevice)); + + DEFAULT_ENTRY = mContext.getString(R.string.bluetooth_audio_codec_default_selection); + } + + private void verifySetupDefaultListPreference() { + List entries = new ArrayList<>(1); + entries.add(DEFAULT_ENTRY); + List entryValues = new ArrayList<>(1); + entryValues.add(DEFAULT_ENTRY_VALUE); + + verify(mPreference).setEntries(entries.toArray(new String[entries.size()])); + verify(mPreference).setEntryValues(entryValues.toArray(new String[entryValues.size()])); + verify(mPreference).setValue(DEFAULT_ENTRY_VALUE); + verify(mPreference).setSummary(DEFAULT_ENTRY); + } + + @Test + public void onPreferenceChange_shouldSetupDefaultListPreference() { + mController.onPreferenceChange(mPreference, "" /* new value */); + verifySetupDefaultListPreference(); + } + + @Test + public void setupListPreference_wrongSize_shouldSetupDefaultListPreference() { + List entries = new ArrayList<>(1); + entries.add(DEFAULT_ENTRY); + List entryValues = new ArrayList<>(2); + entryValues.add(DEFAULT_ENTRY_VALUE); + entryValues.add(DEFAULT_ENTRY_VALUE); + + mController.setupListPreference(entries, entryValues, "", ""); + verifySetupDefaultListPreference(); + } + + @Test + public void setupListPreference_listEmpty_shouldSetupDefaultListPreference() { + List entries = new ArrayList<>(1); + entries.add(DEFAULT_ENTRY); + List entryValues = new ArrayList<>(); + + mController.setupListPreference(entries, entryValues, "", ""); + verifySetupDefaultListPreference(); + } + + @Test + public void getBluetoothCodecStatus_errorChecking() { + mController.onBluetoothServiceConnected(null); + assertThat(mController.getBluetoothCodecStatus()).isNull(); + + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(null); + assertThat(mController.getBluetoothCodecStatus()).isNull(); + } + + @Test + public void getCurrentCodecConfig_errorChecking() { + mController.onBluetoothServiceConnected(null); + assertThat(mController.getCurrentCodecConfig()).isNull(); + + mController.onBluetoothServiceConnected(mBluetoothA2dp); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(null); + assertThat(mController.getCurrentCodecConfig()).isNull(); + } + + @Test + public void getCurrentCodecConfig_verifyConfig() { + mCodecStatus = new BluetoothCodecStatus.Builder().setCodecConfig(mCodecConfigAAC).build(); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus); + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + assertThat(mController.getCurrentCodecConfig()).isEqualTo(mCodecConfigAAC); + } + + @Test + public void isHDAudioEnabled_errorChecking() { + mController.onBluetoothServiceConnected(null); + assertFalse(mController.isHDAudioEnabled()); + + mController.onBluetoothServiceConnected(mBluetoothA2dp); + when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)) + .thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED); + assertFalse(mController.isHDAudioEnabled()); + } + + @Test + public void isHDAudioEnabled_verifyEnabled() { + mController.onBluetoothServiceConnected(mBluetoothA2dp); + when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)) + .thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED); + assertTrue(mController.isHDAudioEnabled()); + } + + @Test + public void onBluetoothServiceConnected_verifyBluetoothA2dpConfigStore() { + mCodecStatus = + new BluetoothCodecStatus.Builder() + .setCodecConfig(mCodecConfigAAC) + .setCodecsSelectableCapabilities(Arrays.asList(mCodecConfigs)) + .build(); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus); + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + verify(mBluetoothA2dpConfigStore).setCodecType(mCodecConfigAAC.getExtendedCodecType()); + verify(mBluetoothA2dpConfigStore).setSampleRate(mCodecConfigAAC.getSampleRate()); + verify(mBluetoothA2dpConfigStore).setBitsPerSample(mCodecConfigAAC.getBitsPerSample()); + verify(mBluetoothA2dpConfigStore).setChannelMode(mCodecConfigAAC.getChannelMode()); + verify(mBluetoothA2dpConfigStore).setCodecPriority(CODEC_PRIORITY_HIGHEST); + verify(mBluetoothA2dpConfigStore) + .setCodecSpecific1Value(mCodecConfigAAC.getCodecSpecific1()); + } + + private static class AbstractBluetoothListPreferenceControllerImpl + extends AbstractBluetoothListPreferenceController { + + private AbstractBluetoothListPreferenceControllerImpl( + Context context, Lifecycle lifecycle, BluetoothA2dpConfigStore store) { + super(context, lifecycle, store); + } + + @Override + public String getPreferenceKey() { + return "KEY"; + } + + @Override + protected void writeConfigurationValues(String entryValue) {} + } +} diff --git a/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceControllerTest.java new file mode 100644 index 00000000000..b86d9df1c85 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecListPreferenceControllerTest.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.development.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothA2dp; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothCodecConfig; +import android.bluetooth.BluetoothCodecStatus; +import android.bluetooth.BluetoothCodecType; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.development.BluetoothA2dpConfigStore; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothCodecListPreferenceControllerTest { + + private static final String DEVICE_ADDRESS = "00:11:22:33:44:55"; + + @Mock private BluetoothA2dp mBluetoothA2dp; + @Mock private BluetoothAdapter mBluetoothAdapter; + @Mock private PreferenceScreen mScreen; + @Mock private AbstractBluetoothPreferenceController.Callback mCallback; + + private BluetoothCodecListPreferenceController mController; + private ListPreference mPreference; + private BluetoothA2dpConfigStore mBluetoothA2dpConfigStore; + private BluetoothCodecStatus mCodecStatus; + private BluetoothCodecType mCodecTypeAAC; + private BluetoothCodecType mCodecTypeSBC; + private BluetoothCodecType mCodecTypeAPTX; + private BluetoothCodecType mCodecTypeLDAC; + private BluetoothCodecType mCodecTypeOPUS; + private List mCodecTypes; + + private BluetoothCodecConfig mCodecConfigAAC; + private BluetoothCodecConfig mCodecConfigSBC; + private BluetoothCodecConfig mCodecConfigAPTX; + private BluetoothCodecConfig mCodecConfigAPTXHD; + private BluetoothCodecConfig mCodecConfigLDAC; + private BluetoothCodecConfig mCodecConfigOPUS; + private List mCodecConfigs; + private BluetoothDevice mActiveDevice; + private Context mContext; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + mBluetoothA2dpConfigStore = spy(new BluetoothA2dpConfigStore()); + mActiveDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(DEVICE_ADDRESS); + mController = + new BluetoothCodecListPreferenceController( + mContext, mLifecycle, mBluetoothA2dpConfigStore, mCallback); + mController.mBluetoothAdapter = mBluetoothAdapter; + mPreference = new ListPreference(mContext); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + + mCodecTypeAAC = + BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC); + mCodecTypeSBC = + BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC); + mCodecTypeAPTX = + BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX); + mCodecTypeLDAC = + BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC); + mCodecTypeOPUS = + BluetoothCodecType.createFromType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS); + + mCodecTypes = new ArrayList<>(); + mCodecTypes.addAll( + Arrays.asList( + mCodecTypeSBC, + mCodecTypeAAC, + mCodecTypeAPTX, + mCodecTypeLDAC, + mCodecTypeOPUS)); + + mCodecConfigSBC = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) + .setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST) + .setSampleRate( + BluetoothCodecConfig.SAMPLE_RATE_96000 + | BluetoothCodecConfig.SAMPLE_RATE_176400) + .setBitsPerSample(BluetoothCodecConfig.BITS_PER_SAMPLE_32) + .setChannelMode( + BluetoothCodecConfig.CHANNEL_MODE_MONO + | BluetoothCodecConfig.CHANNEL_MODE_STEREO) + .build(); + mCodecConfigAAC = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC) + .setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST) + .setSampleRate( + BluetoothCodecConfig.SAMPLE_RATE_48000 + | BluetoothCodecConfig.SAMPLE_RATE_88200) + .setBitsPerSample( + BluetoothCodecConfig.BITS_PER_SAMPLE_16 + | BluetoothCodecConfig.BITS_PER_SAMPLE_24) + .setChannelMode(BluetoothCodecConfig.CHANNEL_MODE_STEREO) + .build(); + mCodecConfigAPTX = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX) + .build(); + mCodecConfigAPTXHD = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD) + .build(); + mCodecConfigLDAC = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) + .build(); + mCodecConfigOPUS = + new BluetoothCodecConfig.Builder() + .setCodecType(BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS) + .build(); + + mCodecConfigs = new ArrayList<>(); + mCodecConfigs.addAll( + Arrays.asList( + mCodecConfigOPUS, + mCodecConfigAAC, + mCodecConfigSBC, + mCodecConfigAPTX, + mCodecConfigAPTXHD, + mCodecConfigLDAC)); + + when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP))) + .thenReturn(Arrays.asList(mActiveDevice)); + when(mBluetoothA2dp.getSupportedCodecTypes()).thenReturn(mCodecTypes); + } + + @Test + public void writeConfigurationValues_selectDefault() { + mCodecStatus = + new BluetoothCodecStatus.Builder() + .setCodecConfig(mCodecConfigSBC) + .setCodecsSelectableCapabilities(mCodecConfigs) + .build(); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus); + when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)) + .thenReturn(BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED); + + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + mController.writeConfigurationValues(String.valueOf(mController.DEFAULT_VALUE_INT)); + verify(mBluetoothA2dpConfigStore, times(2)).setCodecType(mCodecTypeSBC); + } + + @Test + public void writeConfigurationValues_checkCodec() { + mCodecStatus = + new BluetoothCodecStatus.Builder() + .setCodecConfig(mCodecConfigSBC) + .setCodecsSelectableCapabilities(mCodecConfigs) + .build(); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus); + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + mController.writeConfigurationValues(String.valueOf(mCodecTypeSBC.getCodecId())); + verify(mBluetoothA2dpConfigStore, atLeastOnce()).setCodecType(mCodecTypeSBC); + + mController.writeConfigurationValues(String.valueOf(mCodecTypeAAC.getCodecId())); + verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeAAC); + + mController.writeConfigurationValues(String.valueOf(mCodecTypeAPTX.getCodecId())); + verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeAPTX); + + mController.writeConfigurationValues(String.valueOf(mCodecTypeLDAC.getCodecId())); + verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeLDAC); + + mController.writeConfigurationValues(String.valueOf(mCodecTypeOPUS.getCodecId())); + verify(mBluetoothA2dpConfigStore).setCodecType(mCodecTypeOPUS); + } + + @Test + public void writeConfigurationValues_chooseHighestConfig() { + mCodecStatus = + new BluetoothCodecStatus.Builder() + .setCodecConfig(mCodecConfigSBC) + .setCodecsSelectableCapabilities((mCodecConfigs)) + .build(); + when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus); + mController.onBluetoothServiceConnected(mBluetoothA2dp); + mController.writeConfigurationValues(String.valueOf(mCodecTypeAAC.getCodecId())); + + verify(mBluetoothA2dpConfigStore, atLeastOnce()) + .setCodecPriority(BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST); + verify(mBluetoothA2dpConfigStore, atLeastOnce()) + .setSampleRate(BluetoothCodecConfig.SAMPLE_RATE_88200); + verify(mBluetoothA2dpConfigStore, atLeastOnce()) + .setBitsPerSample(BluetoothCodecConfig.BITS_PER_SAMPLE_24); + verify(mBluetoothA2dpConfigStore, atLeastOnce()) + .setChannelMode(BluetoothCodecConfig.CHANNEL_MODE_STEREO); + } + + @Test + public void onPreferenceChange_notifyPreference() { + assertFalse( + mController.onPreferenceChange( + mPreference, String.valueOf(mCodecTypeAAC.getCodecId()))); + + mController.onBluetoothServiceConnected(mBluetoothA2dp); + + assertTrue( + mController.onPreferenceChange( + mPreference, String.valueOf(mCodecTypeAAC.getCodecId()))); + + verify(mCallback).onBluetoothCodecChanged(); + } + + @Test + public void onHDAudioEnabled_setsPreferenceEnabled() { + mController.onHDAudioEnabled(/* enabled= */ true); + assertThat(mPreference.isEnabled()).isTrue(); + } +} From 0bcfc383070df946cbf2224b02e81ff16d348c11 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Fri, 15 Mar 2024 13:17:40 +0000 Subject: [PATCH 04/11] Revert "Prevent full-screen face enroll on tablet" This reverts commit 812d880ee7c5ef27537b11639030ee156f243d1a. Reason for revert: Block face enrollment b/316900124 Change-Id: I457ecb7ee8babdc3a15085a1600246b0eff4bd1d --- .../activityembedding/ActivityEmbeddingRulesController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java index b2ec589c965..4e39070febd 100644 --- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java +++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java @@ -39,6 +39,7 @@ import com.android.settings.Settings; import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.biometrics.face.FaceEnrollIntroduction; +import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal; import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling; import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction; import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal; @@ -259,6 +260,7 @@ public class ActivityEmbeddingRulesController { addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class); addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class); addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class); + addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class); addActivityFilter(activityFilters, FaceEnrollIntroduction.class); addActivityFilter(activityFilters, RemoteAuthActivity.class); addActivityFilter(activityFilters, RemoteAuthActivityInternal.class); From 47973b88acfbb93ae4471bfc108859f26f50803b Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Thu, 14 Mar 2024 15:15:53 +0000 Subject: [PATCH 05/11] Auth-bound keys usability: Update strings Update the strings for the warning shown to the user when they are about to remove their screen lock and there are authentication-bound keys that would be invalidated. These strings are provided by Android UXW. Additionally, apply the new string to all types of device lock screen: Pattern, password and unknown. Bug: 302109605 Test: Manual, flashed a device and added different types of screen lock. Change-Id: Ida6f5f16c5aa1671f3f2c1358160b8173a1d1407 --- res/values/strings.xml | 17 ++--- .../settings/password/ChooseLockGeneric.java | 66 ++++++++++++++----- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index dd51f522b1f..732bbca5b3b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1542,20 +1542,12 @@ "A pattern protects your phone if it\u2019s lost or stolen.\n\nThis deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps." "A PIN protects your phone if it\u2019s lost or stolen" - - "You will lose saved data like your PIN.\n\nCards set up for tap to pay will be removed.\n\nWallets and other apps that require device unlock may not work properly." "A PIN protects your phone if it\u2019s lost or stolen.\n\nThis also deletes the fingerprint model stored on your device. You won\u2019t be able to use your fingerprint for authentication in apps." - - "You will lose saved data like your PIN and fingerprint model.\n\nCards set up for tap to pay will be removed.\n\nWallets and other apps that require device unlock may not work properly." "A PIN protects your phone if it\u2019s lost or stolen.\n\nYour face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps." - - "You will lose saved data like your PIN and face model.\n\nCards set up for tap to pay will be removed.\n\nWallets and other apps that require device unlock may not work properly." "A PIN protects your phone if it\u2019s lost or stolen.\n\nThis deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps." - - "You will lose saved data like your PIN, face and fingerprint models.\n\nCards set up for tap to pay will be removed.\n\nWallets and other apps that require device unlock may not work properly." "A password protects your phone if it\u2019s lost or stolen" @@ -1572,6 +1564,15 @@ "Device protection features will not work without your screen lock.\n\nYour face model will also be permanently and securely deleted. You won\u2019t be able to use your face for authentication in apps." "Device protection features will not work without your screen lock.\n\nThis deletes the fingerprint model stored on your device. Your face model will also be permanently and securely deleted. You won\u2019t be able to use your face or fingerprint for authentication in apps." + + "Your screen lock will be removed.\n\nTap to pay won\u2019t be available.\n\nWallet, payment, and other apps that require authentication may not work properly." + + "Your screen lock and Fingerprint Unlock will be removed.\n\nTap to pay won\u2019t be available.\n\nWallet, payment, and other apps that require authentication may not work properly." + + "Your screen lock and Face Unlock will be removed.\n\nTap to pay won\u2019t be available.\n\nWallet, payment, and other apps that require authentication may not work properly." + + "Your screen lock and Face & Fingerprint Unlock will be removed.\n\nTap to pay won\u2019t be available.\n\nWallet, payment, and other apps that require authentication may not work properly." + Delete diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 178c3872c21..4aa751bdbb2 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -927,34 +927,45 @@ public class ChooseLockGeneric extends SettingsActivity { switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) { case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: if (hasFingerprints && hasFace) { - return R.string.unlock_disable_frp_warning_content_pattern_face_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_pattern_face_fingerprint; } else if (hasFingerprints) { - return R.string.unlock_disable_frp_warning_content_pattern_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_pattern_fingerprint; } else if (hasFace) { - return R.string.unlock_disable_frp_warning_content_pattern_face; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_authbound_keys + : R.string.unlock_disable_frp_warning_content_pattern_face; } else { - return R.string.unlock_disable_frp_warning_content_pattern; + return hasAppsWithAuthBoundKeys + ? R.string.unlock_disable_frp_warning_content_authbound_keys + : R.string.unlock_disable_frp_warning_content_pattern; } case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: if (hasFingerprints && hasFace) { return hasAppsWithAuthBoundKeys ? - R.string.unlock_disable_frp_warning_content_pin_face_fingerprint_authbound_keys + R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys : R.string.unlock_disable_frp_warning_content_pin_face_fingerprint; } else if (hasFingerprints) { return hasAppsWithAuthBoundKeys ? - R.string.unlock_disable_frp_warning_content_pin_fingerprint_authbound_keys + R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys : R.string.unlock_disable_frp_warning_content_pin_fingerprint; } else if (hasFace) { return hasAppsWithAuthBoundKeys ? - R.string.unlock_disable_frp_warning_content_pin_face_authbound_keys + R.string.unlock_disable_frp_warning_content_face_authbound_keys : R.string.unlock_disable_frp_warning_content_pin_face; } else { return hasAppsWithAuthBoundKeys - ? R.string.unlock_disable_frp_warning_content_pin_authbound_keys + ? R.string.unlock_disable_frp_warning_content_authbound_keys : R.string.unlock_disable_frp_warning_content_pin; } case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: @@ -962,24 +973,45 @@ public class ChooseLockGeneric extends SettingsActivity { case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: if (hasFingerprints && hasFace) { - return R.string - .unlock_disable_frp_warning_content_password_face_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_password_face_fingerprint; } else if (hasFingerprints) { - return R.string.unlock_disable_frp_warning_content_password_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_password_fingerprint; } else if (hasFace) { - return R.string.unlock_disable_frp_warning_content_password_face; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_authbound_keys + : R.string.unlock_disable_frp_warning_content_password_face; } else { - return R.string.unlock_disable_frp_warning_content_password; + return hasAppsWithAuthBoundKeys + ? R.string.unlock_disable_frp_warning_content_authbound_keys + : R.string.unlock_disable_frp_warning_content_password; } default: if (hasFingerprints && hasFace) { - return R.string.unlock_disable_frp_warning_content_unknown_face_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_unknown_face_fingerprint; } else if (hasFingerprints) { - return R.string.unlock_disable_frp_warning_content_unknown_fingerprint; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_fingerprint_authbound_keys + : R.string.unlock_disable_frp_warning_content_unknown_fingerprint; } else if (hasFace) { - return R.string.unlock_disable_frp_warning_content_unknown_face; + return hasAppsWithAuthBoundKeys + ? + R.string.unlock_disable_frp_warning_content_face_authbound_keys + : R.string.unlock_disable_frp_warning_content_unknown_face; } else { - return R.string.unlock_disable_frp_warning_content_unknown; + return hasAppsWithAuthBoundKeys + ? R.string.unlock_disable_frp_warning_content_authbound_keys + : R.string.unlock_disable_frp_warning_content_unknown; } } } From 5cdf972b50f81f57360fc456603e704724e02f17 Mon Sep 17 00:00:00 2001 From: Chun-Ku Lin Date: Sat, 16 Mar 2024 01:13:16 +0000 Subject: [PATCH 06/11] Make QS shortcut type as default preferred shortcut for A11yService that associate with a TileService Bug: 322712028 Test: manual (Turn on the shortcut for the first time for various feature with or without tile. Verify only the A11yService with tile would show QS as the shortcut when directly turn on the main shortcut toggle) Test: atest com.android.settings.accessibility Flag: aconfig android.view.accessibility.a11y_qs_shortcut Change-Id: I569b417639d2db8b7eddd818a2b9037ed4be2509 --- .../accessibility/PreferredShortcuts.java | 33 ++-- ...ccessibilityServicePreferenceFragment.java | 15 +- .../ToggleFeaturePreferenceFragment.java | 20 +- ...sibilityServicePreferenceFragmentTest.java | 178 ++++++++++++++++-- .../accessibility/PreferredShortcutsTest.java | 17 ++ 5 files changed, 231 insertions(+), 32 deletions(-) diff --git a/src/com/android/settings/accessibility/PreferredShortcuts.java b/src/com/android/settings/accessibility/PreferredShortcuts.java index e166f38a52f..895430afb73 100644 --- a/src/com/android/settings/accessibility/PreferredShortcuts.java +++ b/src/com/android/settings/accessibility/PreferredShortcuts.java @@ -42,7 +42,8 @@ public final class PreferredShortcuts { /** * Retrieves the user preferred shortcut types for the given {@code componentName} from - * SharedPreferences. + * SharedPreferences. If the user doesn't have a preferred shortcut, + * {@link ShortcutConstants.UserShortcutType.SOFTWARE} is returned. * * @param context {@link Context} to access the {@link SharedPreferences} * @param componentName Name of the service or activity, should be the format of {@link @@ -52,7 +53,26 @@ public final class PreferredShortcuts { @ShortcutConstants.UserShortcutType public static int retrieveUserShortcutType( @NonNull Context context, @NonNull String componentName) { - final int defaultTypes = getDefaultPreferredShortcutTypesForTarget(componentName); + return retrieveUserShortcutType( + context, componentName, ShortcutConstants.UserShortcutType.SOFTWARE); + } + + /** + * Retrieves the user preferred shortcut types for the given {@code componentName} from + * SharedPreferences. + * + * @param context {@link Context} to access the {@link SharedPreferences} + * @param componentName Name of the service or activity, should be the format of {@link + * ComponentName#flattenToString()}. + * @param defaultTypes The default shortcut types to use if the user doesn't have a + * preferred shortcut. + * @return {@link ShortcutConstants.UserShortcutType} + */ + @ShortcutConstants.UserShortcutType + public static int retrieveUserShortcutType( + @NonNull Context context, + @NonNull String componentName, + @ShortcutConstants.UserShortcutType int defaultTypes) { // Create a mutable set to modify final Set info = new HashSet<>(getFromSharedPreferences(context)); @@ -150,14 +170,5 @@ public final class PreferredShortcuts { getSharedPreferences(context).edit().clear().apply(); } - /** - * Returns the default shortcut types for the given accessibility feature. - */ - @ShortcutConstants.UserShortcutType - private static int getDefaultPreferredShortcutTypesForTarget(@NonNull String componentName) { - // TODO (b/322712028): return different default shortcut types for the given component - return ShortcutConstants.UserShortcutType.SOFTWARE; - } - private PreferredShortcuts() {} } diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 0b5ad3ee9f0..e89ff9473c5 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -45,6 +45,7 @@ import android.widget.CompoundButton; import androidx.annotation.Nullable; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment; @@ -330,7 +331,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public void onToggleClicked(ShortcutPreference preference) { final int shortcutTypes = retrieveUserShortcutType(getPrefContext(), - mComponentName.flattenToString()); + mComponentName.flattenToString(), getDefaultShortcutTypes()); if (preference.isChecked()) { final boolean isWarningRequired; if (android.view.accessibility.Flags.cleanupAccessibilityWarningDialog()) { @@ -476,6 +477,16 @@ public class ToggleAccessibilityServicePreferenceFragment extends return TAG; } + @Override + protected int getDefaultShortcutTypes() { + if (android.view.accessibility.Flags.a11yQsShortcut()) { + return getTileComponentName() == null ? super.getDefaultShortcutTypes() + : ShortcutConstants.UserShortcutType.QUICK_SETTINGS; + } + + return super.getDefaultShortcutTypes(); + } + private void onAllowButtonFromEnableToggleClicked() { handleConfirmServiceEnabled(/* confirmed= */ true); if (serviceSupportsAccessibilityButton()) { @@ -507,7 +518,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends mShortcutPreference.setChecked(true); final int shortcutTypes = retrieveUserShortcutType(getPrefContext(), - mComponentName.flattenToString()); + mComponentName.flattenToString(), getDefaultShortcutTypes()); AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); mIsDialogShown.set(false); diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index ed47007fbcf..ef828dbf973 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -54,6 +54,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; @@ -661,7 +662,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment int value = restoreOnConfigChangedValue(); if (value == NOT_SET) { final int lastNonEmptyUserShortcutType = PreferredShortcuts.retrieveUserShortcutType( - getPrefContext(), mComponentName.flattenToString()); + getPrefContext(), mComponentName.flattenToString(), getDefaultShortcutTypes()); value = mShortcutPreference.isChecked() ? lastNonEmptyUserShortcutType : UserShortcutType.EMPTY; } @@ -710,8 +711,8 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment return context.getText(R.string.accessibility_shortcut_state_off); } - final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context, - mComponentName.flattenToString()); + final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType( + context, mComponentName.flattenToString(), getDefaultShortcutTypes()); final List list = new ArrayList<>(); if (android.view.accessibility.Flags.a11yQsShortcut()) { @@ -811,7 +812,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment } final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(), - mComponentName.flattenToString()); + mComponentName.flattenToString(), getDefaultShortcutTypes()); mShortcutPreference.setChecked( AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes, mComponentName)); @@ -829,7 +830,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment } final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(getPrefContext(), - mComponentName.flattenToString()); + mComponentName.flattenToString(), getDefaultShortcutTypes()); if (preference.isChecked()) { AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); @@ -977,4 +978,13 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment boolean isAnySetupWizard() { return WizardManagerHelper.isAnySetupWizard(getIntent()); } + + /** + * Returns the default preferred shortcut types when the user doesn't have a preferred shortcut + * types + */ + @ShortcutConstants.UserShortcutType + protected int getDefaultShortcutTypes() { + return ShortcutConstants.UserShortcutType.SOFTWARE; + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java index 31741012d47..ae4f9a0ec9c 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragmentTest.java @@ -34,10 +34,10 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; -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 android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; import android.service.quicksettings.TileService; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.Flags; @@ -47,6 +47,7 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.accessibility.common.ShortcutConstants; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; @@ -68,13 +69,13 @@ import org.robolectric.shadows.ShadowAccessibilityManager; import org.robolectric.shadows.ShadowPackageManager; import java.util.List; +import java.util.Set; /** Tests for {@link ToggleAccessibilityServicePreferenceFragment} */ @RunWith(RobolectricTestRunner.class) public class ToggleAccessibilityServicePreferenceFragmentTest { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; private static final String PLACEHOLDER_PACKAGE_NAME2 = "com.placeholder.example2"; @@ -236,7 +237,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) public void enableService_warningRequired_showWarning() throws Throwable { setupServiceWarningRequired(true); mFragment.mToggleServiceSwitchPreference = @@ -249,7 +250,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) public void enableService_warningNotRequired_dontShowWarning() throws Throwable { final AccessibilityServiceInfo info = setupServiceWarningRequired(false); mFragment.mToggleServiceSwitchPreference = @@ -263,7 +264,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) public void toggleShortcutPreference_warningRequired_showWarning() throws Throwable { setupServiceWarningRequired(true); mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null); @@ -277,7 +278,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) public void toggleShortcutPreference_warningNotRequired_dontShowWarning() throws Throwable { setupServiceWarningRequired(false); mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null); @@ -291,7 +292,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) public void clickShortcutSettingsPreference_warningRequired_showWarning() throws Throwable { setupServiceWarningRequired(true); mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null); @@ -303,8 +304,8 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) - @RequiresFlagsDisabled( + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @DisableFlags( com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN) public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_showDialog() throws Throwable { @@ -318,7 +319,7 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { } @Test - @RequiresFlagsEnabled({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, + @EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN}) public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_launchActivity() throws Throwable { @@ -334,6 +335,155 @@ public class ToggleAccessibilityServicePreferenceFragmentTest { .isEqualTo(EditShortcutsPreferenceFragment.class.getName()); } + @Test + public void getDefaultShortcutTypes_noAssociatedTile_softwareTypeIsDefault() { + PreferredShortcuts.clearPreferredShortcuts(mContext); + when(mFragment.getTileComponentName()).thenReturn(null); + + assertThat(mFragment.getDefaultShortcutTypes()) + .isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); + } + + @Test + @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void getDefaultShortcutTypes_hasAssociatedTile_qsTypeIsDefault() { + PreferredShortcuts.clearPreferredShortcuts(mContext); + when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME); + + assertThat(mFragment.getDefaultShortcutTypes()) + .isEqualTo(ShortcutConstants.UserShortcutType.QUICK_SETTINGS); + } + + @Test + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void getDefaultShortcutTypes_hasAssociatedTile_softwareTypeIsDefault() { + PreferredShortcuts.clearPreferredShortcuts(mContext); + when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME); + + assertThat(mFragment.getDefaultShortcutTypes()) + .isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE); + } + + @Test + @EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT}) + public void toggleShortcutPreference_noUserPreferredShortcut_hasQsTile_enableQsShortcut() + throws Throwable { + PreferredShortcuts.clearPreferredShortcuts(mContext); + setupServiceWarningRequired(false); + when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + verify(mMockAccessibilityManager) + .enableShortcutsForTargets(true, + ShortcutConstants.UserShortcutType.QUICK_SETTINGS, + Set.of(mFragment.mComponentName.flattenToString()), mContext.getUserId()); + } + + @Test + @EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT}) + public void toggleShortcutPreference_noUserPreferredShortcut_noQsTile_enableSoftwareShortcut() + throws Throwable { + PreferredShortcuts.clearPreferredShortcuts(mContext); + setupServiceWarningRequired(false); + when(mFragment.getTileComponentName()).thenReturn(null); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + verify(mMockAccessibilityManager) + .enableShortcutsForTargets(true, + ShortcutConstants.UserShortcutType.SOFTWARE, + Set.of(mFragment.mComponentName.flattenToString()), mContext.getUserId()); + } + + @Test + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void toggleShortcutPreference_noUserPreferredShortcut_hasQsTile_flagOff_enableSoftwareShortcut() + throws Throwable { + PreferredShortcuts.clearPreferredShortcuts(mContext); + setupServiceWarningRequired(false); + when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + assertThat( + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS)) + .contains(mFragment.mComponentName.flattenToString()); + } + + @Test + @EnableFlags(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG) + @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) + public void toggleShortcutPreference_noUserPreferredShortcut_noQsTile_flagOff_enableSoftwareShortcut() + throws Throwable { + PreferredShortcuts.clearPreferredShortcuts(mContext); + setupServiceWarningRequired(false); + when(mFragment.getTileComponentName()).thenReturn(null); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + assertThat( + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS)) + .contains(mFragment.mComponentName.flattenToString()); + } + + @Test + @EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT}) + public void toggleShortcutPreference_userPreferVolumeKeysShortcut_noQsTile_enableVolumeKeysShortcut() + throws Throwable { + setupServiceWarningRequired(false); + String componentName = mFragment.mComponentName.flattenToString(); + PreferredShortcuts.saveUserShortcutType( + mContext, + new PreferredShortcut(componentName, ShortcutConstants.UserShortcutType.HARDWARE)); + when(mFragment.getTileComponentName()).thenReturn(null); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + verify(mMockAccessibilityManager) + .enableShortcutsForTargets( + true, + ShortcutConstants.UserShortcutType.HARDWARE, + Set.of(componentName), + mContext.getUserId()); + } + + @Test + @EnableFlags({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG, Flags.FLAG_A11Y_QS_SHORTCUT}) + public void toggleShortcutPreference_userPreferVolumeKeysShortcut_hasQsTile_enableVolumeKeysShortcut() + throws Throwable { + setupServiceWarningRequired(false); + String componentName = mFragment.mComponentName.flattenToString(); + PreferredShortcuts.saveUserShortcutType( + mContext, + new PreferredShortcut(componentName, ShortcutConstants.UserShortcutType.HARDWARE)); + when(mFragment.getTileComponentName()).thenReturn(PLACEHOLDER_TILE_COMPONENT_NAME); + mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null); + + mFragment.mShortcutPreference.setChecked(true); + mFragment.onToggleClicked(mFragment.mShortcutPreference); + + verify(mMockAccessibilityManager) + .enableShortcutsForTargets( + true, + ShortcutConstants.UserShortcutType.HARDWARE, + Set.of(componentName), + mContext.getUserId()); + } + private void setupTileService(String packageName, String name, String tileName) { final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE); final ResolveInfo info = new ResolveInfo(); diff --git a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java index 4ef63d0df81..364b17cc646 100644 --- a/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java +++ b/tests/unit/src/com/android/settings/accessibility/PreferredShortcutsTest.java @@ -208,6 +208,23 @@ public class PreferredShortcutsTest { assertThat(savedPreferredShortcut).isEqualTo(UserShortcutType.HARDWARE); } + @Test + public void retrieveUserShortcutTypeWithoutDefault_noUserPreferredShortcuts_returnSoftwareShortcut() { + String target = COMPONENT_NAME_1.flattenToString(); + + assertThat(PreferredShortcuts.retrieveUserShortcutType(mContext, target)) + .isEqualTo(UserShortcutType.SOFTWARE); + } + + @Test + public void retrieveUserShortcutTypeWithDefaultAsDefault_noUserPreferredShortcuts_returnSpecifiedDefault() { + String target = COMPONENT_NAME_1.flattenToString(); + + assertThat(PreferredShortcuts.retrieveUserShortcutType(mContext, target, + UserShortcutType.HARDWARE)) + .isEqualTo(UserShortcutType.HARDWARE); + } + private static void clearShortcuts() { Settings.Secure.putString(sContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, ""); From 18f3d29a5c8edecaf92d978f5b5c8df220f6d3f0 Mon Sep 17 00:00:00 2001 From: Charlotte Lu Date: Mon, 18 Mar 2024 11:30:59 +0800 Subject: [PATCH 07/11] Add server name title. Test: Manual Fix: 330084607 Change-Id: I11f2cc995d5d09d04bbfb3d95b9bf5309813e8eb --- res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 5c98fac6153..da0c7540059 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2317,6 +2317,8 @@ Network details Subnet mask + + Server name Type From be49e61d0f9d666b7e598a72999f3870fffd83f0 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Tue, 12 Mar 2024 18:30:52 +0800 Subject: [PATCH 08/11] Enforce BaseUserRestriction for DISALLOW_CONFIG_BRIGHTNESS Fix: 329205638 Test: pm set-user-restriction --user 0 no_config_brightness 1 Change-Id: Icacf051789ea40d23cd29c16168fbeb204cf8f5b --- .../display/BrightnessLevelPreferenceController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java index ac1a1cbf12a..468a1d8dd7f 100644 --- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java +++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java @@ -31,6 +31,8 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.net.Uri; import android.os.Handler; import android.os.Looper; +import android.os.Process; +import android.os.UserManager; import android.provider.Settings.System; import android.text.TextUtils; @@ -116,6 +118,10 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr @Override public void updateState(Preference preference) { + if (preference.isEnabled() && UserManager.get(mContext).hasBaseUserRestriction( + UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())) { + preference.setEnabled(false); + } updatedSummary(preference); } From 10f5bdabb468b806d634a2b9061b9908b2e8d430 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Mon, 18 Mar 2024 13:40:30 +0800 Subject: [PATCH 09/11] Fix SubscriptionInfoListViewModelTest Fix: 329160337 Test: unit test Change-Id: I7a3d27cb53c930a56ab0f0896b545807bf4f9dc0 --- .../SubscriptionInfoListViewModelTest.kt | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/tests/spa_unit/src/com/android/settings/network/SubscriptionInfoListViewModelTest.kt b/tests/spa_unit/src/com/android/settings/network/SubscriptionInfoListViewModelTest.kt index 020a4706997..6eb7c586b3c 100644 --- a/tests/spa_unit/src/com/android/settings/network/SubscriptionInfoListViewModelTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/SubscriptionInfoListViewModelTest.kt @@ -23,12 +23,9 @@ import android.content.Context import android.platform.test.flag.junit.SetFlagsRule import android.telephony.SubscriptionInfo import android.telephony.SubscriptionManager -import android.telephony.TelephonyCallback -import android.telephony.TelephonyManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.internal.telephony.flags.Flags -import com.android.settings.network.telephony.CallStateFlowTest import com.android.settingslib.spa.testutils.toListWithTimeout import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.async @@ -42,7 +39,6 @@ import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.spy -import org.mockito.kotlin.stub @RunWith(AndroidJUnit4::class) class SubscriptionInfoListViewModelTest { @@ -62,8 +58,7 @@ class SubscriptionInfoListViewModelTest { on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager } - private val subscriptionInfoListViewModel: SubscriptionInfoListViewModel = - SubscriptionInfoListViewModel(context as Application); + private fun createViewModel() = SubscriptionInfoListViewModel(context as Application) private var activeSubscriptionInfoList: List? = null @@ -72,7 +67,7 @@ class SubscriptionInfoListViewModelTest { activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2) val listDeferred = async { - subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout() + createViewModel().subscriptionInfoListFlow.toListWithTimeout() } delay(100) subInfoListener?.onSubscriptionsChanged() @@ -83,49 +78,44 @@ class SubscriptionInfoListViewModelTest { @Test fun onSubscriptionsChanged_hasProvisioning_filterProvisioning() = runBlocking { activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_3) - val expectation = listOf(SUB_INFO_1, SUB_INFO_2) val listDeferred = async { - subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout() + createViewModel().subscriptionInfoListFlow.toListWithTimeout() } delay(100) subInfoListener?.onSubscriptionsChanged() - assertThat(listDeferred.await()).contains(expectation) + assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2)) } @Test fun onSubscriptionsChanged_flagOffHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() = runBlocking { mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) - activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4) - val expectation = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4) val listDeferred = async { - subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout() + createViewModel().subscriptionInfoListFlow.toListWithTimeout() } delay(100) subInfoListener?.onSubscriptionsChanged() - assertThat(listDeferred.await()).contains(expectation) + assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4)) } @Test fun onSubscriptionsChanged_flagOnHasNonTerrestrialNetwork_filterNonTerrestrialNetwork() = runBlocking { mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) - activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2, SUB_INFO_4) - val expectation = listOf(SUB_INFO_1, SUB_INFO_2) val listDeferred = async { - subscriptionInfoListViewModel.subscriptionInfoListFlow.toListWithTimeout() + createViewModel().subscriptionInfoListFlow.toListWithTimeout() } delay(100) subInfoListener?.onSubscriptionsChanged() - assertThat(listDeferred.await()).contains(expectation) + assertThat(listDeferred.await()).contains(listOf(SUB_INFO_1, SUB_INFO_2)) } private companion object { From 99fb1065fa4500aa18124bde0ecc37a403ae0756 Mon Sep 17 00:00:00 2001 From: Allen Su Date: Mon, 11 Mar 2024 07:16:19 +0000 Subject: [PATCH 10/11] Fix Locale unit test failure Bug: 301380610 Bug: 313604701 Test: atest LocalePickerActivityTest Change-Id: Icab8eeea62c7c40c160d745afd08f71fcca5ec9c --- .../settings/localepicker/AppLocalePickerActivityTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java b/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java index 2989324701f..58ce1b2d028 100644 --- a/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java +++ b/tests/robotests/src/com/android/settings/localepicker/AppLocalePickerActivityTest.java @@ -58,7 +58,6 @@ import com.android.settings.testutils.FakeFeatureFactory; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -203,7 +202,6 @@ public class AppLocalePickerActivityTest { assertThat(controller.get().isFinishing()).isTrue(); } - @Ignore("b/313604701") @Test public void onLocaleSelected_getLocaleNotNull_getLanguageTag() { ActivityController controller = @@ -216,7 +214,10 @@ public class AppLocalePickerActivityTest { AppLocalePickerActivity mActivity = controller.get(); mActivity.onLocaleSelected(mLocaleInfo); - verify(mLocaleInfo, times(2)).getLocale(); + // 1st for getLocale()!= null + // 2nd for setAppDefaultLocale(getLocale()) + // 3rd for broadcastAppLocaleChange() + verify(mLocaleInfo, times(3)).getLocale(); assertThat(mLocaleInfo.getLocale().toLanguageTag()).isEqualTo("en-US"); assertThat(controller.get().isFinishing()).isTrue(); } From 6666bb97b482812084e21fb6de53d01d308f65e0 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 6 Mar 2024 09:11:34 +0000 Subject: [PATCH 11/11] Show calibtation result in FingerprintSettings & EnrollEnrolling if results are available Bug: b/326155807 Test: Enroll multiple fingerprints and check if calibration isn't triggered. Change-Id: I006db64f001fb70d2bb294a15a2d3efc77e2da25 --- .../FingerprintEnrollEnrolling.java | 21 ++++++++----------- .../FingerprintEnrollFindSensor.java | 4 ++-- .../FingerprintEnrollIntroduction.java | 2 +- .../fingerprint/FingerprintSettings.java | 16 ++++++++++++++ .../SetupFingerprintEnrollFindSensor.java | 2 +- .../SetupFingerprintEnrollIntroduction.java | 2 +- .../fingerprint/UdfpsEnrollCalibrator.kt | 7 ++++--- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 90b93461b9c..bbeaf2afb85 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -71,7 +71,6 @@ import com.android.settings.biometrics.BiometricsEnrollEnrolling; import com.android.settings.biometrics.BiometricsSplitScreenDialog; import com.android.settings.biometrics.fingerprint.feature.SfpsEnrollmentFeature; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; -import com.android.settings.flags.Flags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.display.DisplayDensityUtils; @@ -252,12 +251,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { setContentView(layout); setDescriptionText(R.string.security_settings_udfps_enroll_start_message); - - if (Flags.udfpsEnrollCalibration()) { - mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() - .getUdfpsEnrollCalibrator(getApplicationContext(), savedInstanceState, - getIntent()); - } } else if (mCanAssumeSfps) { mSfpsEnrollmentFeature = FeatureFactory.getFeatureFactory() .getFingerprintFeatureProvider().getSfpsEnrollmentFeature(); @@ -342,6 +335,15 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { final Configuration config = getApplicationContext().getResources().getConfiguration(); maybeHideSfpsText(config); + + if (!mIsSetupWizard) { + mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() + .getUdfpsEnrollCalibrator(getApplicationContext(), null, getIntent()); + if (mCalibrator != null) { + mCalibrator.onWaitingPage(getLifecycle(), + getSupportFragmentManager(), null); + } + } } private void setHelpAnimation() { @@ -371,11 +373,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { super.onSaveInstanceState(outState); outState.putBoolean(KEY_STATE_CANCELED, mIsCanceled); outState.putInt(KEY_STATE_PREVIOUS_ROTATION, mPreviousRotation); - if (Flags.udfpsEnrollCalibration()) { - if (mCalibrator != null) { - mCalibrator.onSaveInstanceState(outState); - } - } } private void restoreSavedState(Bundle savedInstanceState) { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index 6b7538ae220..aeb0dac97c4 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -167,7 +167,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements .getUdfpsEnrollCalibrator(getApplicationContext(), savedInstanceState, getIntent()); if (mCalibrator != null) { - mCalibrator.onFindSensorPage( + mCalibrator.onWaitingPage( getLifecycle(), getSupportFragmentManager(), this::enableUdfpsLottieAndNextButton @@ -296,7 +296,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements getIntent().getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1)); if (Flags.udfpsEnrollCalibration()) { if (mCalibrator != null) { - ret.putExtras(mCalibrator.getExtrasForNextIntent(true)); + ret.putExtras(mCalibrator.getExtrasForNextIntent()); } } return ret; diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java index f92cfbf6696..59e4035497c 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java @@ -384,7 +384,7 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction { } if (Flags.udfpsEnrollCalibration()) { if (mCalibrator != null) { - intent.putExtras(mCalibrator.getExtrasForNextIntent(false)); + intent.putExtras(mCalibrator.getExtrasForNextIntent()); } } intent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON, diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 2aacbe4bd88..9dac46dd1d1 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -88,6 +88,7 @@ import com.android.settingslib.transition.SettingsTransitionHelper; import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.TwoTargetPreference; +import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.util.DeviceHelper; import java.util.ArrayList; @@ -111,6 +112,9 @@ public class FingerprintSettings extends SubSettings { private static final int RESULT_SKIP = BiometricEnrollBase.RESULT_SKIP; private static final int RESULT_TIMEOUT = BiometricEnrollBase.RESULT_TIMEOUT; + @Nullable + private UdfpsEnrollCalibrator mCalibrator; + @Override public Intent getIntent() { Intent modIntent = new Intent(super.getIntent()); @@ -131,6 +135,13 @@ public class FingerprintSettings extends SubSettings { setTitle(msg); } + @Override + public void onResume() { + super.onResume(); + mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() + .getUdfpsEnrollCalibrator(getApplicationContext(), null, null); + } + /** * @param context * @return true if the Fingerprint hardware is detected. @@ -800,6 +811,11 @@ public class FingerprintSettings extends SubSettings { } intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); + if (((FingerprintSettings) getActivity()).mCalibrator != null) { + intent.putExtras( + (((FingerprintSettings) getActivity()).mCalibrator) + .getExtrasForNextIntent()); + } startActivityForResult(intent, ADD_FINGERPRINT_REQUEST); } else if (pref instanceof FingerprintPreference) { FingerprintPreference fpref = (FingerprintPreference) pref; diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java index 6590530cecf..3037c2a61eb 100644 --- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensor.java @@ -51,7 +51,7 @@ public class SetupFingerprintEnrollFindSensor extends FingerprintEnrollFindSenso SetupWizardUtils.copySetupExtras(getIntent(), intent); if (Flags.udfpsEnrollCalibration()) { if (mCalibrator != null) { - intent.putExtras(mCalibrator.getExtrasForNextIntent(true)); + intent.putExtras(mCalibrator.getExtrasForNextIntent()); } } return intent; diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java index 0ee9ad380b5..c263b2e4e2d 100644 --- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java @@ -49,7 +49,7 @@ public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntrodu SetupWizardUtils.copySetupExtras(getIntent(), intent); if (Flags.udfpsEnrollCalibration()) { if (mCalibrator != null) { - intent.putExtras(mCalibrator.getExtrasForNextIntent(false)); + intent.putExtras(mCalibrator.getExtrasForNextIntent()); } } return intent; diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollCalibrator.kt b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollCalibrator.kt index c54c6b5eba5..22a69baacb0 100644 --- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollCalibrator.kt +++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollCalibrator.kt @@ -6,13 +6,14 @@ import androidx.lifecycle.Lifecycle interface UdfpsEnrollCalibrator { - fun getExtrasForNextIntent(isEnrolling: Boolean): Bundle + fun getExtrasForNextIntent(): Bundle fun onSaveInstanceState(outState: Bundle) - fun onFindSensorPage( + fun onWaitingPage( lifecycle: Lifecycle, fragmentManager: FragmentManager, - enableEnrollingRunnable: Runnable + enableEnrollingRunnable: Runnable? ) + } \ No newline at end of file