diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 47d3360fa09..d3c82d6cd5a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5508,6 +5508,24 @@ android:value="com.android.settings.applications.contacts.ContactsStorageSettings"/> + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/keyboard_arrow_right.xml b/res/drawable/keyboard_arrow_right.xml new file mode 100644 index 00000000000..ba763690521 --- /dev/null +++ b/res/drawable/keyboard_arrow_right.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/accessibility_text_reading_preview.xml b/res/layout/accessibility_text_reading_preview.xml index 830d9e66778..2532a7957eb 100644 --- a/res/layout/accessibility_text_reading_preview.xml +++ b/res/layout/accessibility_text_reading_preview.xml @@ -38,20 +38,47 @@ android:text="@string/screen_zoom_preview_title" style="@style/AccessibilityTextReadingPreviewTitle" /> - - - + android:orientation="vertical"> + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index d8dbd1a3743..3bc451bc1fd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -80,6 +80,10 @@ Preview QR code + + Previous preview + + Next preview Make smaller @@ -174,6 +178,12 @@ Left Right + + Surroundings + + Left surroundings + + Right surroundings Mute surroundings @@ -521,6 +531,8 @@ Add a language Choose a region + + Number System Region preference @@ -536,7 +548,7 @@ Your device will keep %1$s as a system language - Most apps will use your regional preferences + Choose how your device, websites, and apps display numbers @@ -3163,6 +3175,7 @@ Will turn off when %1$s ends Dark theme uses a black background to help keep battery alive longer on some screens. Dark theme schedules wait to turn on until your screen is off. + Use a dark background to make your screen more comfortable to view and reduce battery usage on some screens. Your theme will change if you have a schedule, when the screen is off. Dark theme is currently following your Bedtime mode schedule @@ -5560,7 +5573,7 @@ Make more apps dark - Automatically convert light theme apps to dark theme + Expands dark theme to more apps. May not work with all apps. Remove animations @@ -6981,7 +6994,8 @@ Data usage charges may apply. Other options are disabled by your admin - Learn more + + Learn more about disabled screen timeout options Notification log Notification history @@ -9315,7 +9329,7 @@ Data usage charges may apply. It can turn Do Not Disturb on or off and change related settings. It can manage and activate Modes, and change related settings. - If you turn off notification access for %1$s, Do Not Disturb access may also be turned off. + If you turn off notification access for %1$s, Do Not Disturb control may also be turned off. If you turn off notification access for %1$s, Modes access may also be turned off. @@ -9498,14 +9512,14 @@ Data usage charges may apply. The placeholder would be the app name (e.g. Calendar). [CHAR LIMIT=NONE]--> Tap to get the app - - Do Not Disturb access + + Do Not Disturb control Allow Do Not Disturb - - No installed apps have requested Do Not Disturb access + + No installed apps have requested Do Not Disturb control Modes access @@ -9513,7 +9527,7 @@ Data usage charges may apply. Allow Modes access - + No installed apps have requested Modes access diff --git a/res/xml/accessibility_vibration_intensity_settings.xml b/res/xml/accessibility_vibration_intensity_settings.xml index ba1bd83da94..17e9f93b7b9 100644 --- a/res/xml/accessibility_vibration_intensity_settings.xml +++ b/res/xml/accessibility_vibration_intensity_settings.xml @@ -29,7 +29,7 @@ android:key="vibration_intensity_category_call" android:title="@string/accessibility_call_vibration_category_title"> - - - - - + + + \ No newline at end of file diff --git a/res/xml/dark_mode_settings.xml b/res/xml/dark_mode_settings.xml index 44bd807b660..f886daf2e5b 100644 --- a/res/xml/dark_mode_settings.xml +++ b/res/xml/dark_mode_settings.xml @@ -22,8 +22,8 @@ + settings:searchable="false" + settings:controller="com.android.settings.display.darkmode.DarkModeTopIntroPreferenceController"/> + viewPager.setCurrentItem(getCurrentItem() - 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_previous_button)); + nextButton.setOnClickListener((view) -> + viewPager.setCurrentItem(getCurrentItem() + 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_next_button)); } @Override diff --git a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java index bc8c6005806..f39cd96d63f 100644 --- a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java +++ b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java @@ -24,10 +24,10 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.SliderPreferenceController; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.widget.SliderPreference; /** * Abstract preference controller for a vibration intensity setting, that displays multiple @@ -69,15 +69,16 @@ public abstract class VibrationIntensityPreferenceController extends SliderPrefe @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - final SeekBarPreference preference = screen.findPreference(getPreferenceKey()); + final SliderPreference preference = screen.findPreference(getPreferenceKey()); mSettingsContentObserver.onDisplayPreference(this, preference); preference.setEnabled(mPreferenceConfig.isPreferenceEnabled()); preference.setSummaryProvider(unused -> mPreferenceConfig.getSummary()); preference.setMin(getMin()); preference.setMax(getMax()); + preference.setSliderIncrement(1); // Discrete slider // Haptics previews played by the Settings app don't bypass user settings to be played. // The sliders continuously updates the intensity value so the previews can apply them. - preference.setContinuousUpdates(true); + preference.setUpdatesContinuously(true); } @Override diff --git a/src/com/android/settings/bluetooth/AmbientVolumePreference.java b/src/com/android/settings/bluetooth/AmbientVolumePreference.java index b39e9613ce4..0230205ce0d 100644 --- a/src/com/android/settings/bluetooth/AmbientVolumePreference.java +++ b/src/com/android/settings/bluetooth/AmbientVolumePreference.java @@ -339,9 +339,16 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV if (side == SIDE_LEFT) { slider.setTitle( getContext().getString(R.string.bluetooth_ambient_volume_control_left)); + slider.setSliderContentDescription(getContext().getString( + R.string.bluetooth_ambient_volume_control_left_description)); } else if (side == SIDE_RIGHT) { slider.setTitle( getContext().getString(R.string.bluetooth_ambient_volume_control_right)); + slider.setSliderContentDescription(getContext().getString( + R.string.bluetooth_ambient_volume_control_right_description)); + } else { + slider.setSliderContentDescription(getContext().getString( + R.string.bluetooth_ambient_volume_control_description)); } mSideToSliderMap.put(side, slider); } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivity.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivity.java new file mode 100644 index 00000000000..82c099d6cdc --- /dev/null +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivity.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import android.os.Bundle; + +import com.android.settings.SettingsActivity; +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.flags.Flags; + +public class AudioSharingJoinHandlerActivity extends SettingsActivity { + private static final String TAG = "AudioSharingJoinHandlerActivity"; + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + if (!Flags.promoteAudioSharingForSecondAutoConnectedLeaDevice() + || !BluetoothUtils.isAudioSharingUIAvailable(this)) { + finish(); + } + } + + @Override + protected boolean isToolbarEnabled() { + return false; + } + + @Override + protected boolean isValidFragment(String fragmentName) { + return AudioSharingJoinHandlerDashboardFragment.class.getName().equals(fragmentName); + } +} diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerController.java new file mode 100644 index 00000000000..6b664788d64 --- /dev/null +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerController.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceScreen; + +import com.android.settings.bluetooth.Utils; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.BluetoothEventManager; +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.flags.Flags; +import com.android.settingslib.utils.ThreadUtils; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class AudioSharingJoinHandlerController extends BasePreferenceController + implements DefaultLifecycleObserver, BluetoothCallback { + private static final String TAG = "AudioSharingJoinHandlerCtrl"; + private static final String KEY = "audio_sharing_join_handler"; + + @Nullable private final LocalBluetoothManager mBtManager; + @Nullable private final BluetoothEventManager mEventManager; + @Nullable private final CachedBluetoothDeviceManager mDeviceManager; + @Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant; + private final Executor mExecutor; + @Nullable private DashboardFragment mFragment; + @Nullable private AudioSharingDialogHandler mDialogHandler; + @VisibleForTesting + BluetoothLeBroadcastAssistant.Callback mAssistantCallback = + new BluetoothLeBroadcastAssistant.Callback() { + @Override + public void onSearchStarted(int reason) { + } + + @Override + public void onSearchStartFailed(int reason) { + } + + @Override + public void onSearchStopped(int reason) { + } + + @Override + public void onSearchStopFailed(int reason) { + } + + @Override + public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) { + } + + @Override + public void onSourceAdded( + @NonNull BluetoothDevice sink, int sourceId, int reason) { + Log.d(TAG, "onSourceAdded: dismiss stale dialog."); + if (mDeviceManager != null && mDialogHandler != null) { + CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(sink); + if (cachedDevice != null) { + mDialogHandler.closeOpeningDialogsForLeaDevice(cachedDevice); + } + } + } + + @Override + public void onSourceAddFailed( + @NonNull BluetoothDevice sink, + @NonNull BluetoothLeBroadcastMetadata source, + int reason) { + } + + @Override + public void onSourceModified( + @NonNull BluetoothDevice sink, int sourceId, int reason) { + } + + @Override + public void onSourceModifyFailed( + @NonNull BluetoothDevice sink, int sourceId, int reason) { + } + + @Override + public void onSourceRemoved( + @NonNull BluetoothDevice sink, int sourceId, int reason) { + } + + @Override + public void onSourceRemoveFailed( + @NonNull BluetoothDevice sink, int sourceId, int reason) { + } + + @Override + public void onReceiveStateChanged( + @NonNull BluetoothDevice sink, + int sourceId, + @NonNull BluetoothLeBroadcastReceiveState state) { + } + }; + + public AudioSharingJoinHandlerController(@NonNull Context context, + @NonNull String preferenceKey) { + super(context, preferenceKey); + mBtManager = Utils.getLocalBtManager(mContext); + mEventManager = mBtManager == null ? null : mBtManager.getEventManager(); + mDeviceManager = mBtManager == null ? null : mBtManager.getCachedDeviceManager(); + mAssistant = mBtManager == null ? null + : mBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile(); + mExecutor = Executors.newSingleThreadExecutor(); + } + + /** + * Initialize the controller. + * + * @param fragment The fragment to provide the context and metrics category for {@link + * AudioSharingBluetoothDeviceUpdater} and provide the host for dialogs. + */ + public void init(@NonNull DashboardFragment fragment) { + mFragment = fragment; + mDialogHandler = new AudioSharingDialogHandler(mContext, fragment); + } + + @Override + public void onStart(@NonNull LifecycleOwner owner) { + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStart(), feature is not supported."); + return; + } + if (mEventManager == null || mDialogHandler == null || mAssistant == null) { + Log.d(TAG, "Skip onStart(), profile is not ready."); + return; + } + Log.d(TAG, "onStart() Register callbacks."); + mEventManager.registerCallback(this); + mAssistant.registerServiceCallBack(mExecutor, mAssistantCallback); + mDialogHandler.registerCallbacks(mExecutor); + }); + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + var unused = ThreadUtils.postOnBackgroundThread(() -> { + if (!isAvailable()) { + Log.d(TAG, "Skip onStop(), feature is not supported."); + return; + } + if (mEventManager == null || mDialogHandler == null || mAssistant == null) { + Log.d(TAG, "Skip onStop(), profile is not ready."); + return; + } + Log.d(TAG, "onStop() Unregister callbacks."); + mEventManager.unregisterCallback(this); + mAssistant.unregisterServiceCallBack(mAssistantCallback); + mDialogHandler.unregisterCallbacks(); + }); + } + + + @Override + public int getAvailabilityStatus() { + return (Flags.promoteAudioSharingForSecondAutoConnectedLeaDevice() + && BluetoothUtils.isAudioSharingUIAvailable(mContext)) + ? AVAILABLE_UNSEARCHABLE + : UNSUPPORTED_ON_DEVICE; + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + public int getSliceHighlightMenuRes() { + return 0; + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + if (mFragment == null + || mFragment.getActivity() == null + || mFragment.getActivity().getIntent() == null) { + Log.d(TAG, "Skip handleDeviceConnectedFromIntent, fragment intent is null"); + return; + } + Intent intent = mFragment.getActivity().getIntent(); + var unused = + ThreadUtils.postOnBackgroundThread(() -> handleDeviceConnectedFromIntent(intent)); + } + + @Override + public void onProfileConnectionStateChanged( + @NonNull CachedBluetoothDevice cachedDevice, + @ConnectionState int state, + int bluetoothProfile) { + if (mDialogHandler == null || mFragment == null) { + Log.d(TAG, "Ignore onProfileConnectionStateChanged, not init correctly"); + return; + } + // Close related dialogs if the BT remote device is disconnected. + if (state == BluetoothAdapter.STATE_DISCONNECTED) { + boolean isLeAudioSupported = BluetoothUtils.isLeAudioSupported(cachedDevice); + if (isLeAudioSupported + && bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT) { + mDialogHandler.closeOpeningDialogsForLeaDevice(cachedDevice); + } else if (!isLeAudioSupported && !cachedDevice.isConnected()) { + mDialogHandler.closeOpeningDialogsForNonLeaDevice(cachedDevice); + } + } + } + + /** Handle just connected device via intent. */ + @WorkerThread + public void handleDeviceConnectedFromIntent(@NonNull Intent intent) { + BluetoothDevice device = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE, + BluetoothDevice.class); + CachedBluetoothDevice cachedDevice = + (device == null || mDeviceManager == null) + ? null + : mDeviceManager.findDevice(device); + if (cachedDevice == null) { + Log.d(TAG, "Skip handleDeviceConnectedFromIntent, device is null"); + return; + } + if (mDialogHandler == null) { + Log.d(TAG, "Skip handleDeviceConnectedFromIntent, handler is null"); + return; + } + Log.d(TAG, "handleDeviceConnectedFromIntent, device = " + device.getAnonymizedAddress()); + mDialogHandler.handleDeviceConnected(cachedDevice, /* userTriggered= */ false); + } + + @VisibleForTesting + void setDialogHandler(@Nullable AudioSharingDialogHandler dialogHandler) { + mDialogHandler = dialogHandler; + } +} diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragment.java new file mode 100644 index 00000000000..ff7dab6205f --- /dev/null +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragment.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; + +public class AudioSharingJoinHandlerDashboardFragment extends DashboardFragment { + private static final String TAG = "AudioSharingJoinHandlerFrag"; + + @Nullable private AudioSharingJoinHandlerController mController; + + @Override + public int getMetricsCategory() { + // TODO: use real enum + return 0; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.bluetooth_le_audio_sharing_join_handler; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mController = use(AudioSharingJoinHandlerController.class); + if (mController != null) { + mController.init(this); + } + } +} diff --git a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java index 84fbc05f1c9..75b94395963 100644 --- a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java +++ b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java @@ -16,8 +16,6 @@ package com.android.settings.connecteddevice.display; -import static android.view.Display.INVALID_DISPLAY; - import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DISPLAY_ID_ARG; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_NOT_FOUND_RESOURCE; @@ -60,7 +58,6 @@ import com.android.settingslib.display.DisplayDensityUtils; import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.IllustrationPreference; import com.android.settingslib.widget.MainSwitchPreference; -import com.android.settingslib.widget.TwoTargetPreference; import java.util.ArrayList; import java.util.HashMap; @@ -87,10 +84,12 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen EXTERNAL_DISPLAY_RESOLUTION(60, "external_display_resolution", R.string.external_display_resolution_settings_title), - // Built-in display link is after per-display settings. + // Built-in display link is before per-display settings. BUILTIN_DISPLAY_LIST(70, "builtin_display_list_preference", R.string.builtin_display_settings_category), + EXTERNAL_DISPLAY_LIST(-1, "external_display_list", null), + // If shown, footer should appear below everything. FOOTER(90, "footer_preference", null); @@ -106,16 +105,27 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen public final String key; @Nullable public final Integer titleResource; - void apply(Preference preference) { + /** + * Applies this basic data to the given preference. + * + * @param preference object whose properties to set + * @param nth if non-null, disambiguates the key so that other preferences can have the same + * basic properties. Does not affect the order. + */ + void apply(Preference preference, @Nullable Integer nth) { if (order != -1) { preference.setOrder(order); } if (titleResource != null) { preference.setTitle(titleResource); } - preference.setKey(key); + preference.setKey(nth == null ? key : keyForNth(nth)); preference.setPersistent(false); } + + String keyForNth(int nth) { + return key + "_" + nth; + } } static final int EXTERNAL_DISPLAY_SETTINGS_RESOURCE = R.xml.external_display_settings; @@ -131,12 +141,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen R.drawable.external_display_mirror_portrait; static final int EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE = R.string.screen_zoom_short_summary; - @VisibleForTesting - static final String PREVIOUSLY_SHOWN_LIST_KEY = "mPreviouslyShownListOfDisplays"; private boolean mStarted; @Nullable - private IllustrationPreference mImagePreference; - @Nullable private Preference mDisplayTopologyPreference; @Nullable private PreferenceCategory mBuiltinDisplayPreference; @@ -156,7 +162,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen scheduleUpdate(); } }; - private boolean mPreviouslyShownListOfDisplays; public ExternalDisplayPreferenceFragment() {} @@ -175,12 +180,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen return EXTERNAL_DISPLAY_HELP_URL; } - @Override - public void onSaveInstanceStateCallback(@NonNull Bundle outState) { - outState.putSerializable(PREVIOUSLY_SHOWN_LIST_KEY, - mPreviouslyShownListOfDisplays); - } - @Override public void onCreateCallback(@Nullable Bundle icicle) { if (mInjector == null) { @@ -191,7 +190,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @Override public void onActivityCreatedCallback(@Nullable Bundle savedInstanceState) { - restoreState(savedInstanceState); View view = getView(); TextView emptyView = null; if (view != null) { @@ -241,17 +239,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen .setSourceMetricsCategory(getMetricsCategory()).launch(); } - @VisibleForTesting - protected void launchExternalDisplaySettings(final int displayId) { - final Bundle args = new Bundle(); - var context = getPrefContext(); - args.putInt(DISPLAY_ID_ARG, displayId); - new SubSettingLauncher(context) - .setDestination(this.getClass().getName()) - .setArguments(args) - .setSourceMetricsCategory(getMetricsCategory()).launch(); - } - @VisibleForTesting protected void launchBuiltinDisplaySettings() { final Bundle args = new Bundle(); @@ -275,30 +262,33 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen var pref = refresh.findUnusedPreference(PrefBasics.FOOTER.key); if (pref == null) { pref = newFooterPreference(context); - PrefBasics.FOOTER.apply(pref); + PrefBasics.FOOTER.apply(pref, /* nth= */ null); } pref.setTitle(title); refresh.addPreference(pref); } @NonNull - private ListPreference reuseRotationPreference(@NonNull Context context, PrefRefresh refresh) { + private ListPreference reuseRotationPreference(@NonNull Context context, PrefRefresh refresh, + int position) { ListPreference pref = refresh.findUnusedPreference( - PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); + PrefBasics.EXTERNAL_DISPLAY_ROTATION.keyForNth(position)); if (pref == null) { pref = new ListPreference(context); - PrefBasics.EXTERNAL_DISPLAY_ROTATION.apply(pref); + PrefBasics.EXTERNAL_DISPLAY_ROTATION.apply(pref, position); } refresh.addPreference(pref); return pref; } @NonNull - private Preference reuseResolutionPreference(@NonNull Context context, PrefRefresh refresh) { - var pref = refresh.findUnusedPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); + private Preference reuseResolutionPreference(@NonNull Context context, PrefRefresh refresh, + int position) { + var pref = refresh.findUnusedPreference( + PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(position)); if (pref == null) { pref = new Preference(context); - PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.apply(pref); + PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.apply(pref, position); } refresh.addPreference(pref); return pref; @@ -306,41 +296,34 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @NonNull private MainSwitchPreference reuseUseDisplayPreference( - @NonNull Context context, @NonNull PrefRefresh refresh) { + Context context, PrefRefresh refresh, int position) { MainSwitchPreference pref = refresh.findUnusedPreference( - PrefBasics.EXTERNAL_DISPLAY_USE.key); + PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(position)); if (pref == null) { pref = new MainSwitchPreference(context); - PrefBasics.EXTERNAL_DISPLAY_USE.apply(pref); + PrefBasics.EXTERNAL_DISPLAY_USE.apply(pref, position); } refresh.addPreference(pref); return pref; } @NonNull - @VisibleForTesting - IllustrationPreference getIllustrationPreference(@NonNull Context context) { - if (mImagePreference == null) { - mImagePreference = new IllustrationPreference(context); - PrefBasics.ILLUSTRATION.apply(mImagePreference); + private IllustrationPreference reuseIllustrationPreference( + Context context, PrefRefresh refresh) { + IllustrationPreference pref = refresh.findUnusedPreference(PrefBasics.ILLUSTRATION.key); + if (pref == null) { + pref = new IllustrationPreference(context); + PrefBasics.ILLUSTRATION.apply(pref, /* nth= */ null); } - return mImagePreference; - } - - /** - * @return return display id argument of this settings page. - */ - @VisibleForTesting - protected int getDisplayIdArg() { - var args = getArguments(); - return args != null ? args.getInt(DISPLAY_ID_ARG, INVALID_DISPLAY) : INVALID_DISPLAY; + refresh.addPreference(pref); + return pref; } @NonNull private PreferenceCategory getBuiltinDisplayListPreference(@NonNull Context context) { if (mBuiltinDisplayPreference == null) { mBuiltinDisplayPreference = new PreferenceCategory(context); - PrefBasics.BUILTIN_DISPLAY_LIST.apply(mBuiltinDisplayPreference); + PrefBasics.BUILTIN_DISPLAY_LIST.apply(mBuiltinDisplayPreference, /* nth= */ null); } return mBuiltinDisplayPreference; } @@ -356,7 +339,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @NonNull Preference getDisplayTopologyPreference(@NonNull Context context) { if (mDisplayTopologyPreference == null) { mDisplayTopologyPreference = new DisplayTopologyPreference(context); - PrefBasics.DISPLAY_TOPOLOGY.apply(mDisplayTopologyPreference); + PrefBasics.DISPLAY_TOPOLOGY.apply(mDisplayTopologyPreference, /* nth= */ null); } return mDisplayTopologyPreference; } @@ -366,23 +349,23 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen if (pref == null) { pref = new MirrorPreference(context, DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()); - PrefBasics.MIRROR.apply(pref); + PrefBasics.MIRROR.apply(pref, /* nth= */ null); } refresh.addPreference(pref); } @NonNull private AccessibilitySeekBarPreference reuseSizePreference(Context context, - PrefRefresh refresh, int displayId) { + PrefRefresh refresh, int displayId, int position) { AccessibilitySeekBarPreference pref = - refresh.findUnusedPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + refresh.findUnusedPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(position)); if (pref == null) { pref = new AccessibilitySeekBarPreference(context, /* attrs= */ null); pref.setIconStart(R.drawable.ic_remove_24dp); pref.setIconStartContentDescription(R.string.screen_zoom_make_smaller_desc); pref.setIconEnd(R.drawable.ic_add_24dp); pref.setIconEndContentDescription(R.string.screen_zoom_make_larger_desc); - PrefBasics.EXTERNAL_DISPLAY_SIZE.apply(pref); + PrefBasics.EXTERNAL_DISPLAY_SIZE.apply(pref, position); setStateForDisplaySizePreference(context, displayId, pref); } @@ -404,74 +387,43 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen preference.setOnSeekBarChangeListener(seekBarChangeHandler); } - private void restoreState(@Nullable Bundle savedInstanceState) { - if (savedInstanceState == null) { - return; - } - mPreviouslyShownListOfDisplays = Boolean.TRUE.equals(savedInstanceState.getSerializable( - PREVIOUSLY_SHOWN_LIST_KEY, Boolean.class)); - } - private void update() { final var screen = getPreferenceScreen(); if (screen == null || mInjector == null || mInjector.getContext() == null) { return; } try (var cleanableScreen = new PrefRefresh(screen)) { - updateScreenForDisplayId(getDisplayIdArg(), cleanableScreen, mInjector.getContext()); + updateScreen(cleanableScreen, mInjector.getContext()); } } - private void updateScreenForDisplayId(final int displayId, - @NonNull final PrefRefresh screen, @NonNull Context context) { - final var displaysToShow = externalDisplaysToShow(displayId); + private void updateScreen(final PrefRefresh screen, Context context) { + final var displaysToShow = externalDisplaysToShow(); - if (displaysToShow.isEmpty() && displayId == INVALID_DISPLAY) { - showTextWhenNoDisplaysToShow(screen, context); - } else if (displaysToShow.size() == 1 - && ((displayId == INVALID_DISPLAY && !mPreviouslyShownListOfDisplays) - || displaysToShow.get(0).getDisplayId() == displayId)) { - showDisplaySettings(displaysToShow.get(0), screen, context); - if (displayId == INVALID_DISPLAY && isTopologyPaneEnabled(mInjector)) { - // Only show the topology pane if the user did not arrive via the displays list. - maybeAddV2Components(context, screen); - } - } else if (displayId == INVALID_DISPLAY) { - // If ever shown a list of displays - keep showing it for consistency after - // disconnecting one of the displays, and only one display is left. - mPreviouslyShownListOfDisplays = true; + if (displaysToShow.isEmpty()) { + showTextWhenNoDisplaysToShow(screen, context, /* position= */ 0); + } else { showDisplaysList(displaysToShow, screen, context); } - updateSettingsTitle(displaysToShow, displayId); - } - private void updateSettingsTitle(@NonNull final List displaysToShow, int displayId) { final Activity activity = getCurrentActivity(); - if (activity == null) { - return; + if (activity != null) { + activity.setTitle(EXTERNAL_DISPLAY_TITLE_RESOURCE); } - if (displaysToShow.size() == 1 && displaysToShow.get(0).getDisplayId() == displayId) { - var displayName = displaysToShow.get(0).getName(); - if (!displayName.isEmpty()) { - activity.setTitle(displayName.substring(0, Math.min(displayName.length(), 40))); - return; - } - } - activity.setTitle(EXTERNAL_DISPLAY_TITLE_RESOURCE); } private void showTextWhenNoDisplaysToShow(@NonNull final PrefRefresh screen, - @NonNull Context context) { + @NonNull Context context, int position) { if (isUseDisplaySettingEnabled(mInjector)) { - addUseDisplayPreferenceNoDisplaysFound(context, screen); + addUseDisplayPreferenceNoDisplaysFound(context, screen, position); } addFooterPreference(context, screen, EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE); } - private static PreferenceCategory getCategoryForDisplay(@NonNull Display display, - @NonNull PrefRefresh screen, @NonNull Context context) { + private static PreferenceCategory reuseDisplayCategory( + PrefRefresh screen, Context context, int position) { // The rest of the settings are in a category with the display name as the title. - String categoryKey = "expanded_display_items_" + display.getDisplayId(); + String categoryKey = PrefBasics.EXTERNAL_DISPLAY_LIST.keyForNth(position); var category = (PreferenceCategory) screen.findUnusedPreference(categoryKey); if (category != null) { @@ -479,45 +431,30 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen } else { category = new PreferenceCategory(context); screen.addPreference(category); - category.setPersistent(false); - category.setKey(categoryKey); - category.setTitle(display.getName()); - category.setOrder(PrefBasics.BUILTIN_DISPLAY_LIST.order + 1); + PrefBasics.EXTERNAL_DISPLAY_LIST.apply(category, position); + category.setOrder(PrefBasics.BUILTIN_DISPLAY_LIST.order + 1 + position); } return category; } - private void showDisplaySettings(@NonNull Display display, @NonNull PrefRefresh screen, - @NonNull Context context) { + private void showDisplaySettings(Display display, PrefRefresh refresh, + Context context, boolean includeV1Helpers, int position) { final var isEnabled = mInjector != null && mInjector.isDisplayEnabled(display); if (isUseDisplaySettingEnabled(mInjector)) { - addUseDisplayPreferenceForDisplay(context, screen, display, isEnabled); + addUseDisplayPreferenceForDisplay(context, refresh, display, isEnabled, position); } if (!isEnabled) { // Skip all other settings return; } final var displayRotation = getDisplayRotation(display.getDisplayId()); - if (!isTopologyPaneEnabled(mInjector)) { - screen.addPreference(updateIllustrationImage(context, displayRotation)); + if (includeV1Helpers) { + addIllustrationImage(context, refresh, displayRotation); } - if (isTopologyPaneEnabled(mInjector)) { - var displayCategory = getCategoryForDisplay(display, screen, context); - try (var categoryRefresh = new PrefRefresh(displayCategory)) { - addDisplaySettings(context, categoryRefresh, display, displayRotation); - } - } else { - addDisplaySettings(context, screen, display, displayRotation); - } - - } - - private void addDisplaySettings(Context context, PrefRefresh refresh, Display display, - int displayRotation) { - addResolutionPreference(context, refresh, display); - addRotationPreference(context, refresh, display, displayRotation); + addResolutionPreference(context, refresh, display, position); + addRotationPreference(context, refresh, display, displayRotation, position); if (isResolutionSettingEnabled(mInjector)) { // Do not show the footer about changing resolution affecting apps. This is not in the // UX design for v2, and there is no good place to put it, since (a) if it is on the @@ -529,13 +466,13 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen // inconsistent with the topology pane, which shows that display. // TODO(b/352648432): probably remove footer once the pane and rest of v2 UI is in // place. - if (!isTopologyPaneEnabled(mInjector)) { + if (includeV1Helpers) { addFooterPreference( context, refresh, EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE); } } if (isDisplaySizeSettingEnabled(mInjector)) { - addSizePreference(context, refresh, display.getDisplayId()); + addSizePreference(context, refresh, display.getDisplayId(), position); } } @@ -555,66 +492,26 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen private void showDisplaysList(@NonNull List displaysToShow, @NonNull PrefRefresh screen, @NonNull Context context) { maybeAddV2Components(context, screen); - int order = PrefBasics.BUILTIN_DISPLAY_LIST.order; + int position = 0; + boolean includeV1Helpers = !isTopologyPaneEnabled(mInjector) && displaysToShow.size() <= 1; for (var display : displaysToShow) { - var pref = getDisplayPreference(context, display, screen, ++order); - pref.setSummary(display.getMode().getPhysicalWidth() + " x " - + display.getMode().getPhysicalHeight()); - } - } - - @VisibleForTesting - static String displayListDisplayCategoryKey(int displayId) { - return "display_list_display_category_" + displayId; - } - - @VisibleForTesting - static String resolutionRotationPreferenceKey(int displayId) { - return "display_id_" + displayId; - } - - private Preference getDisplayPreference(@NonNull Context context, - @NonNull Display display, @NonNull PrefRefresh groupCleanable, int categoryOrder) { - var itemKey = resolutionRotationPreferenceKey(display.getDisplayId()); - var categoryKey = displayListDisplayCategoryKey(display.getDisplayId()); - var category = (PreferenceCategory) groupCleanable.findUnusedPreference(categoryKey); - - if (category != null) { - groupCleanable.addPreference(category); - return category.findPreference(itemKey); - } else { - category = new PreferenceCategory(context); - category.setPersistent(false); - category.setKey(categoryKey); - category.setOrder(categoryOrder); - // Must add the category to the hierarchy before adding its descendants. Otherwise - // the category will not have a preference manager, which causes an exception when a - // child is added to it. - groupCleanable.addPreference(category); - - var prefItem = new DisplayPreference(context, display); - prefItem.setTitle( - context.getString(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.titleResource) + " | " - + context.getString(PrefBasics.EXTERNAL_DISPLAY_ROTATION.titleResource)); - prefItem.setKey(itemKey); - - category.addPreference(prefItem); + var category = reuseDisplayCategory(screen, context, position); category.setTitle(display.getName()); - return prefItem; + try (var refresh = new PrefRefresh(category)) { + // The category may have already been populated if it was retrieved from `screen`, + // but we still need to update resolution and rotation items. + showDisplaySettings(display, refresh, context, includeV1Helpers, position); + } + + position++; } } - private List externalDisplaysToShow(int displayIdToShow) { + private List externalDisplaysToShow() { if (mInjector == null) { return List.of(); } - if (displayIdToShow != INVALID_DISPLAY) { - var display = mInjector.getDisplay(displayIdToShow); - if (display != null && isDisplayAllowed(display, mInjector)) { - return List.of(display); - } - } var displaysToShow = new ArrayList(); for (var display : mInjector.getAllDisplays()) { if (display != null && isDisplayAllowed(display, mInjector)) { @@ -624,16 +521,17 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen return displaysToShow; } - private void addUseDisplayPreferenceNoDisplaysFound(Context context, PrefRefresh refresh) { - final var pref = reuseUseDisplayPreference(context, refresh); + private void addUseDisplayPreferenceNoDisplaysFound(Context context, PrefRefresh refresh, + int position) { + final var pref = reuseUseDisplayPreference(context, refresh, position); pref.setChecked(false); pref.setEnabled(false); pref.setOnPreferenceChangeListener(null); } private void addUseDisplayPreferenceForDisplay(final Context context, - PrefRefresh refresh, final Display display, boolean isEnabled) { - final var pref = reuseUseDisplayPreference(context, refresh); + PrefRefresh refresh, final Display display, boolean isEnabled, int position) { + final var pref = reuseUseDisplayPreference(context, refresh, position); pref.setChecked(isEnabled); pref.setEnabled(true); pref.setOnPreferenceChangeListener((p, newValue) -> { @@ -654,20 +552,19 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen }); } - private Preference updateIllustrationImage(@NonNull final Context context, + private void addIllustrationImage(final Context context, PrefRefresh refresh, final int displayRotation) { - var pref = getIllustrationPreference(context); + var pref = reuseIllustrationPreference(context, refresh); if (displayRotation % 2 == 0) { pref.setLottieAnimationResId(EXTERNAL_DISPLAY_PORTRAIT_DRAWABLE); } else { pref.setLottieAnimationResId(EXTERNAL_DISPLAY_LANDSCAPE_DRAWABLE); } - return pref; } private void addRotationPreference(final Context context, - PrefRefresh refresh, final Display display, final int displayRotation) { - var pref = reuseRotationPreference(context, refresh); + PrefRefresh refresh, final Display display, final int displayRotation, int position) { + var pref = reuseRotationPreference(context, refresh, position); if (mRotationEntries == null || mRotationEntriesValues == null) { mRotationEntries = new String[] { context.getString(R.string.external_display_standard_rotation), @@ -694,8 +591,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen } private void addResolutionPreference(final Context context, PrefRefresh refresh, - final Display display) { - var pref = reuseResolutionPreference(context, refresh); + final Display display, int position) { + var pref = reuseResolutionPreference(context, refresh, position); pref.setSummary(display.getMode().getPhysicalWidth() + " x " + display.getMode().getPhysicalHeight()); pref.setOnPreferenceClickListener((Preference p) -> { @@ -706,8 +603,9 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen pref.setEnabled(isResolutionSettingEnabled(mInjector)); } - private void addSizePreference(final Context context, PrefRefresh refresh, int displayId) { - var pref = reuseSizePreference(context, refresh, displayId); + private void addSizePreference(final Context context, PrefRefresh refresh, int displayId, + int position) { + var pref = reuseSizePreference(context, refresh, displayId, position); pref.setSummary(EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE); pref.setOnPreferenceClickListener( (Preference p) -> { @@ -804,27 +702,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen public void onStopTrackingTouch(@NonNull SeekBar seekBar) {} } - @VisibleForTesting - class DisplayPreference extends TwoTargetPreference - implements Preference.OnPreferenceClickListener { - private final int mDisplayId; - - DisplayPreference(@NonNull final Context context, @NonNull final Display display) { - super(context); - mDisplayId = display.getDisplayId(); - - setPersistent(false); - setOnPreferenceClickListener(this); - } - - @Override - public boolean onPreferenceClick(@NonNull Preference preference) { - launchExternalDisplaySettings(mDisplayId); - writePreferenceClickMetric(preference); - return true; - } - } - private static class PrefRefresh implements AutoCloseable { private final PreferenceGroup mScreen; private final HashMap mUnusedPreferences = new HashMap<>(); diff --git a/src/com/android/settings/core/SliderPreferenceController.java b/src/com/android/settings/core/SliderPreferenceController.java index 9cd4697eae6..79385c1699d 100644 --- a/src/com/android/settings/core/SliderPreferenceController.java +++ b/src/com/android/settings/core/SliderPreferenceController.java @@ -42,6 +42,9 @@ public abstract class SliderPreferenceController extends BasePreferenceControlle } else if (preference instanceof androidx.preference.SeekBarPreference) { ((androidx.preference.SeekBarPreference) preference) .setValue(getSliderPosition()); + } else if (preference instanceof com.android.settingslib.widget.SliderPreference) { + ((com.android.settingslib.widget.SliderPreference) preference) + .setValue(getSliderPosition()); } } diff --git a/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java b/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java new file mode 100644 index 00000000000..3688a05c6b8 --- /dev/null +++ b/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java @@ -0,0 +1,59 @@ +/* + * Copyright 2025 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.display.darkmode; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.widget.TopIntroPreference; + +/** + * Controller of the top info preference in the Dark Mode settings page. + * + * This should be removed after the flag android.view.accessibility.force_invert_color is launched. + */ +public class DarkModeTopIntroPreferenceController extends BasePreferenceController { + @Nullable private TopIntroPreference mPreference; + + public DarkModeTopIntroPreferenceController( + @NonNull Context context, + @NonNull String preferenceKey) { + super(context, preferenceKey); + + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE_UNSEARCHABLE; + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + if (android.view.accessibility.Flags.forceInvertColor()) { + mPreference.setTitle(R.string.dark_ui_text_force_invert); + } else { + mPreference.setTitle(R.string.dark_ui_text); + } + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java index 2edbf99f55a..a248bdff16f 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java @@ -259,7 +259,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mDailyChartIndex, mHourlyChartIndex)); refreshUi(); mHandler.post( - () -> mDailyChartView.announceForAccessibility(getAccessibilityAnnounceMessage())); + () -> mDailyChartView.setAccessibilityPaneTitle(getAccessibilityAnnounceMessage())); if (mOnSelectedIndexUpdatedListener != null) { mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated(); } @@ -299,7 +299,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll refreshUi(); mHandler.post( () -> - mDailyChartView.announceForAccessibility( + mDailyChartView.setAccessibilityPaneTitle( getAccessibilityAnnounceMessage())); mMetricsFeatureProvider.action( mPrefContext, @@ -326,7 +326,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll refreshUi(); mHandler.post( () -> - mHourlyChartView.announceForAccessibility( + mHourlyChartView.setAccessibilityPaneTitle( getAccessibilityAnnounceMessage())); mMetricsFeatureProvider.action( mPrefContext, diff --git a/src/com/android/settings/localepicker/RegionAndNumberingSystemPickerFragment.java b/src/com/android/settings/localepicker/RegionAndNumberingSystemPickerFragment.java index 9831c137915..72a5c311245 100644 --- a/src/com/android/settings/localepicker/RegionAndNumberingSystemPickerFragment.java +++ b/src/com/android/settings/localepicker/RegionAndNumberingSystemPickerFragment.java @@ -34,6 +34,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceScreen; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.app.LocaleHelper; @@ -42,7 +43,6 @@ import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.widget.TopIntroPreference; import com.google.android.material.appbar.AppBarLayout; @@ -75,6 +75,7 @@ public class RegionAndNumberingSystemPickerFragment extends DashboardFragment im private static final String KEY_PREFERENCE_APP_LOCALE_SUGGESTED_LIST = "app_locale_suggested_list"; private static final String KEY_TOP_INTRO_PREFERENCE = "top_intro_region"; + private static final String KEY_PREFERENCE_SCREEN ="key_system_language_picker_page"; private static final String EXTRA_EXPAND_SEARCH_VIEW = "expand_search_view"; @Nullable @@ -121,9 +122,10 @@ public class RegionAndNumberingSystemPickerFragment extends DashboardFragment im } Log.d(TAG, "onCreate, mIsNumberingMode = " + mIsNumberingMode); - if (!mIsNumberingMode) { - mActivity.setTitle(R.string.region_selection_title); - } + + PreferenceScreen screen = findPreference(KEY_PREFERENCE_SCREEN); + screen.setTitle(mIsNumberingMode ? R.string.numbering_system_selection_title + : R.string.region_selection_title); TopIntroPreference topIntroPreference = findPreference(KEY_TOP_INTRO_PREFERENCE); if (topIntroPreference != null && mIsNumberingMode) { diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java index 92c9e2e0405..043a672a08f 100644 --- a/src/com/android/settings/notification/RedactionInterstitial.java +++ b/src/com/android/settings/notification/RedactionInterstitial.java @@ -70,8 +70,7 @@ public class RedactionInterstitial extends SettingsActivity { @Override protected void onCreate(Bundle savedInstance) { - setTheme(SetupWizardUtils.getTheme(this, getIntent())); - ThemeHelper.trySetDynamicColor(this); + ThemeHelper.trySetSuwTheme(this); super.onCreate(savedInstance); findViewById(R.id.content_parent).setFitsSystemWindows(false); } diff --git a/src/com/android/settings/privatespace/OWNERS b/src/com/android/settings/privatespace/OWNERS index 158c26a57fb..a22bb0cc9ab 100644 --- a/src/com/android/settings/privatespace/OWNERS +++ b/src/com/android/settings/privatespace/OWNERS @@ -8,4 +8,3 @@ himanshuz@google.com jigarthakkar@google.com josephpv@google.com onshimiye@google.com -saumyap@google.com diff --git a/src/com/android/settings/spa/preference/ComposePreference.kt b/src/com/android/settings/spa/preference/ComposePreference.kt index 57aa3866390..81d2b4bceb9 100644 --- a/src/com/android/settings/spa/preference/ComposePreference.kt +++ b/src/com/android/settings/spa/preference/ComposePreference.kt @@ -27,20 +27,25 @@ import androidx.preference.PreferenceViewHolder import com.android.settings.R import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.widget.GroupSectionDividerMixin +import com.android.settingslib.widget.NormalPaddingMixin -open class ComposeGroupSectionPreference @JvmOverloads constructor( +open class ComposeGroupSectionPreference +@JvmOverloads +constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0, ) : ComposePreference(context, attrs, defStyleAttr, defStyleRes), GroupSectionDividerMixin -open class ComposePreference @JvmOverloads constructor( +open class ComposePreference +@JvmOverloads +constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0, -) : Preference(context, attrs, defStyleAttr, defStyleRes) { +) : Preference(context, attrs, defStyleAttr, defStyleRes), NormalPaddingMixin { private var content: @Composable () -> Unit = {} fun setContent(content: @Composable () -> Unit) { diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java index 39c77a17924..713dfb2458a 100644 --- a/src/com/android/settings/wifi/WifiConfigController.java +++ b/src/com/android/settings/wifi/WifiConfigController.java @@ -545,13 +545,13 @@ public class WifiConfigController implements TextWatcher, && !isValidSaePassword(mPasswordView.getText().toString())))) { passwordInvalid = true; } - if ((mSsidView != null && mSsidView.length() == 0) - // If Accesspoint is not saved, apply passwordInvalid check - || ((mAccessPoint == null || !mAccessPoint.isSaved()) && passwordInvalid - // If AccessPoint is saved (modifying network) and password is changed, apply - // Invalid password check - || mAccessPoint != null && mAccessPoint.isSaved() && passwordInvalid - && mPasswordView.length() > 0)) { + if ((mAccessPoint == null || !mAccessPoint.isSaved()) && passwordInvalid) { + // If Accesspoint is not saved, apply passwordInvalid check + enabled = false; + } else if (mAccessPoint != null && mAccessPoint.isSaved() && passwordInvalid + && mPasswordView.length() > 0) { + // If AccessPoint is saved (modifying network) and password is changed, apply + // Invalid password check enabled = false; } else { enabled = ipAndProxyFieldsAreValid(); diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java index a1ff1ac9a45..40d22e60fa2 100644 --- a/src/com/android/settings/wifi/WifiDialog.java +++ b/src/com/android/settings/wifi/WifiDialog.java @@ -28,6 +28,8 @@ import android.widget.TextView; import androidx.appcompat.app.AlertDialog; import com.android.settings.R; +import com.android.settings.wifi.utils.SsidInputGroup; +import com.android.settings.wifi.utils.WifiDialogHelper; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.wifi.AccessPoint; @@ -62,6 +64,7 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, private View mView; private WifiConfigController mController; private boolean mHideSubmitButton; + private WifiDialogHelper mDialogHelper; /** * Creates a WifiDialog with no additional style. It displays as a dialog above the current @@ -115,6 +118,9 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, if (mAccessPoint == null) { mController.hideForgetButton(); } + + mDialogHelper = new WifiDialogHelper(this, + new SsidInputGroup(getContext(), mView, R.id.ssid_layout, R.id.ssid)); } @SuppressWarnings("MissingSuperCall") // TODO: Fix me @@ -155,9 +161,6 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, public void onClick(DialogInterface dialogInterface, int id) { if (mListener != null) { switch (id) { - case BUTTON_SUBMIT: - mListener.onSubmit(this); - break; case BUTTON_FORGET: if (WifiUtils.isNetworkLockedDown(getContext(), mAccessPoint.getConfig())) { RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), @@ -170,6 +173,11 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase, } } + /** Return true to tell the parent activity to call onSubmit before onDismiss. */ + public boolean shouldSubmitBeforeFinish() { + return mDialogHelper.isPositive(); + } + @Override public int getMode() { return mMode; diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java index 951277aa9cf..1d431753f32 100644 --- a/src/com/android/settings/wifi/WifiDialogActivity.java +++ b/src/com/android/settings/wifi/WifiDialogActivity.java @@ -346,6 +346,9 @@ public class WifiDialogActivity extends ObservableActivity implements WifiDialog @Override public void onDismiss(DialogInterface dialogInterface) { mDialog2 = null; + if (mDialog != null && mDialog.shouldSubmitBeforeFinish()) { + onSubmit(mDialog); + } mDialog = null; finish(); } diff --git a/src/com/android/settings/wifi/utils/AlertDialogHelper.kt b/src/com/android/settings/wifi/utils/AlertDialogHelper.kt new file mode 100644 index 00000000000..c50323220b7 --- /dev/null +++ b/src/com/android/settings/wifi/utils/AlertDialogHelper.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2025 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.wifi.utils + +import android.content.DialogInterface +import android.util.Log +import androidx.appcompat.app.AlertDialog + +open class AlertDialogHelper(val alertDialog: AlertDialog) { + + var isPositive = false + + init { + alertDialog.setOnShowListener { + alertDialog.getButton(DialogInterface.BUTTON_POSITIVE)?.setOnClickListener { + onPositiveButtonClicked() + } ?: Log.e(TAG, "Can't get the positive button!") + } + } + + open fun onPositiveButtonClicked() { + if (!canDismiss()) { + Log.w(TAG, "Can't dismiss dialog!") + return + } + isPositive = true + alertDialog.dismiss() + } + + open fun canDismiss() = true + + companion object { + const val TAG = "AlertDialogHelper" + } +} diff --git a/src/com/android/settings/wifi/utils/WifiDialogHelper.kt b/src/com/android/settings/wifi/utils/WifiDialogHelper.kt new file mode 100644 index 00000000000..3b23b1a7e50 --- /dev/null +++ b/src/com/android/settings/wifi/utils/WifiDialogHelper.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 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.wifi.utils + +import android.util.Log +import androidx.appcompat.app.AlertDialog + +class WifiDialogHelper( + alertDialog: AlertDialog, + private val ssidInputGroup: SsidInputGroup? = null, +) : AlertDialogHelper(alertDialog) { + + override fun canDismiss(): Boolean { + val isValid = ssidInputGroup?.validate() ?: true + if (!isValid) Log.w(TAG, "SSID is invalid!") + return isValid + } + + companion object { + const val TAG = "WifiDialogHelper" + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java index 4a791e3fd9e..f7da254513b 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java @@ -32,8 +32,8 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Test; @@ -56,7 +56,7 @@ public class AlarmVibrationIntensityPreferenceControllerTest { private Context mContext; private Vibrator mVibrator; private AlarmVibrationIntensityPreferenceController mController; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -69,7 +69,7 @@ public class AlarmVibrationIntensityPreferenceControllerTest { mController = new AlarmVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); mLifecycle.addObserver(mController); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); @@ -91,7 +91,7 @@ public class AlarmVibrationIntensityPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo( + assertThat(mPreference.getValue()).isEqualTo( mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_ALARM)); } @@ -101,17 +101,17 @@ public class AlarmVibrationIntensityPreferenceControllerTest { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); } @@ -119,25 +119,25 @@ public class AlarmVibrationIntensityPreferenceControllerTest { public void updateState_shouldDisplayIntensityInSliderPosition() { updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_updatesIntensitySetting() throws Exception { + public void setSliderPosition_updatesIntensitySetting() throws Exception { mController.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(readSetting(Settings.System.ALARM_VIBRATION_INTENSITY)) .isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java index e4faaaad0cc..be34b0d5461 100644 --- a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java @@ -32,8 +32,8 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Test; @@ -58,7 +58,7 @@ public class HapticFeedbackIntensityPreferenceControllerTest { private Context mContext; private Vibrator mVibrator; private HapticFeedbackIntensityPreferenceController mController; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -71,7 +71,7 @@ public class HapticFeedbackIntensityPreferenceControllerTest { mController = new HapticFeedbackIntensityPreferenceController(mContext, PREFERENCE_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); mLifecycle.addObserver(mController); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); @@ -91,7 +91,7 @@ public class HapticFeedbackIntensityPreferenceControllerTest { Settings.System.putString(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_INTENSITY, /* value= */ null); mController.updateState(mPreference); - assertThat(mPreference.getProgress()) + assertThat(mPreference.getValue()) .isEqualTo(mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_TOUCH)); } @@ -101,17 +101,17 @@ public class HapticFeedbackIntensityPreferenceControllerTest { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); } @@ -121,44 +121,44 @@ public class HapticFeedbackIntensityPreferenceControllerTest { updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test public void updateState_shouldDisplayIntensityInSliderPosition() { updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_updatesIntensityAndDependentSettings() throws Exception { + public void setSliderPosition_updatesIntensityAndDependentSettings() throws Exception { mController.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(readSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY)) .isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingFragmentTest.java index db82be6db3a..37076abd799 100644 --- a/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingFragmentTest.java @@ -156,9 +156,7 @@ public class HearingDevicePairingFragmentTest { @Test public void handleLeScanResult_markDeviceAsHearingAid() { - ScanResult scanResult = mock(ScanResult.class); - doReturn(mDevice).when(scanResult).getDevice(); - doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice); + ScanResult scanResult = createMockScanResult(); mFragment.handleLeScanResult(scanResult); @@ -167,9 +165,7 @@ public class HearingDevicePairingFragmentTest { @Test public void handleLeScanResult_isAndroidCompatible_addDevice() { - ScanResult scanResult = mock(ScanResult.class); - doReturn(mDevice).when(scanResult).getDevice(); - doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice); + ScanResult scanResult = createMockScanResult(); doReturn(true).when(mFragment).isAndroidCompatibleHearingAid(scanResult); mFragment.handleLeScanResult(scanResult); @@ -179,9 +175,7 @@ public class HearingDevicePairingFragmentTest { @Test public void handleLeScanResult_isNotAndroidCompatible_discoverServices() { - ScanResult scanResult = mock(ScanResult.class); - doReturn(mDevice).when(scanResult).getDevice(); - doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice); + ScanResult scanResult = createMockScanResult(); doReturn(false).when(mFragment).isAndroidCompatibleHearingAid(scanResult); mFragment.handleLeScanResult(scanResult); @@ -191,9 +185,7 @@ public class HearingDevicePairingFragmentTest { @Test public void handleLeScanResult_alreadyBonded_doNothing() { - ScanResult scanResult = mock(ScanResult.class); - doReturn(mDevice).when(scanResult).getDevice(); - doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice); + ScanResult scanResult = createMockScanResult(); doReturn(BluetoothDevice.BOND_BONDED).when(mCachedDevice).getBondState(); mFragment.handleLeScanResult(scanResult); @@ -292,6 +284,14 @@ public class HearingDevicePairingFragmentTest { assertThat(isCompatible).isFalse(); } + private ScanResult createMockScanResult() { + ScanResult scanResult = mock(ScanResult.class); + doReturn(mDevice).when(scanResult).getDevice(); + doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice); + doReturn(true).when(mFragment).isDeviceDiscoverable(scanResult); + return scanResult; + } + private ScanResult createAshaScanResult() { ScanResult scanResult = mock(ScanResult.class); ScanRecord scanRecord = mock(ScanRecord.class); diff --git a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java index da8059c25ec..2a4834c9bf1 100644 --- a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java @@ -34,8 +34,8 @@ import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.After; import org.junit.Before; @@ -60,7 +60,7 @@ public class MediaVibrationIntensityPreferenceControllerTest { private Context mContext; private Vibrator mVibrator; private MediaVibrationIntensityPreferenceController mController; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -73,7 +73,7 @@ public class MediaVibrationIntensityPreferenceControllerTest { mController = new MediaVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); mLifecycle.addObserver(mController); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); @@ -100,7 +100,7 @@ public class MediaVibrationIntensityPreferenceControllerTest { mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo( + assertThat(mPreference.getValue()).isEqualTo( mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_MEDIA)); } @@ -110,17 +110,17 @@ public class MediaVibrationIntensityPreferenceControllerTest { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); } @@ -128,25 +128,25 @@ public class MediaVibrationIntensityPreferenceControllerTest { public void updateState_shouldDisplayIntensityInSliderPosition() { updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_updatesIntensitySetting() throws Exception { + public void setSliderPosition_updatesIntensitySetting() throws Exception { mController.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(readSetting(Settings.System.MEDIA_VIBRATION_INTENSITY)) .isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceControllerTest.java index a9bd2d06bad..f372bb8c34b 100644 --- a/tests/robotests/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/NotificationVibrationIntensityPreferenceControllerTest.java @@ -30,10 +30,11 @@ import android.provider.Settings; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Test; @@ -56,7 +57,7 @@ public class NotificationVibrationIntensityPreferenceControllerTest { private Context mContext; private Vibrator mVibrator; private NotificationVibrationIntensityPreferenceController mController; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -69,7 +70,7 @@ public class NotificationVibrationIntensityPreferenceControllerTest { mController = new NotificationVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); mLifecycle.addObserver(mController); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); @@ -89,7 +90,7 @@ public class NotificationVibrationIntensityPreferenceControllerTest { Settings.System.putString(mContext.getContentResolver(), Settings.System.NOTIFICATION_VIBRATION_INTENSITY, /* value= */ null); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo( + assertThat(mPreference.getValue()).isEqualTo( mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_NOTIFICATION)); } @@ -101,22 +102,21 @@ public class NotificationVibrationIntensityPreferenceControllerTest { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.getSummary()).isNull(); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); - // TODO(b/136805769): summary is broken in SeekBarPreference, enable this once fixed -// assertThat(mPreference.getSummary()).isNotNull(); -// assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString( -// R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary)); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getSummary()).isNotNull(); + assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString( + R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary)); assertThat(mPreference.isEnabled()).isFalse(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.getSummary()).isNull(); assertThat(mPreference.isEnabled()).isTrue(); } @@ -126,27 +126,27 @@ public class NotificationVibrationIntensityPreferenceControllerTest { updateSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_updatesIntensitySetting() throws Exception { + public void setSliderPosition_updatesIntensitySetting() throws Exception { mController.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(readSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY)) .isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceControllerTest.java index 67f643ac30c..ac218ffc891 100644 --- a/tests/robotests/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/RingVibrationIntensityPreferenceControllerTest.java @@ -30,10 +30,11 @@ import android.provider.Settings; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Test; @@ -59,7 +60,7 @@ public class RingVibrationIntensityPreferenceControllerTest { private Context mContext; private Vibrator mVibrator; private RingVibrationIntensityPreferenceController mController; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -72,7 +73,7 @@ public class RingVibrationIntensityPreferenceControllerTest { mController = new RingVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); mLifecycle.addObserver(mController); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mController.displayPreference(mScreen); @@ -92,7 +93,7 @@ public class RingVibrationIntensityPreferenceControllerTest { Settings.System.putString(mContext.getContentResolver(), Settings.System.RING_VIBRATION_INTENSITY, /* value= */ null); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo( + assertThat(mPreference.getValue()).isEqualTo( mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_RINGTONE)); } @@ -102,22 +103,21 @@ public class RingVibrationIntensityPreferenceControllerTest { when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.getSummary()).isNull(); assertThat(mPreference.isEnabled()).isTrue(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); - // TODO(b/136805769): summary is broken in SeekBarPreference, enable this once fixed -// assertThat(mPreference.getSummary()).isNotNull(); -// assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString( -// R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary)); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getSummary()).isNotNull(); + assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString( + R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary)); assertThat(mPreference.isEnabled()).isFalse(); when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.getSummary()).isNull(); assertThat(mPreference.isEnabled()).isTrue(); } @@ -129,44 +129,44 @@ public class RingVibrationIntensityPreferenceControllerTest { updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test public void updateState_shouldDisplayIntensityInSliderPosition() { updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(Settings.System.RING_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF); mController.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_updatesIntensityAndDependentSettings() throws Exception { + public void setSliderPosition_updatesIntensityAndDependentSettings() throws Exception { mController.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(readSetting(Settings.System.RING_VIBRATION_INTENSITY)) .isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityPreferenceControllerTest.java index 2508345b552..6716e361d16 100644 --- a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityPreferenceControllerTest.java @@ -29,8 +29,8 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Test; @@ -70,7 +70,7 @@ public class VibrationIntensityPreferenceControllerTest { private Lifecycle mLifecycle; private Context mContext; private Vibrator mVibrator; - private SeekBarPreference mPreference; + private SliderPreference mPreference; @Before public void setUp() { @@ -85,7 +85,7 @@ public class VibrationIntensityPreferenceControllerTest { VibrationIntensityPreferenceController controller = createPreferenceController(3); Settings.System.putString(mContext.getContentResolver(), SETTING_KEY, /* value= */ null); controller.updateState(mPreference); - assertThat(mPreference.getProgress()) + assertThat(mPreference.getValue()) .isEqualTo(mVibrator.getDefaultVibrationIntensity(VIBRATION_USAGE)); } @@ -96,17 +96,17 @@ public class VibrationIntensityPreferenceControllerTest { updateSetting(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY, ON); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); updateSetting(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY, OFF); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(mPreference.isEnabled()).isFalse(); updateSetting(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY, ON); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); assertThat(mPreference.isEnabled()).isTrue(); } @@ -116,19 +116,19 @@ public class VibrationIntensityPreferenceControllerTest { updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_HIGH); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_MEDIUM); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_LOW); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_OFF); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test @@ -137,19 +137,19 @@ public class VibrationIntensityPreferenceControllerTest { updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_MEDIUM); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_MEDIUM); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_LOW); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_OFF); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test @@ -158,39 +158,39 @@ public class VibrationIntensityPreferenceControllerTest { updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_HIGH); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_MEDIUM); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_LOW); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_OFF); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_mainSwitchDisabled_ignoresUpdates() throws Exception { + public void setSliderPosition_mainSwitchDisabled_ignoresUpdates() throws Exception { VibrationIntensityPreferenceController controller = createPreferenceController(3); updateSetting(SETTING_KEY, Vibrator.VIBRATION_INTENSITY_LOW); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); updateSetting(VibrationPreferenceConfig.MAIN_SWITCH_SETTING_KEY, OFF); controller.updateState(mPreference); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); assertThat(mPreference.isEnabled()).isFalse(); assertThat(controller.setSliderPosition(Vibrator.VIBRATION_INTENSITY_HIGH)).isFalse(); assertThat(readSetting(SETTING_KEY)).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW); - assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); + assertThat(mPreference.getValue()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF); } @Test - public void setProgress_allSupportedPositions_updatesIntensitySetting() throws Exception { + public void setSliderPosition_allSupportedPositions_updatesIntensitySetting() throws Exception { VibrationIntensityPreferenceController controller = createPreferenceController(3); controller.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); @@ -207,7 +207,8 @@ public class VibrationIntensityPreferenceControllerTest { } @Test - public void setProgress_twoSupportedPositions_updatesMediumPositionToHigh() throws Exception { + public void setSliderPosition_twoSupportedPositions_updatesMediumPositionToHigh() + throws Exception { VibrationIntensityPreferenceController controller = createPreferenceController(2); controller.setSliderPosition(Vibrator.VIBRATION_INTENSITY_OFF); @@ -224,7 +225,7 @@ public class VibrationIntensityPreferenceControllerTest { } @Test - public void setProgress_oneSupportedPosition_updatesOnPositionsToDeviceDefault() + public void setSliderPosition_oneSupportedPosition_updatesOnPositionsToDeviceDefault() throws Exception { int defaultIntensity = mVibrator.getDefaultVibrationIntensity(VIBRATION_USAGE); VibrationIntensityPreferenceController controller = createPreferenceController(1); @@ -255,7 +256,7 @@ public class VibrationIntensityPreferenceControllerTest { VibrationIntensityPreferenceController controller = new TestPreferenceController(mContext, supportedIntensityLevels); mLifecycle.addObserver(controller); - mPreference = new SeekBarPreference(mContext); + mPreference = new SliderPreference(mContext); mPreference.setSummary("Test summary"); when(mScreen.findPreference(controller.getPreferenceKey())).thenReturn(mPreference); controller.displayPreference(mScreen); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java index d754993d998..327e2cae5a2 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java @@ -35,7 +35,6 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.input.InputManager; -import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.util.FeatureFlagUtils; import android.view.InputDevice; @@ -54,7 +53,6 @@ import com.android.settings.connecteddevice.stylus.StylusDeviceUpdater; import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.flags.FakeFeatureFlagsImpl; -import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -213,6 +211,7 @@ public class ConnectedDeviceGroupControllerTest { mConnectedDeviceGroupController.onStart(); verify(mExternalDisplayUpdater).registerCallback(); + verify(mExternalDisplayUpdater).refreshPreference(); verify(mConnectedBluetoothDeviceUpdater).registerCallback(); verify(mConnectedUsbDeviceUpdater).registerCallback(); verify(mConnectedDockUpdater).registerCallback(); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivityTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivityTest.java new file mode 100644 index 00000000000..db43e460bb1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerActivityTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothStatusCodes; +import android.os.Bundle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settingslib.flags.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class AudioSharingJoinHandlerActivityTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + private AudioSharingJoinHandlerActivity mActivity; + + @Before + public void setUp() { + mActivity = spy(Robolectric.buildActivity(AudioSharingJoinHandlerActivity.class).get()); + mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + mShadowBluetoothAdapter.setEnabled(true); + mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( + BluetoothStatusCodes.FEATURE_SUPPORTED); + mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( + BluetoothStatusCodes.FEATURE_SUPPORTED); + } + + @Test + @DisableFlags(Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE) + public void onCreate_flagOff_finish() { + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + mActivity.onCreate(new Bundle()); + verify(mActivity).finish(); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void onCreate_flagOn_create() { + mActivity.onCreate(new Bundle()); + verify(mActivity, never()).finish(); + } + + @Test + public void isValidFragment_returnsTrue() { + assertThat(mActivity.isValidFragment( + AudioSharingJoinHandlerDashboardFragment.class.getName())).isTrue(); + } + + @Test + public void isValidFragment_returnsFalse() { + assertThat(mActivity.isValidFragment("")).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerControllerTest.java new file mode 100644 index 00000000000..7b8ab6d7b9b --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerControllerTest.java @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; +import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE; + +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.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothLeBroadcastAssistant; +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothStatusCodes; +import android.content.Context; +import android.content.Intent; +import android.os.Looper; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.bluetooth.Utils; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; +import com.android.settings.testutils.shadow.ShadowFragment; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.BluetoothEventManager; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.LeAudioProfile; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.flags.Flags; + +import com.google.common.collect.ImmutableList; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +import java.util.concurrent.Executor; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowBluetoothAdapter.class, + ShadowBluetoothUtils.class, + ShadowFragment.class, +}) +public class AudioSharingJoinHandlerControllerTest { + private static final String PREF_KEY = "audio_sharing_join_handler"; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Spy + Context mContext = ApplicationProvider.getApplicationContext(); + private Lifecycle mLifecycle; + private LifecycleOwner mLifecycleOwner; + @Mock + private LocalBluetoothManager mLocalBtManager; + @Mock private BluetoothEventManager mEventManager; + @Mock private LocalBluetoothProfileManager mProfileManager; + @Mock private CachedBluetoothDeviceManager mDeviceManager; + @Mock private LocalBluetoothLeBroadcastAssistant mAssistant; + @Mock private PreferenceScreen mScreen; + @Mock private DashboardFragment mFragment; + @Mock private FragmentActivity mActivity; + @Mock private AudioSharingDialogHandler mDialogHandler; + private AudioSharingJoinHandlerController mController; + + @Before + public void setUp() { + ShadowBluetoothAdapter shadowBluetoothAdapter = + Shadow.extract(BluetoothAdapter.getDefaultAdapter()); + shadowBluetoothAdapter.setEnabled(true); + shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( + BluetoothStatusCodes.FEATURE_SUPPORTED); + shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( + BluetoothStatusCodes.FEATURE_SUPPORTED); + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager; + mLocalBtManager = Utils.getLocalBtManager(mContext); + when(mLocalBtManager.getEventManager()).thenReturn(mEventManager); + when(mLocalBtManager.getProfileManager()).thenReturn(mProfileManager); + when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mDeviceManager); + when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant); + mController = new AudioSharingJoinHandlerController(mContext, PREF_KEY); + doReturn(mActivity).when(mFragment).getActivity(); + mController.init(mFragment); + mController.setDialogHandler(mDialogHandler); + } + + @After + public void tearDown() { + ShadowBluetoothUtils.reset(); + } + + @Test + @DisableFlags(Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE) + public void onStart_flagOff_doNothing() { + mController.onStart(mLifecycleOwner); + verify(mEventManager, never()).registerCallback(any(BluetoothCallback.class)); + verify(mDialogHandler, never()).registerCallbacks(any(Executor.class)); + verify(mAssistant, never()) + .registerServiceCallBack( + any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void onStart_flagOn_registerCallbacks() { + mController.onStart(mLifecycleOwner); + verify(mEventManager).registerCallback(any(BluetoothCallback.class)); + verify(mDialogHandler).registerCallbacks(any(Executor.class)); + verify(mAssistant) + .registerServiceCallBack( + any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class)); + } + + @Test + @DisableFlags(Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE) + public void onStop_flagOff_doNothing() { + mController.onStop(mLifecycleOwner); + verify(mEventManager, never()).unregisterCallback(any(BluetoothCallback.class)); + verify(mDialogHandler, never()).unregisterCallbacks(); + verify(mAssistant, never()) + .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void onStop_flagOn_unregisterCallbacks() { + mController.onStop(mLifecycleOwner); + verify(mEventManager).unregisterCallback(any(BluetoothCallback.class)); + verify(mDialogHandler).unregisterCallbacks(); + verify(mAssistant) + .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class)); + } + + @Test + @EnableFlags({Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE, + Flags.FLAG_ENABLE_LE_AUDIO_SHARING}) + public void getAvailabilityStatus_flagOn() { + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + } + + @Test + @DisableFlags(Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE) + public void getAvailabilityStatus_flagOff() { + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getPreferenceKey_returnsCorrectKey() { + assertThat(mController.getPreferenceKey()).isEqualTo(PREF_KEY); + } + + @Test + public void getSliceHighlightMenuRes_returnsZero() { + assertThat(mController.getSliceHighlightMenuRes()).isEqualTo(0); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void displayPreference_flagOn_updateDeviceList() { + mController.displayPreference(mScreen); + + } + + @Test + public void onProfileConnectionStateChanged_notDisconnectedProfile_doNothing() { + CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + + mController.onProfileConnectionStateChanged( + cachedDevice, BluetoothAdapter.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + verifyNoInteractions(mDialogHandler); + } + + @Test + public void onProfileConnectionStateChanged_leaDeviceDisconnected_closeOpeningDialogsForIt() { + // Test when LEA device LE_AUDIO_BROADCAST_ASSISTANT disconnected. + BluetoothDevice device = mock(BluetoothDevice.class); + CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + LeAudioProfile profile = mock(LeAudioProfile.class); + when(profile.isEnabled(device)).thenReturn(true); + when(cachedDevice.getProfiles()).thenReturn(ImmutableList.of(profile)); + when(cachedDevice.isConnected()).thenReturn(true); + when(cachedDevice.getDevice()).thenReturn(device); + + mController.onProfileConnectionStateChanged( + cachedDevice, + BluetoothAdapter.STATE_DISCONNECTED, + BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + verify(mDialogHandler).closeOpeningDialogsForLeaDevice(cachedDevice); + } + + @Test + public void + onProfileConnectionStateChanged_classicDeviceDisconnected_closeOpeningDialogsForIt() { + // Test when classic device totally disconnected + BluetoothDevice device = mock(BluetoothDevice.class); + CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + LeAudioProfile profile = mock(LeAudioProfile.class); + when(profile.isEnabled(device)).thenReturn(false); + when(cachedDevice.getProfiles()).thenReturn(ImmutableList.of(profile)); + when(cachedDevice.isConnected()).thenReturn(false); + when(cachedDevice.getDevice()).thenReturn(device); + + mController.onProfileConnectionStateChanged( + cachedDevice, BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.A2DP); + verify(mDialogHandler).closeOpeningDialogsForNonLeaDevice(cachedDevice); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void handleDeviceConnectedFromIntent_noDevice_doNothing() { + Intent intent = new Intent(); + doReturn(intent).when(mActivity).getIntent(); + mController.displayPreference(mScreen); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDeviceManager, never()).findDevice(any(BluetoothDevice.class)); + verify(mDialogHandler, never()) + .handleDeviceConnected(any(CachedBluetoothDevice.class), anyBoolean()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, + Flags.FLAG_PROMOTE_AUDIO_SHARING_FOR_SECOND_AUTO_CONNECTED_LEA_DEVICE}) + public void handleDeviceClickFromIntent_handle() { + CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + BluetoothDevice device = mock(BluetoothDevice.class); + when(mDeviceManager.findDevice(device)).thenReturn(cachedDevice); + Intent intent = new Intent(); + intent.putExtra(EXTRA_BLUETOOTH_DEVICE, device); + doReturn(intent).when(mActivity).getIntent(); + mController.displayPreference(mScreen); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDialogHandler).handleDeviceConnected(cachedDevice, /* userTriggered = */ false); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_closeOpeningDialogsForSourceAdded() { + CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + BluetoothDevice device = mock(BluetoothDevice.class); + when(mDeviceManager.findDevice(device)).thenReturn(cachedDevice); + // onSourceAdded will dismiss stale dialogs + mController.mAssistantCallback.onSourceAdded(device, /* sourceId= */ + 1, /* reason= */ 1); + + verify(mDialogHandler).closeOpeningDialogsForLeaDevice(cachedDevice); + } + + @Test + public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() { + BluetoothDevice device = mock(BluetoothDevice.class); + mController.mAssistantCallback.onSearchStarted(/* reason= */ 1); + mController.mAssistantCallback.onSearchStartFailed(/* reason= */ 1); + mController.mAssistantCallback.onSearchStopped(/* reason= */ 1); + mController.mAssistantCallback.onSearchStopFailed(/* reason= */ 1); + BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class); + mController.mAssistantCallback.onReceiveStateChanged(device, /* sourceId= */ 1, state); + mController.mAssistantCallback.onSourceModified(device, /* sourceId= */ 1, /* reason= */ 1); + mController.mAssistantCallback.onSourceModifyFailed(device, /* sourceId= */ 1, /* reason= */ + 1); + BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class); + mController.mAssistantCallback.onSourceFound(metadata); + mController.mAssistantCallback.onSourceLost(/* broadcastId= */ 1); + shadowOf(Looper.getMainLooper()).idle(); + + // Above callbacks won't dismiss stale dialogs + verifyNoInteractions(mDialogHandler); + } +} diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragmentTest.java new file mode 100644 index 00000000000..3fd27b10b11 --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinHandlerDashboardFragmentTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2025 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.connecteddevice.audiosharing; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class AudioSharingJoinHandlerDashboardFragmentTest { + private AudioSharingJoinHandlerDashboardFragment mFragment; + + @Before + public void setUp() { + mFragment = new AudioSharingJoinHandlerDashboardFragment(); + } + + @Test + public void getPreferenceScreenResId_returnsCorrectXml() { + assertThat(mFragment.getPreferenceScreenResId()) + .isEqualTo(R.xml.bluetooth_le_audio_sharing_join_handler); + } + + @Test + public void getLogTag_returnsCorrectTag() { + assertThat(mFragment.getLogTag()).isEqualTo("AudioSharingJoinHandlerFrag"); + } + + @Test + public void getMetricsCategory_returnsCorrectCategory() { + assertThat(mFragment.getMetricsCategory()).isEqualTo(0); + } +} diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java new file mode 100644 index 00000000000..f5f25d89f82 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2025 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.display.darkmode; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.accessibility.Flags; + +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settingslib.widget.TopIntroPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** + * Tests for {@link DarkModeTopIntroPreferenceController}. + */ +@RunWith(RobolectricTestRunner.class) +public class DarkModeTopIntroPreferenceControllerTest { + @Rule + public final MockitoRule mocks = MockitoJUnit.rule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private static final String PREFERENCE_KEY = "preference_key"; + + @Mock + private PreferenceScreen mScreen; + @Mock + private TopIntroPreference mPreference; + private DarkModeTopIntroPreferenceController mController; + private final Context mContext = ApplicationProvider.getApplicationContext(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = new DarkModeTopIntroPreferenceController(mContext, PREFERENCE_KEY); + when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference); + } + + @Test + @EnableFlags(Flags.FLAG_FORCE_INVERT_COLOR) + public void enableForceInvert_newPreferenceTitle() { + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(eq(R.string.dark_ui_text_force_invert)); + } + + @Test + @DisableFlags(Flags.FLAG_FORCE_INVERT_COLOR) + public void disableForceInvert_originalPreferenceTitle() { + mController.displayPreference(mScreen); + + verify(mPreference).setTitle(eq(R.string.dark_ui_text)); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java index d80464d5467..d5d395e4452 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java @@ -145,14 +145,6 @@ public class WifiConfigControllerTest { .isEqualTo(View.GONE); } - @Test - public void isSubmittable_noSSID_shouldReturnFalse() { - final TextView ssid = mView.findViewById(R.id.ssid); - assertThat(ssid).isNotNull(); - ssid.setText(""); - assertThat(mController.isSubmittable()).isFalse(); - } - @Test public void isSubmittable_longPsk_shouldReturnFalse() { final TextView password = mView.findViewById(R.id.password); diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java index d1cbd0ee1b7..159d97acd15 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java @@ -349,4 +349,14 @@ public class WifiDialogActivityTest { verify(mActivity).dismissDialog(); } + + @Test + public void onDismiss_shouldSubmitBeforeFinish_callOnSubmit() { + mActivity.mDialog = mWifiDialog; + when(mWifiDialog.shouldSubmitBeforeFinish()).thenReturn(true); + + mActivity.onDismiss(mWifiDialog); + + verify(mActivity).onSubmit(mWifiDialog); + } } diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java index c6bdebdcc14..c9cf5a2a852 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java @@ -56,7 +56,6 @@ import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiEntry.ConnectedState; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -73,7 +72,6 @@ import org.robolectric.shadows.ShadowBinder; import java.util.ArrayList; import java.util.List; -@Ignore("b/394813533") @Deprecated(forRemoval = true) @RunWith(RobolectricTestRunner.class) @Config(shadows = { diff --git a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java index a87e66b1b96..0b118a78358 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java +++ b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java @@ -21,9 +21,6 @@ import static com.android.settings.connecteddevice.display.ExternalDisplayPrefer import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SETTINGS_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE; -import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.PREVIOUSLY_SHOWN_LIST_KEY; -import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.displayListDisplayCategoryKey; -import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.resolutionRotationPreferenceKey; import static com.android.settings.flags.Flags.FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING; import static com.android.settings.flags.Flags.FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST; @@ -53,7 +50,6 @@ import androidx.preference.PreferenceScreen; import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.DisplayPreference; import com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.PrefBasics; import com.android.settingslib.widget.MainSwitchPreference; @@ -67,7 +63,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @Nullable private ExternalDisplayPreferenceFragment mFragment; private int mPreferenceIdFromResource; - private int mDisplayIdArg = INVALID_DISPLAY; private boolean mLaunchedBuiltinSettings; private int mResolutionSelectorDisplayId = INVALID_DISPLAY; @Mock @@ -80,17 +75,20 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa assertThat(mPreferenceIdFromResource).isEqualTo(EXTERNAL_DISPLAY_SETTINGS_RESOURCE); } - private void assertDisplayList(boolean present, int displayId) { - // In display list fragment, there is a combined resolution/rotation preference key. - var category = mPreferenceScreen.findPreference(displayListDisplayCategoryKey(displayId)); - var pref = mPreferenceScreen.findPreference(resolutionRotationPreferenceKey(displayId)); - if (present) { - assertThat(category).isNotNull(); - assertThat(pref).isNotNull(); - } else { - assertThat(category).isNull(); - assertThat(pref).isNull(); + private PreferenceCategory getExternalDisplayCategory(int positionIndex) { + return mPreferenceScreen.findPreference( + PrefBasics.EXTERNAL_DISPLAY_LIST.keyForNth(positionIndex)); + } + + private void assertDisplayListCount(int expectedCount) { + int actualCount = 0; + for (int i = 0; i < mPreferenceScreen.getPreferenceCount(); i++) { + Preference child = mPreferenceScreen.getPreference(i); + if (child.getKey().startsWith(PrefBasics.EXTERNAL_DISPLAY_LIST.key)) { + actualCount++; + } } + assertThat(actualCount).isEqualTo(expectedCount); } @Test @@ -100,27 +98,15 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa var fragment = initFragment(); var outState = new Bundle(); - fragment.onSaveInstanceStateCallback(outState); - assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isFalse(); assertThat(mHandler.getPendingMessages().size()).isEqualTo(1); - // Combined resolution/refresh rate are not available in displays list because the pane is - // disabled (v1 UI). - assertDisplayList(false, EXTERNAL_DISPLAY_ID); - assertDisplayList(false, OVERLAY_DISPLAY_ID); - // Individual resolution preference is not available in displays list. - assertThat(mPreferenceScreen.findPreference( - PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key)) - .isNull(); + assertDisplayListCount(0); verify(mMockedInjector, never()).getAllDisplays(); mHandler.flush(); assertThat(mHandler.getPendingMessages().size()).isEqualTo(0); verify(mMockedInjector).getAllDisplays(); - assertDisplayList(true, EXTERNAL_DISPLAY_ID); - assertDisplayList(true, OVERLAY_DISPLAY_ID); - fragment.onSaveInstanceStateCallback(outState); - assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isTrue(); + assertDisplayListCount(2); Preference pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key); assertThat(pref).isNull(); @@ -143,7 +129,8 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key); assertThat(pref).isNotNull(); - assertDisplayList(false, mDisplays[1].getDisplayId()); + assertDisplayListCount(1); + assertThat("" + getExternalDisplayCategory(0).getTitle()).isEqualTo("HDMI"); PreferenceCategory listPref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key); @@ -168,8 +155,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key); assertThat(pref).isNull(); - assertDisplayList(false, EXTERNAL_DISPLAY_ID); - assertDisplayList(false, OVERLAY_DISPLAY_ID); + assertDisplayListCount(0); var listPref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key); assertThat(listPref).isNull(); @@ -179,46 +165,36 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @UiThreadTest public void testLaunchDisplaySettingFromList() { initFragment(); + doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); mHandler.flush(); - assertDisplayList(true, EXTERNAL_DISPLAY_ID); - assertDisplayList(true, OVERLAY_DISPLAY_ID); - PreferenceCategory display1Category = mPreferenceScreen.findPreference( - displayListDisplayCategoryKey(EXTERNAL_DISPLAY_ID)); - var display1Pref = (DisplayPreference) display1Category.getPreference(0); - PreferenceCategory display2Category = mPreferenceScreen.findPreference( - displayListDisplayCategoryKey(OVERLAY_DISPLAY_ID)); - var display2Pref = (DisplayPreference) display2Category.getPreference(0); - assertThat(display1Pref.getKey()).isEqualTo( - resolutionRotationPreferenceKey(EXTERNAL_DISPLAY_ID)); + assertDisplayListCount(2); + var display1Category = getExternalDisplayCategory(0); + var display2Category = getExternalDisplayCategory(1); assertThat("" + display1Category.getTitle()).isEqualTo("HDMI"); - assertThat("" + display1Pref.getSummary()).isEqualTo("1920 x 1080"); - display1Pref.onPreferenceClick(display1Pref); - assertThat(mDisplayIdArg).isEqualTo(1); - verify(mMockedMetricsLogger).writePreferenceClickMetric(display1Pref); - assertThat(display2Pref.getKey()).isEqualTo( - resolutionRotationPreferenceKey(OVERLAY_DISPLAY_ID)); + var display1Resolution = display1Category.findPreference( + PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); + display1Resolution.performClick(); + assertThat(mResolutionSelectorDisplayId).isEqualTo(1); + verify(mMockedMetricsLogger).writePreferenceClickMetric(display1Resolution); + var display2Resolution = display2Category.findPreference( + PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(1)); assertThat("" + display2Category.getTitle()).isEqualTo("Overlay #1"); - assertThat("" + display2Pref.getSummary()).isEqualTo("1240 x 780"); - display2Pref.onPreferenceClick(display2Pref); - assertThat(mDisplayIdArg).isEqualTo(2); - verify(mMockedMetricsLogger).writePreferenceClickMetric(display2Pref); + assertThat("" + display2Resolution.getSummary()).isEqualTo("1240 x 780"); + display2Resolution.performClick(); + assertThat(mResolutionSelectorDisplayId).isEqualTo(2); + verify(mMockedMetricsLogger).writePreferenceClickMetric(display2Resolution); } @Test @UiThreadTest public void testShowDisplayListForOnlyOneDisplay_PreviouslyShownList() { var fragment = initFragment(); - // Previously shown list of displays - fragment.onActivityCreatedCallback(createBundleForPreviouslyShownList()); // Only one display available doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); mHandler.flush(); int attachedId = mDisplays[1].getDisplayId(); - assertDisplayList(true, attachedId); - assertThat(mPreferenceScreen.findPreference( - resolutionRotationPreferenceKey(attachedId))) - .isNotNull(); - assertDisplayList(false, mDisplays[2].getDisplayId()); + assertDisplayListCount(1); + assertThat("" + getExternalDisplayCategory(0).getTitle()).isEqualTo("HDMI"); } @Test @@ -231,14 +207,15 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa // Init initFragment(); mHandler.flush(); - assertDisplayList(false, mDisplays[1].getDisplayId()); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); + assertDisplayListCount(1); + var category = getExternalDisplayCategory(0); + var pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); assertThat(pref).isNotNull(); - pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); + pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.keyForNth(0)); assertThat(pref).isNotNull(); - var footerPref = mPreferenceScreen.findPreference(PrefBasics.FOOTER.key); + var footerPref = category.findPreference(PrefBasics.FOOTER.key); assertThat(footerPref).isNotNull(); - var sizePref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + var sizePref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(0)); assertThat(sizePref).isNull(); assertThat("" + footerPref.getTitle()) .isEqualTo(getText(EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE)); @@ -253,15 +230,12 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa // Init initFragment(); mHandler.flush(); - assertDisplayList(false, mDisplays[1].getDisplayId()); - assertDisplayList(false, mDisplays[2].getDisplayId()); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); - assertThat(pref).isNotNull(); - pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); - assertThat(pref).isNotNull(); - var footerPref = mPreferenceScreen.findPreference(PrefBasics.FOOTER.key); + assertDisplayListCount(1); + var category = getExternalDisplayCategory(0); + assertThat("" + category.getTitle()).isEqualTo("HDMI"); + var footerPref = category.findPreference(PrefBasics.FOOTER.key); assertThat(footerPref).isNotNull(); - var sizePref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + var sizePref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(0)); assertThat(sizePref).isNotNull(); assertThat("" + footerPref.getTitle()) .isEqualTo(getText(EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE)); @@ -270,47 +244,48 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @Test @UiThreadTest public void testShowOneEnabledDisplay_FewAvailable() { - mDisplayIdArg = 1; doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); initFragment(); - verify(mMockedInjector, never()).getDisplay(anyInt()); + verify(mMockedInjector, never()).getAllDisplays(); mHandler.flush(); - verify(mMockedInjector).getDisplay(mDisplayIdArg); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); + verify(mMockedInjector, never()).getDisplay(anyInt()); + verify(mMockedInjector).getAllDisplays(); + var pref = mPreferenceScreen.findPreference( + PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); assertThat(pref).isNotNull(); - pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); + pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.keyForNth(0)); assertThat(pref).isNotNull(); var footerPref = mPreferenceScreen.findPreference(PrefBasics.FOOTER.key); - assertThat(footerPref).isNotNull(); - var sizePref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + // No footer for showing multiple displays. + assertThat(footerPref).isNull(); + var sizePref = mPreferenceScreen.findPreference( + PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(0)); assertThat(sizePref).isNotNull(); - assertThat("" + footerPref.getTitle()) - .isEqualTo(getText(EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE)); } @Test @UiThreadTest public void testShowDisabledDisplay() { - mDisplayIdArg = 1; initFragment(); - verify(mMockedInjector, never()).getDisplay(anyInt()); mHandler.flush(); - verify(mMockedInjector).getDisplay(mDisplayIdArg); - var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference( - PrefBasics.EXTERNAL_DISPLAY_USE.key); + verify(mMockedInjector, never()).getDisplay(anyInt()); + verify(mMockedInjector).getAllDisplays(); + var category = getExternalDisplayCategory(0); + var mainPref = (MainSwitchPreference) category.findPreference( + PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0)); assertThat(mainPref).isNotNull(); assertThat("" + mainPref.getTitle()).isEqualTo( getText(PrefBasics.EXTERNAL_DISPLAY_USE.titleResource)); assertThat(mainPref.isChecked()).isFalse(); assertThat(mainPref.isEnabled()).isTrue(); assertThat(mainPref.getOnPreferenceChangeListener()).isNotNull(); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); + var pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); assertThat(pref).isNull(); - pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); + pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.keyForNth(0)); assertThat(pref).isNull(); - var footerPref = mPreferenceScreen.findPreference(PrefBasics.FOOTER.key); + var footerPref = category.findPreference(PrefBasics.FOOTER.key); assertThat(footerPref).isNull(); - var sizePref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + var sizePref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(0)); assertThat(sizePref).isNull(); } @@ -321,7 +296,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa initFragment(); mHandler.flush(); var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference( - PrefBasics.EXTERNAL_DISPLAY_USE.key); + PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0)); assertThat(mainPref).isNotNull(); assertThat("" + mainPref.getTitle()).isEqualTo( getText(PrefBasics.EXTERNAL_DISPLAY_USE.titleResource)); @@ -337,13 +312,13 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @Test @UiThreadTest public void testDisplayRotationPreference() { - mDisplayIdArg = 1; + final int displayId = 1; doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); var fragment = initFragment(); mHandler.flush(); - ListPreference pref = - mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); - assertThat(pref.getKey()).isEqualTo(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); + var category = getExternalDisplayCategory(0); + ListPreference pref = category.findPreference( + PrefBasics.EXTERNAL_DISPLAY_ROTATION.keyForNth(0)); assertThat("" + pref.getTitle()).isEqualTo( getText(PrefBasics.EXTERNAL_DISPLAY_ROTATION.titleResource)); assertThat(pref.getEntries().length).isEqualTo(4); @@ -359,10 +334,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa assertThat(pref.getOnPreferenceChangeListener()).isNotNull(); assertThat(pref.isEnabled()).isTrue(); var rotation = 1; - doReturn(true).when(mMockedInjector).freezeDisplayRotation(mDisplayIdArg, rotation); + doReturn(true).when(mMockedInjector).freezeDisplayRotation(displayId, rotation); assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, rotation + "")) .isTrue(); - verify(mMockedInjector).freezeDisplayRotation(mDisplayIdArg, rotation); + verify(mMockedInjector).freezeDisplayRotation(displayId, rotation); assertThat(pref.getValue()).isEqualTo(rotation + ""); verify(mMockedMetricsLogger).writePreferenceClickMetric(pref); } @@ -370,31 +345,30 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @Test @UiThreadTest public void testDisplayResolutionPreference() { - mDisplayIdArg = 1; + final int displayId = 1; doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); var fragment = initFragment(); mHandler.flush(); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); - assertThat(pref.getKey()).isEqualTo(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); + var category = getExternalDisplayCategory(0); + var pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); assertThat("" + pref.getTitle()).isEqualTo( getText(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.titleResource)); assertThat("" + pref.getSummary()).isEqualTo("1920 x 1080"); assertThat(pref.isEnabled()).isTrue(); assertThat(pref.getOnPreferenceClickListener()).isNotNull(); assertThat(pref.getOnPreferenceClickListener().onPreferenceClick(pref)).isTrue(); - assertThat(mResolutionSelectorDisplayId).isEqualTo(mDisplayIdArg); + assertThat(mResolutionSelectorDisplayId).isEqualTo(displayId); verify(mMockedMetricsLogger).writePreferenceClickMetric(pref); } @Test @UiThreadTest public void testDisplaySizePreference() { - mDisplayIdArg = 1; doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); var fragment = initFragment(); mHandler.flush(); - var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); - assertThat(pref.getKey()).isEqualTo(PrefBasics.EXTERNAL_DISPLAY_SIZE.key); + var category = getExternalDisplayCategory(0); + var pref = category.findPreference(PrefBasics.EXTERNAL_DISPLAY_SIZE.keyForNth(0)); assertThat("" + pref.getTitle()) .isEqualTo(getText(PrefBasics.EXTERNAL_DISPLAY_SIZE.titleResource)); assertThat("" + pref.getSummary()) @@ -408,25 +382,25 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa @Test @UiThreadTest public void testUseDisplayPreference_EnabledDisplay() { - mDisplayIdArg = 1; + final int displayId = 1; doReturn(true).when(mMockedInjector).isDisplayEnabled(any()); - doReturn(true).when(mMockedInjector).enableConnectedDisplay(mDisplayIdArg); - doReturn(true).when(mMockedInjector).disableConnectedDisplay(mDisplayIdArg); + doReturn(true).when(mMockedInjector).enableConnectedDisplay(displayId); + doReturn(true).when(mMockedInjector).disableConnectedDisplay(displayId); var fragment = initFragment(); mHandler.flush(); - MainSwitchPreference pref = - mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_USE.key); - assertThat(pref.getKey()).isEqualTo(PrefBasics.EXTERNAL_DISPLAY_USE.key); + MainSwitchPreference pref = getExternalDisplayCategory(0) + .findPreference(PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0)); + assertThat(pref.getKey()).isEqualTo(PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0)); assertThat("" + pref.getTitle()) .isEqualTo(getText(PrefBasics.EXTERNAL_DISPLAY_USE.titleResource)); assertThat(pref.isEnabled()).isTrue(); assertThat(pref.isChecked()).isTrue(); assertThat(pref.getOnPreferenceChangeListener()).isNotNull(); assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, false)).isTrue(); - verify(mMockedInjector).disableConnectedDisplay(mDisplayIdArg); + verify(mMockedInjector).disableConnectedDisplay(displayId); assertThat(pref.isChecked()).isFalse(); assertThat(pref.getOnPreferenceChangeListener().onPreferenceChange(pref, true)).isTrue(); - verify(mMockedInjector).enableConnectedDisplay(mDisplayIdArg); + verify(mMockedInjector).enableConnectedDisplay(displayId); assertThat(pref.isChecked()).isTrue(); verify(mMockedMetricsLogger, times(2)).writePreferenceClickMetric(pref); } @@ -443,13 +417,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa return mFragment; } - @NonNull - private Bundle createBundleForPreviouslyShownList() { - var state = new Bundle(); - state.putBoolean(PREVIOUSLY_SHOWN_LIST_KEY, true); - return state; - } - @NonNull private String getText(int id) { return mContext.getResources().getText(id).toString(); @@ -501,21 +468,11 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa mPreferenceIdFromResource = resource; } - @Override - protected int getDisplayIdArg() { - return mDisplayIdArg; - } - @Override protected void launchResolutionSelector(@NonNull Context context, int displayId) { mResolutionSelectorDisplayId = displayId; } - @Override - protected void launchExternalDisplaySettings(final int displayId) { - mDisplayIdArg = displayId; - } - @Override Preference newFooterPreference(Context context) { return new Preference(context); diff --git a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayUpdaterTest.java b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayUpdaterTest.java index 824974ad854..698f0a42e20 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayUpdaterTest.java +++ b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayUpdaterTest.java @@ -63,6 +63,7 @@ public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase { return null; }).when(mMockedCallback).onDeviceAdded(any()); mUpdater.initPreference(mContext, mMockedInjector); + mUpdater.refreshPreference(); mUpdater.registerCallback(); mHandler.flush(); assertThat(mPreferenceAdded).isNotNull(); @@ -85,6 +86,7 @@ public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase { return null; }).when(mMockedCallback).onDeviceRemoved(any()); mUpdater.initPreference(mContext, mMockedInjector); + mUpdater.refreshPreference(); mUpdater.registerCallback(); mHandler.flush(); assertThat(mPreferenceAdded).isNotNull();