diff --git a/aconfig/settings_globalintl_flag_declarations.aconfig b/aconfig/settings_globalintl_flag_declarations.aconfig index 909e4642d9a..6cfd140b66f 100644 --- a/aconfig/settings_globalintl_flag_declarations.aconfig +++ b/aconfig/settings_globalintl_flag_declarations.aconfig @@ -27,4 +27,11 @@ flag { namespace: "globalintl" description: "Feature flag for regional preferences APIs" bug: "370379000" +} + +flag { + name: "settings_expressive_design_enabled" + namespace: "globalintl" + description: "Feature flag for expressive design" + bug: "385659296" } \ No newline at end of file diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml index 059adbe4ea2..13061b53c35 100644 --- a/res-product/values/strings.xml +++ b/res-product/values/strings.xml @@ -89,12 +89,6 @@ Use your face to unlock your tablet or for authentication in apps, like when you sign in to apps or approve a purchase Use your face to unlock your device or for authentication in apps, like when you sign in to apps or approve a purchase - - - - - - Allow your child to use their face to unlock their phone @@ -113,18 +107,6 @@ Using your child\u2019s face to unlock their tablet may be less secure than a strong pattern or PIN. Using your child\u2019s face to unlock their device may be less secure than a strong pattern or PIN. - - - - - - - - - - - - @@ -179,12 +161,6 @@ - - - - - - @@ -217,8 +193,6 @@ Use your face to unlock your device or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the device can unlock it when you don\u2019t intend to.\n\nYour device can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour device can be unlocked by someone who looks a lot like you, like an identical sibling. Use your fingerprint to unlock your %s or verify it\u2019s you, like when you sign in to apps or approve a purchase - - Use your fingerprints to unlock your %s or verify it\u2019s you in apps Allow your child to use their fingerprint to unlock their phone or verify it\u2019s them. This happens when they sign in to apps, approve a purchase, and more. @@ -267,18 +241,6 @@ Your child\u2019s tablet can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger. Your child\u2019s device can be unlocked when they don\u2019t intend to, like if someone holds it up to their finger. - - - - - - - - - - - - Use your fingerprint to unlock your tablet or verify it\u2019s you, like when you sign in to apps diff --git a/res/drawable/ic_eyeglasses.xml b/res/drawable/ic_eyeglasses.xml deleted file mode 100644 index c35d7b30529..00000000000 --- a/res/drawable/ic_eyeglasses.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/res/drawable/ic_familiar_face_and_zone.xml b/res/drawable/ic_familiar_face_and_zone.xml deleted file mode 100644 index dbef199e896..00000000000 --- a/res/drawable/ic_familiar_face_and_zone.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/drawable/ic_privacy_tip.xml b/res/drawable/ic_privacy_tip.xml deleted file mode 100644 index 8f34eb65f22..00000000000 --- a/res/drawable/ic_privacy_tip.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/res/drawable/ic_security_privacy_safe.xml b/res/drawable/ic_security_privacy_safe.xml deleted file mode 100644 index 99aeaef2496..00000000000 --- a/res/drawable/ic_security_privacy_safe.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - \ No newline at end of file diff --git a/res/layout/face_enroll_introduction_2.xml b/res/layout/face_enroll_introduction_2.xml deleted file mode 100644 index cbc14bce15b..00000000000 --- a/res/layout/face_enroll_introduction_2.xml +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/layout/hearing_device_input_routing_dialog.xml b/res/layout/hearing_device_input_routing_dialog.xml new file mode 100644 index 00000000000..266126986f5 --- /dev/null +++ b/res/layout/hearing_device_input_routing_dialog.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index cbcf51dfbf9..7386eabaa38 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -180,6 +180,16 @@ Unmute surroundings Couldn\u2019t update surroundings + + Default microphone for calls + + Default microphone + + Choose a microphone for calls. + + Hearing aid microphone + + This phone\'s microphone Audio output @@ -807,8 +817,6 @@ - - Cancel @@ -936,8 +944,6 @@ You and your child are in control Keep in mind - - Secure and helpful Use your fingerprint to unlock your phone or approve purchases.\n\nNote: You can\u2019t use your fingerprint to unlock this device. For more information, contact your organization\u2019s admin. @@ -968,8 +974,6 @@ For best results, use a screen protector that\u2019s Made for Google certified. With other screen protectors, your child\u2019s fingerprint may not work. - - @@ -5450,9 +5454,9 @@ Make the mouse pointer more noticeable - Make all apps dark + Make more apps dark - Applies to apps without their own dark theme. Some apps may have display issues, like inverted colors. + Automatically convert light theme apps to dark theme Remove animations @@ -12304,11 +12308,6 @@ Inactive / eSIM - - SIM name & color Name diff --git a/res/xml/accessibility_color_and_motion.xml b/res/xml/accessibility_color_and_motion.xml index ffcdbddf7fe..9cc8f8b9bc7 100644 --- a/res/xml/accessibility_color_and_motion.xml +++ b/res/xml/accessibility_color_and_motion.xml @@ -51,14 +51,6 @@ settings:controller="com.android.settings.display.DarkUIPreferenceController" settings:searchable="false"/> - - - + - + - + + + + + + + supportedStrategies = mAudioRoutingHelper.getSupportedStrategies(audioAttributes); final AudioDeviceAttributes hearingDeviceAttributes = - mAudioRoutingHelper.getMatchedHearingDeviceAttributes(hearingDevice); + mAudioRoutingHelper.getMatchedHearingDeviceAttributesForOutput(hearingDevice); if (hearingDeviceAttributes == null) { if (DEBUG) { Log.d(TAG, diff --git a/src/com/android/settings/accessibility/HighContrastTextMigrationReceiver.java b/src/com/android/settings/accessibility/HighContrastTextMigrationReceiver.java index 7743a1fdee1..803546707fd 100644 --- a/src/com/android/settings/accessibility/HighContrastTextMigrationReceiver.java +++ b/src/com/android/settings/accessibility/HighContrastTextMigrationReceiver.java @@ -123,7 +123,7 @@ public class HighContrastTextMigrationReceiver extends BroadcastReceiver { R.string.accessibility_notification_high_contrast_text_title)) .setContentText(context.getString( R.string.accessibility_notification_high_contrast_text_content)) - .setAutoCancel(true); + .setFlag(Notification.FLAG_NO_CLEAR, true); Intent settingsIntent = new Intent(Settings.ACTION_TEXT_READING_SETTINGS); settingsIntent.setPackage(context.getPackageName()); @@ -142,9 +142,11 @@ public class HighContrastTextMigrationReceiver extends BroadcastReceiver { settingsPendingIntent ).build(); - notificationBuilder.addAction(settingsAction); + notificationBuilder + .setContentIntent(settingsPendingIntent) + .addAction(settingsAction) + .setAutoCancel(true); } - NotificationManager notificationManager = context.getSystemService(NotificationManager.class); NotificationChannel notificationChannel = new NotificationChannel( diff --git a/src/com/android/settings/accessibility/ToggleForceInvertPreferenceController.java b/src/com/android/settings/accessibility/ToggleForceInvertPreferenceController.java index 3f2cc130ffe..be738e31efa 100644 --- a/src/com/android/settings/accessibility/ToggleForceInvertPreferenceController.java +++ b/src/com/android/settings/accessibility/ToggleForceInvertPreferenceController.java @@ -16,11 +16,16 @@ package com.android.settings.accessibility; +import static com.android.settings.accessibility.AccessibilityUtil.State.OFF; +import static com.android.settings.accessibility.AccessibilityUtil.State.ON; + import android.content.Context; +import android.content.res.Configuration; import android.provider.Settings; import android.view.accessibility.Flags; -import androidx.annotation.VisibleForTesting; +import androidx.annotation.NonNull; +import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; @@ -28,27 +33,28 @@ import com.android.settings.core.TogglePreferenceController; /** A toggle preference controller for force invert (force dark). */ public class ToggleForceInvertPreferenceController extends TogglePreferenceController { - public static final String SETTINGS_KEY = - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED; - - @VisibleForTesting - static final int ON = 1; - @VisibleForTesting - static final int OFF = 0; - public ToggleForceInvertPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } @Override public boolean isChecked() { - return Settings.Secure.getInt(mContext.getContentResolver(), SETTINGS_KEY, OFF) != OFF; + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, OFF) != OFF; } @Override public boolean setChecked(boolean isChecked) { return Settings.Secure.putInt(mContext.getContentResolver(), - SETTINGS_KEY, isChecked ? ON : OFF); + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, isChecked ? ON : OFF); + } + + @Override + public void updateState(@NonNull Preference preference) { + super.updateState(preference); + final boolean isDarkModeActivated = (mContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_YES) != 0; + preference.setEnabled(isDarkModeActivated); } @Override diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index 77f11ff6f0f..1f7b3e512b2 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -37,7 +37,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; -import com.android.settings.flags.Flags; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ConfirmDeviceCredentialActivity; @@ -552,11 +551,8 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase @NonNull protected PorterDuffColorFilter getIconColorFilter() { if (mIconColorFilter == null) { - final int colorType = Flags.biometricsOnboardingEducation() - ? DynamicColorPalette.ColorType.PRIMARY_TEXT - : DynamicColorPalette.ColorType.ACCENT; mIconColorFilter = new PorterDuffColorFilter( - DynamicColorPalette.getColor(this, colorType), + DynamicColorPalette.getColor(this, DynamicColorPalette.ColorType.ACCENT), PorterDuff.Mode.SRC_IN); } return mIconColorFilter; diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index 78e3770810a..d3f75195305 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -53,7 +53,6 @@ import com.android.settings.biometrics.BiometricEnrollActivity; import com.android.settings.biometrics.BiometricEnrollIntroduction; import com.android.settings.biometrics.BiometricUtils; import com.android.settings.biometrics.MultiBiometricEnrollHelper; -import com.android.settings.flags.Flags; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.SetupSkipDialog; import com.android.settings.utils.SensorPrivacyManagerHelper; @@ -145,19 +144,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { final ImageView iconLooking = findViewById(R.id.icon_looking); iconGlasses.getBackground().setColorFilter(getIconColorFilter()); iconLooking.getBackground().setColorFilter(getIconColorFilter()); - if (Flags.biometricsOnboardingEducation()) { - final ImageView iconSecurityPrivacySafe = findViewById(R.id.icon_security_privacy_safe); - final ImageView iconPrivacyTip = findViewById(R.id.icon_privacy_tip); - final ImageView iconFamiliarFaceAndZone = - findViewById(R.id.icon_familiar_face_and_zone); - final ImageView iconTrashCan = findViewById(R.id.icon_trash_can); - final ImageView iconLink = findViewById(R.id.icon_link); - iconSecurityPrivacySafe.getBackground().setColorFilter(getIconColorFilter()); - iconPrivacyTip.getBackground().setColorFilter(getIconColorFilter()); - iconFamiliarFaceAndZone.getBackground().setColorFilter(getIconColorFilter()); - iconTrashCan.getBackground().setColorFilter(getIconColorFilter()); - iconLink.getBackground().setColorFilter(getIconColorFilter()); - } // Set text for views with multiple variations. final TextView infoMessageGlasses = findViewById(R.id.info_message_glasses); @@ -170,19 +156,9 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { infoMessageLooking.setText(getInfoMessageLooking()); inControlTitle.setText(getInControlTitle()); howMessage.setText(getHowMessage()); - if (Flags.biometricsOnboardingEducation()) { - inControlMessage.setText( - R.string.security_settings_face_enroll_introduction_control_message_2); - final TextView learnMore = findViewById(R.id.message_learn_more); - learnMore.setText(Html.fromHtml(getString( - R.string.security_settings_face_enroll_introduction_learn_more_message), - Html.FROM_HTML_MODE_LEGACY)); - learnMore.setMovementMethod(LinkMovementMethod.getInstance()); - } else { - inControlMessage.setText(Html.fromHtml(getString(getInControlMessage()), - Html.FROM_HTML_MODE_LEGACY)); - inControlMessage.setMovementMethod(LinkMovementMethod.getInstance()); - } + inControlMessage.setText(Html.fromHtml(getString(getInControlMessage()), + Html.FROM_HTML_MODE_LEGACY)); + inControlMessage.setMovementMethod(LinkMovementMethod.getInstance()); lessSecure.setText(getLessSecureMessage()); final ScrollView scrollView = @@ -435,11 +411,7 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { @Override protected int getLayoutResource() { - if (Flags.biometricsOnboardingEducation()) { - return R.layout.face_enroll_introduction_2; - } else { - return R.layout.face_enroll_introduction; - } + return R.layout.face_enroll_introduction; } @Override @@ -622,13 +594,8 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { setDescriptionText(getString( R.string.private_space_face_enroll_introduction_message)); } else if (mIsFaceStrong) { - final int messageRes; - if (Flags.biometricsOnboardingEducation()) { - messageRes = R.string.security_settings_face_enroll_introduction_message_class3_2; - } else { - messageRes = R.string.security_settings_face_enroll_introduction_message_class3; - } - setDescriptionText(getString(messageRes)); + setDescriptionText(getString( + R.string.security_settings_face_enroll_introduction_message_class3)); } super.updateDescriptionText(); } diff --git a/src/com/android/settings/bluetooth/AmbientVolumePreference.java b/src/com/android/settings/bluetooth/AmbientVolumePreference.java index 8196edf0bd8..4f89007cf5f 100644 --- a/src/com/android/settings/bluetooth/AmbientVolumePreference.java +++ b/src/com/android/settings/bluetooth/AmbientVolumePreference.java @@ -37,8 +37,8 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.bluetooth.AmbientVolumeUi; +import com.android.settingslib.widget.SliderPreference; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -68,12 +68,12 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV private boolean mExpanded = false; private boolean mMutable = false; private boolean mMuted = false; - private final BiMap mSideToSliderMap = HashBiMap.create(); + private final BiMap mSideToSliderMap = HashBiMap.create(); private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT; private final OnPreferenceChangeListener mPreferenceChangeListener = (slider, v) -> { - if (slider instanceof SeekBarPreference && v instanceof final Integer value) { + if (slider instanceof SliderPreference && v instanceof final Integer value) { final Integer side = mSideToSliderMap.inverse().get(slider); if (mListener != null && side != null) { mListener.onSliderValueChange(side, value); @@ -173,8 +173,8 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV } mMuted = muted; if (mMutable && mMuted) { - for (SeekBarPreference slider : mSideToSliderMap.values()) { - slider.setProgress(slider.getMin()); + for (SliderPreference slider : mSideToSliderMap.values()) { + slider.setValue(slider.getMin()); } } updateVolumeIcon(); @@ -198,7 +198,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV if (!mSideToSliderMap.isEmpty()) { for (int side : VALID_SIDES) { - final SeekBarPreference slider = mSideToSliderMap.get(side); + final SliderPreference slider = mSideToSliderMap.get(side); if (slider != null && findPreference(slider.getKey()) == null) { addPreference(slider); } @@ -209,7 +209,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV @Override public void setSliderEnabled(int side, boolean enabled) { - SeekBarPreference slider = mSideToSliderMap.get(side); + SliderPreference slider = mSideToSliderMap.get(side); if (slider != null && slider.isEnabled() != enabled) { slider.setEnabled(enabled); updateLayout(); @@ -218,16 +218,16 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV @Override public void setSliderValue(int side, int value) { - SeekBarPreference slider = mSideToSliderMap.get(side); - if (slider != null && slider.getProgress() != value) { - slider.setProgress(value); + SliderPreference slider = mSideToSliderMap.get(side); + if (slider != null && slider.getValue() != value) { + slider.setValue(value); updateVolumeLevel(); } } @Override public void setSliderRange(int side, int min, int max) { - SeekBarPreference slider = mSideToSliderMap.get(side); + SliderPreference slider = mSideToSliderMap.get(side); if (slider != null) { slider.setMin(min); slider.setMax(max); @@ -243,7 +243,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV slider.setVisible(mExpanded); } if (!slider.isEnabled()) { - slider.setProgress(slider.getMin()); + slider.setValue(slider.getMin()); } }); updateVolumeLevel(); @@ -265,14 +265,14 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV } private int getVolumeLevel(int side) { - SeekBarPreference slider = mSideToSliderMap.get(side); + SliderPreference slider = mSideToSliderMap.get(side); if (slider == null || !slider.isEnabled()) { return 0; } final double min = slider.getMin(); final double max = slider.getMax(); final double levelGap = (max - min) / 4.0; - final int value = slider.getProgress(); + final int value = slider.getValue(); return (int) Math.ceil((value - min) / levelGap); } @@ -311,7 +311,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV if (mSideToSliderMap.containsKey(side)) { return; } - SeekBarPreference slider = new SeekBarPreference(getContext()); + SliderPreference slider = new SliderPreference(getContext()); slider.setKey(KEY_AMBIENT_VOLUME_SLIDER + "_" + side); slider.setOrder(order); slider.setOnPreferenceChangeListener(mPreferenceChangeListener); @@ -326,7 +326,7 @@ public class AmbientVolumePreference extends PreferenceGroup implements AmbientV } @VisibleForTesting - Map getSliders() { + Map getSliders() { return mSideToSliderMap; } } diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java index 8af08792180..01f8bb4cc8e 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java @@ -42,6 +42,7 @@ public class BluetoothDetailsHearingDeviceController extends BluetoothDetailsCon public static final int ORDER_HEARING_DEVICE_SETTINGS = 1; public static final int ORDER_HEARING_AIDS_PRESETS = 2; + public static final int ORDER_HEARING_DEVICE_INPUT_ROUTING = 3; public static final int ORDER_AMBIENT_VOLUME = 4; static final String KEY_HEARING_DEVICE_GROUP = "hearing_device_group"; @@ -62,10 +63,12 @@ public class BluetoothDetailsHearingDeviceController extends BluetoothDetailsCon @VisibleForTesting void setSubControllers( BluetoothDetailsHearingDeviceSettingsController hearingDeviceSettingsController, - BluetoothDetailsHearingAidsPresetsController presetsController) { + BluetoothDetailsHearingAidsPresetsController presetsController, + BluetoothDetailsHearingDeviceInputRoutingController inputRoutingController) { mControllers.clear(); mControllers.add(hearingDeviceSettingsController); mControllers.add(presetsController); + mControllers.add(inputRoutingController); } @Override @@ -112,6 +115,11 @@ public class BluetoothDetailsHearingDeviceController extends BluetoothDetailsCon mControllers.add(new BluetoothDetailsAmbientVolumePreferenceController(mContext, mManager, mFragment, mCachedDevice, mLifecycle)); } + if (com.android.settingslib.flags.Flags.hearingDevicesInputRoutingControl()) { + mControllers.add( + new BluetoothDetailsHearingDeviceInputRoutingController(mContext, mFragment, + mCachedDevice, mLifecycle)); + } } @NonNull diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingController.java new file mode 100644 index 00000000000..6c9a075672a --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingController.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2024 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.bluetooth; + +import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP; +import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_HEARING_DEVICE_INPUT_ROUTING; + +import android.content.Context; +import android.media.AudioManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.bluetooth.HearingDeviceInputRoutingPreference.InputRoutingValue; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.HapClientProfile; +import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants; +import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.Arrays; + +/** + * The controller of the hearing device input routing + * + *

It manages the input routing preference and update the routing according to the value. + */ +public class BluetoothDetailsHearingDeviceInputRoutingController extends + BluetoothDetailsController implements + HearingDeviceInputRoutingPreference.InputRoutingCallback { + + private static final String TAG = "BluetoothDetailsHearingDeviceInputRoutingController"; + static final String KEY_HEARING_DEVICE_INPUT_ROUTING = "hearing_device_input_routing"; + + private final HearingAidAudioRoutingHelper mAudioRoutingHelper; + private final AudioManager mAudioManager; + + public BluetoothDetailsHearingDeviceInputRoutingController( + @NonNull Context context, + @NonNull PreferenceFragmentCompat fragment, + @NonNull CachedBluetoothDevice device, + @NonNull Lifecycle lifecycle) { + super(context, fragment, device, lifecycle); + mAudioRoutingHelper = new HearingAidAudioRoutingHelper(context); + mAudioManager = mContext.getSystemService(AudioManager.class); + } + + @Override + public boolean isAvailable() { + boolean isSupportedProfile = mCachedDevice.getProfiles().stream().anyMatch( + profile -> profile instanceof HapClientProfile); + boolean isSupportedInputDevice = Arrays.stream( + mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).anyMatch( + info -> mCachedDevice.getAddress().equals(info.getAddress())); + if (isSupportedProfile && !isSupportedInputDevice) { + Log.d(TAG, "Not supported input type hearing device."); + } + return isSupportedProfile && isSupportedInputDevice; + } + + @Override + protected void init(PreferenceScreen screen) { + PreferenceCategory hearingCategory = screen.findPreference(KEY_HEARING_DEVICE_GROUP); + if (hearingCategory != null) { + hearingCategory.addPreference( + createInputRoutingPreference(hearingCategory.getContext())); + } + } + + @Override + protected void refresh() {} + + @Nullable + @Override + public String getPreferenceKey() { + return KEY_HEARING_DEVICE_INPUT_ROUTING; + } + + private HearingDeviceInputRoutingPreference createInputRoutingPreference(Context context) { + HearingDeviceInputRoutingPreference pref = new HearingDeviceInputRoutingPreference(context); + pref.setKey(KEY_HEARING_DEVICE_INPUT_ROUTING); + pref.setOrder(ORDER_HEARING_DEVICE_INPUT_ROUTING); + pref.setTitle(context.getString(R.string.bluetooth_hearing_device_input_routing_title)); + pref.setChecked(getUserPreferredInputRoutingValue()); + pref.setInputRoutingCallback(this); + return pref; + } + + @InputRoutingValue + private int getUserPreferredInputRoutingValue() { + return mCachedDevice.getDevice().isMicrophonePreferredForCalls() + ? InputRoutingValue.HEARING_DEVICE : InputRoutingValue.BUILTIN_MIC; + } + + @Override + public void onInputRoutingUpdated(int selectedInputRoutingUiValue) { + boolean useBuiltinMic = + (selectedInputRoutingUiValue == InputRoutingValue.BUILTIN_MIC); + boolean status = mAudioRoutingHelper.setPreferredInputDeviceForCalls(mCachedDevice, + useBuiltinMic ? HearingAidAudioRoutingConstants.RoutingValue.BUILTIN_DEVICE + : HearingAidAudioRoutingConstants.RoutingValue.AUTO); + if (!status) { + Log.d(TAG, "Fail to configure setPreferredInputDeviceForCalls"); + } + mCachedDevice.getDevice().setMicrophonePreferredForCalls(!useBuiltinMic); + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java index 403a82429cc..f7829b1eb43 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java @@ -373,6 +373,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment } mFormatter.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE); } + setDivider(null); } @Override diff --git a/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreference.java b/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreference.java new file mode 100644 index 00000000000..2d09f6103f1 --- /dev/null +++ b/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreference.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2024 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.bluetooth; + +import android.content.Context; +import android.content.DialogInterface; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RadioGroup; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settings.R; +import com.android.settingslib.CustomDialogPreferenceCompat; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Preference for controlling the input routing for hearing device. + * + *

This preference displays a dialog that allows users to choose which input device that want to + * use when using this hearing device. + */ +public class HearingDeviceInputRoutingPreference extends CustomDialogPreferenceCompat { + + /** + * Annotations for possible input routing UI for this hearing device input routing preference. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + InputRoutingValue.HEARING_DEVICE, + InputRoutingValue.BUILTIN_MIC + }) + public @interface InputRoutingValue { + int HEARING_DEVICE = 0; + int BUILTIN_MIC = 1; + } + + private static final int INVALID_ID = -1; + private final Context mContext; + private final int mFromHearingDeviceButtonId = R.id.input_from_hearing_device; + private final int mFromBuiltinMicButtonId = R.id.input_from_builtin_mic; + + @Nullable + private RadioGroup mInputRoutingGroup; + @Nullable + private InputRoutingCallback mCallback; + // Default value is hearing device as input + @InputRoutingValue + private int mSelectedInputRoutingValue = InputRoutingValue.HEARING_DEVICE; + + + public HearingDeviceInputRoutingPreference(@NonNull Context context) { + this(context, null); + } + + public HearingDeviceInputRoutingPreference(@NonNull Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + + mContext = context; + setDialogTitle(R.string.bluetooth_hearing_device_input_routing_dialog_title); + setDialogLayoutResource(R.layout.hearing_device_input_routing_dialog); + setNegativeButtonText(R.string.cancel); + setPositiveButtonText(R.string.done_button); + } + + /** + * Sets the callback to receive input routing updates. + */ + public void setInputRoutingCallback(@NonNull InputRoutingCallback callback) { + mCallback = callback; + } + + /** + * Sets the {@link InputRoutingValue} value to determine which radio button should be checked, + * and also update summary accordingly. + * + * @param inputRoutingValue The input routing value. + */ + public void setChecked(@InputRoutingValue int inputRoutingValue) { + mSelectedInputRoutingValue = inputRoutingValue; + setSummary(getSummary()); + } + + @Override + protected void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + int prevBtnId = getRadioButtonId(mSelectedInputRoutingValue); + int curBtnId = Objects.requireNonNull(mInputRoutingGroup).getCheckedRadioButtonId(); + if (prevBtnId == curBtnId) { + return; + } + + setChecked(getSelectedInputRoutingValue()); + if (mCallback != null) { + mCallback.onInputRoutingUpdated(mSelectedInputRoutingValue); + } + } + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + + mInputRoutingGroup = view.requireViewById(R.id.input_routing_group); + mInputRoutingGroup.check(getRadioButtonId(mSelectedInputRoutingValue)); + } + + @Nullable + @Override + public CharSequence getSummary() { + return switch (mSelectedInputRoutingValue) { + case InputRoutingValue.HEARING_DEVICE -> mContext.getResources().getString( + R.string.bluetooth_hearing_device_input_routing_hearing_device_option); + case InputRoutingValue.BUILTIN_MIC -> mContext.getResources().getString( + R.string.bluetooth_hearing_device_input_routing_builtin_option); + default -> null; + }; + } + + private int getRadioButtonId(@InputRoutingValue int inputRoutingValue) { + return switch (inputRoutingValue) { + case InputRoutingValue.HEARING_DEVICE -> mFromHearingDeviceButtonId; + case InputRoutingValue.BUILTIN_MIC -> mFromBuiltinMicButtonId; + default -> INVALID_ID; + }; + } + + @InputRoutingValue + private int getSelectedInputRoutingValue() { + int checkedId = Objects.requireNonNull(mInputRoutingGroup).getCheckedRadioButtonId(); + if (checkedId == mFromBuiltinMicButtonId) { + return InputRoutingValue.BUILTIN_MIC; + } else { + // Should always return default value hearing device as input if something error + // happens. + return InputRoutingValue.HEARING_DEVICE; + } + } + + /** + * Callback to be invoked when input routing changes. + */ + public interface InputRoutingCallback { + + /** + * Called when the positive button is clicked and input routing is changed. + * + * @param selectedInputRoutingValue The selected input routing value. + */ + void onInputRoutingUpdated(@InputRoutingValue int selectedInputRoutingValue); + } +} diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java index e7ee9e1c37e..1ffbb50e548 100644 --- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java +++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java @@ -92,7 +92,17 @@ public class GraphicsDriverEnableAngleAsSystemDriverController // This can be enabled by calling: // `adb shell setprop debug.graphics.angle.developeroption.enable true` private boolean isAngleDeveloperOptionEnabled() { - return mSystemProperties.getBoolean(PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION, false); + boolean intendedUsingAngleDeveloperOption = + mSystemProperties.getBoolean(PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION, false); + if (intendedUsingAngleDeveloperOption) { + Log.v(TAG, + "ANGLE developer option is enabled in system properties, " + + "but temporarily overridden."); + } + + // Temporarily disabling for broader rollout. + // The feature requires further maturation before general availability. + return false; } @VisibleForTesting diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt index 7cc320d228a..0fe2a098734 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreference.kt +++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt @@ -77,6 +77,10 @@ class AdaptiveSleepPreference : override fun storage(context: Context): KeyValueStore = Storage(context) + override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions() + + override fun getWritePermissions(context: Context) = SettingsSecureStore.getWritePermissions() + override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = ReadWritePermit.ALLOW diff --git a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt index 32d29101847..81592cabd31 100644 --- a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt +++ b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt @@ -50,6 +50,10 @@ class PeakRefreshRateSwitchPreference : override fun storage(context: Context): KeyValueStore = PeakRefreshRateStore(context, SettingsSystemStore.get(context)) + override fun getReadPermissions(context: Context) = SettingsSystemStore.getReadPermissions() + + override fun getWritePermissions(context: Context) = SettingsSystemStore.getWritePermissions() + override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = ReadWritePermit.ALLOW diff --git a/src/com/android/settings/display/darkmode/DarkModeScreen.kt b/src/com/android/settings/display/darkmode/DarkModeScreen.kt index 807b0aeb633..87f9f23bf70 100644 --- a/src/com/android/settings/display/darkmode/DarkModeScreen.kt +++ b/src/com/android/settings/display/darkmode/DarkModeScreen.kt @@ -16,6 +16,7 @@ package com.android.settings.display.darkmode +import android.Manifest import android.app.UiModeManager import android.content.BroadcastReceiver import android.content.Context @@ -29,6 +30,7 @@ import com.android.settings.flags.Flags import com.android.settingslib.PrimarySwitchPreference import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.NoOpKeyedObservable +import com.android.settingslib.datastore.Permissions import com.android.settingslib.metadata.BooleanValue import com.android.settingslib.metadata.PersistentPreference import com.android.settingslib.metadata.PreferenceLifecycleContext @@ -71,6 +73,11 @@ class DarkModeScreen : override val keywords: Int get() = R.string.keywords_dark_ui_mode + override fun getReadPermissions(context: Context) = Permissions.EMPTY + + override fun getWritePermissions(context: Context) = + Permissions.allOf(Manifest.permission.MODIFY_DAY_NIGHT_MODE) + override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) = ReadWritePermit.ALLOW diff --git a/src/com/android/settings/localepicker/NewTermsOfAddressController.java b/src/com/android/settings/localepicker/NewTermsOfAddressController.java new file mode 100644 index 00000000000..fe92405f1a1 --- /dev/null +++ b/src/com/android/settings/localepicker/NewTermsOfAddressController.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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.localepicker; + +import android.content.Context; +import android.os.LocaleList; + +import androidx.annotation.NonNull; + +import com.android.internal.app.LocaleStore; +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.flags.Flags; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class NewTermsOfAddressController extends BasePreferenceController { + + public NewTermsOfAddressController(@NonNull Context context, @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + if (Flags.regionalPreferencesApiEnabled()) { + if (Flags.termsOfAddressEnabled()) { + return checkAvailabilityStatus(); + } + } + return CONDITIONALLY_UNAVAILABLE; + } + + private int checkAvailabilityStatus() { + // If language is not available for system language, or if ToA does not apply to + // system language, we will hide it. + final Locale defaultLocale = Locale.getDefault(); + LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(defaultLocale); + final List supportedLanguageList = Arrays.asList( + mContext.getResources().getStringArray( + R.array.terms_of_address_supported_languages)); + final List notSupportedLocaleList = Arrays.asList( + mContext.getResources().getStringArray( + R.array.terms_of_address_unsupported_locales)); + + final Locale locale = localeInfo.getLocale().stripExtensions(); + final String language = locale.getLanguage(); + final String localeTag = locale.toLanguageTag(); + + // Supported locales: + // 1. All French is supported except fr-CA. + // 2. QA language en-XA (LTR pseudo locale), ar_XB (RTL pseudo locale). + if ((supportedLanguageList.contains(language) + && !notSupportedLocaleList.contains(localeTag)) + || LocaleList.isPseudoLocale(locale)) { + return AVAILABLE; + } + + return CONDITIONALLY_UNAVAILABLE; + } +} diff --git a/src/com/android/settings/localepicker/TermsOfAddressCategoryController.java b/src/com/android/settings/localepicker/TermsOfAddressCategoryController.java index 01168c7ff7b..1e2fbef7e83 100644 --- a/src/com/android/settings/localepicker/TermsOfAddressCategoryController.java +++ b/src/com/android/settings/localepicker/TermsOfAddressCategoryController.java @@ -20,7 +20,6 @@ import static com.android.settings.flags.Flags.termsOfAddressEnabled; import android.content.Context; import android.os.LocaleList; -import android.text.TextUtils; import android.util.Log; import androidx.preference.PreferenceCategory; @@ -28,6 +27,7 @@ import androidx.preference.PreferenceScreen; import com.android.internal.app.LocaleStore; import com.android.settings.R; +import com.android.settings.flags.Flags; import com.android.settings.widget.PreferenceCategoryController; import java.util.Arrays; @@ -64,6 +64,9 @@ public class TermsOfAddressCategoryController extends PreferenceCategoryControll @Override public int getAvailabilityStatus() { + if (Flags.regionalPreferencesApiEnabled()) { + return CONDITIONALLY_UNAVAILABLE; + } if (!termsOfAddressEnabled()) { return CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index d934c99634b..f201b1ab037 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -468,7 +468,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { final MenuItem item = menu.add(Menu.NONE, R.id.edit_sim_name, Menu.NONE, - R.string.mobile_network_sim_name); + R.string.mobile_network_sim_label_color_title); item.setIcon(com.android.internal.R.drawable.ic_mode_edit); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); } diff --git a/src/com/android/settings/wifi/repository/WifiRepository.kt b/src/com/android/settings/wifi/repository/WifiRepository.kt index 77f0b1b47cf..39bf1aaec07 100644 --- a/src/com/android/settings/wifi/repository/WifiRepository.kt +++ b/src/com/android/settings/wifi/repository/WifiRepository.kt @@ -25,6 +25,7 @@ import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverF import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.onStart class WifiRepository( private val context: Context, @@ -32,11 +33,13 @@ class WifiRepository( context.broadcastReceiverFlow(IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)), ) { - fun wifiStateFlow() = wifiStateChangedActionFlow - .map { intent -> - intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) - } - .onEach { Log.d(TAG, "wifiStateFlow: $it") } + fun wifiStateFlow(): Flow = + wifiStateChangedActionFlow + .map { intent -> + intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) + } + .onStart { emit(WifiManager.WIFI_STATE_UNKNOWN) } + .onEach { Log.d(TAG, "wifiStateFlow: $it") } private companion object { private const val TAG = "WifiRepository" diff --git a/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionFragmentTest.java index d3f5457560c..2d2827e038b 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ColorAndMotionFragmentTest.java @@ -16,14 +16,10 @@ package com.android.settings.accessibility; -import static android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR; - import static com.google.common.truth.Truth.assertThat; import android.app.settings.SettingsEnums; import android.content.Context; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -73,20 +69,6 @@ public class ColorAndMotionFragmentTest { } @Test - @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR) - public void forceInvertEnabled_getNonIndexableKeys_existInXmlLayout() { - final List niks = ColorAndMotionFragment.SEARCH_INDEX_DATA_PROVIDER - .getNonIndexableKeys(mContext); - final List keys = - XmlTestUtils.getKeysFromPreferenceXml(mContext, - R.xml.accessibility_color_and_motion); - - assertThat(niks).doesNotContain(ColorAndMotionFragment.TOGGLE_FORCE_INVERT); - assertThat(keys).containsAtLeastElementsIn(niks); - } - - @Test - @RequiresFlagsDisabled(FLAG_FORCE_INVERT_COLOR) public void getNonIndexableKeys_existInXmlLayout() { final List niks = ColorAndMotionFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(mContext); @@ -94,7 +76,6 @@ public class ColorAndMotionFragmentTest { XmlTestUtils.getKeysFromPreferenceXml(mContext, R.xml.accessibility_color_and_motion); - assertThat(niks).contains(ColorAndMotionFragment.TOGGLE_FORCE_INVERT); assertThat(keys).containsAtLeastElementsIn(niks); } } diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java index 4decf68d68c..bf27bf8a721 100644 --- a/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java @@ -108,7 +108,7 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(TEST_DEVICE_ADDRESS); when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS); doReturn(hearingDeviceAttribute).when( - mAudioRoutingHelper).getMatchedHearingDeviceAttributes(any()); + mAudioRoutingHelper).getMatchedHearingDeviceAttributesForOutput(any()); when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType( AudioManager.STREAM_MUSIC)).thenReturn((new AudioAttributes.Builder()).build()); when(mAudioRoutingHelper.getAudioProductStrategies()).thenReturn( @@ -143,7 +143,8 @@ public class HearingDeviceAudioRoutingBasePreferenceControllerTest { @Test public void onPreferenceChange_noMatchedDeviceAttributes_notCallSetStrategies() { - when(mAudioRoutingHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null); + when(mAudioRoutingHelper.getMatchedHearingDeviceAttributesForOutput(any())).thenReturn( + null); verify(mAudioRoutingHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), anyInt()); diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleForceInvertPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleForceInvertPreferenceControllerTest.java index d8197ef9a52..a2b259f60e2 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleForceInvertPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleForceInvertPreferenceControllerTest.java @@ -23,13 +23,18 @@ import static com.android.settings.accessibility.AccessibilityUtil.State.ON; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + import android.content.Context; +import android.content.res.Configuration; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; import com.android.settings.core.BasePreferenceController; @@ -52,10 +57,7 @@ public class ToggleForceInvertPreferenceControllerTest { @Before public void setUp() { - mController = new ToggleForceInvertPreferenceController( - mContext, - ColorAndMotionFragment.TOGGLE_FORCE_INVERT - ); + mController = new ToggleForceInvertPreferenceController(mContext, "toggle_force_invert"); } @Test @@ -72,6 +74,30 @@ public class ToggleForceInvertPreferenceControllerTest { .isEqualTo(BasePreferenceController.AVAILABLE); } + @Test + public void updateState_darkModeOn_preferenceEnabled() { + Configuration config = mContext.getResources().getConfiguration(); + config.uiMode = Configuration.UI_MODE_NIGHT_YES; + mContext.getResources().updateConfiguration(config, null); + + Preference preference = mock(Preference.class); + mController.updateState(preference); + + verify(preference).setEnabled(true); + } + + @Test + public void updateState_darkModeOff_preferenceDisabled() { + Configuration config = mContext.getResources().getConfiguration(); + config.uiMode = Configuration.UI_MODE_NIGHT_NO; + mContext.getResources().updateConfiguration(config, null); + + Preference preference = mock(Preference.class); + mController.updateState(preference); + + verify(preference).setEnabled(false); + } + @Test public void settingOff_reflectsCorrectValue() { setEnabled(false); diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java index 3bfe8197b1f..81a72694592 100644 --- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java @@ -64,7 +64,6 @@ import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricUtils; -import com.android.settings.flags.Flags; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; @@ -403,9 +402,7 @@ public class FaceEnrollIntroductionTest { assertThat(getGlifLayout(mActivity).getDescriptionText().toString()).isEqualTo( mContext.getString( - Flags.biometricsOnboardingEducation() - ? R.string.security_settings_face_enroll_introduction_message_class3_2 - : R.string.security_settings_face_enroll_introduction_message_class3)); + R.string.security_settings_face_enroll_introduction_message_class3)); assertThat(mActivity.findViewById(R.id.info_row_less_secure).getVisibility()).isEqualTo( View.GONE); } diff --git a/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java index 115f642d19b..d8c09786a5d 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AmbientVolumePreferenceTest.java @@ -41,8 +41,8 @@ import androidx.preference.PreferenceViewHolder; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; -import com.android.settings.widget.SeekBarPreference; import com.android.settingslib.bluetooth.AmbientVolumeUi; +import com.android.settingslib.widget.SliderPreference; import org.junit.Before; import org.junit.Rule; @@ -99,13 +99,13 @@ public class AmbientVolumePreferenceTest { slider.setMax(4); if (side == SIDE_LEFT) { slider.setKey(KEY_LEFT_SLIDER); - slider.setProgress(TEST_LEFT_VOLUME_LEVEL); + slider.setValue(TEST_LEFT_VOLUME_LEVEL); } else if (side == SIDE_RIGHT) { slider.setKey(KEY_RIGHT_SLIDER); - slider.setProgress(TEST_RIGHT_VOLUME_LEVEL); + slider.setValue(TEST_RIGHT_VOLUME_LEVEL); } else { slider.setKey(KEY_UNIFIED_SLIDER); - slider.setProgress(TEST_UNIFIED_VOLUME_LEVEL); + slider.setValue(TEST_UNIFIED_VOLUME_LEVEL); } }); @@ -223,7 +223,7 @@ public class AmbientVolumePreferenceTest { private void assertControlUiCorrect() { final boolean expanded = mPreference.isExpanded(); - Map sliders = mPreference.getSliders(); + Map sliders = mPreference.getSliders(); assertThat(sliders.get(SIDE_UNIFIED).isVisible()).isEqualTo(!expanded); assertThat(sliders.get(SIDE_LEFT).isVisible()).isEqualTo(expanded); assertThat(sliders.get(SIDE_RIGHT).isVisible()).isEqualTo(expanded); diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java index 4e3c742e284..d0177a8c2a7 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java @@ -56,6 +56,8 @@ public class BluetoothDetailsHearingDeviceControllerTest extends private BluetoothDetailsHearingAidsPresetsController mPresetsController; @Mock private BluetoothDetailsHearingDeviceSettingsController mHearingDeviceSettingsController; + @Mock + private BluetoothDetailsHearingDeviceInputRoutingController mInputRoutingController; private BluetoothDetailsHearingDeviceController mHearingDeviceController; @@ -67,7 +69,7 @@ public class BluetoothDetailsHearingDeviceControllerTest extends mHearingDeviceController = new BluetoothDetailsHearingDeviceController(mContext, mFragment, mLocalManager, mCachedDevice, mLifecycle); mHearingDeviceController.setSubControllers(mHearingDeviceSettingsController, - mPresetsController); + mPresetsController, mInputRoutingController); } @Test @@ -84,6 +86,13 @@ public class BluetoothDetailsHearingDeviceControllerTest extends assertThat(mHearingDeviceController.isAvailable()).isTrue(); } + @Test + public void isAvailable_inputRoutingControllersAvailable_returnFalse() { + when(mInputRoutingController.isAvailable()).thenReturn(true); + + assertThat(mHearingDeviceController.isAvailable()).isTrue(); + } + @Test public void isAvailable_noControllersAvailable_returnFalse() { when(mHearingDeviceSettingsController.isAvailable()).thenReturn(false); @@ -146,4 +155,24 @@ public class BluetoothDetailsHearingDeviceControllerTest extends assertThat(mHearingDeviceController.getSubControllers().stream().anyMatch( c -> c instanceof BluetoothDetailsAmbientVolumePreferenceController)).isFalse(); } + + @Test + @RequiresFlagsEnabled( + com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_INPUT_ROUTING_CONTROL) + public void initSubControllers_flagEnabled_inputRoutingControllerExist() { + mHearingDeviceController.initSubControllers(false); + + assertThat(mHearingDeviceController.getSubControllers().stream().anyMatch( + c -> c instanceof BluetoothDetailsHearingDeviceInputRoutingController)).isTrue(); + } + + @Test + @RequiresFlagsDisabled( + com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_INPUT_ROUTING_CONTROL) + public void initSubControllers_flagDisabled_inputRoutingControllerNotExist() { + mHearingDeviceController.initSubControllers(false); + + assertThat(mHearingDeviceController.getSubControllers().stream().anyMatch( + c -> c instanceof BluetoothDetailsHearingDeviceInputRoutingController)).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingControllerTest.java new file mode 100644 index 00000000000..dc4924da6d7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceInputRoutingControllerTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 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.bluetooth; + +import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP; +import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceInputRoutingController.KEY_HEARING_DEVICE_INPUT_ROUTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothDevice; +import android.media.AudioDeviceInfo; +import android.media.AudioManager; + +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settings.bluetooth.HearingDeviceInputRoutingPreference.InputRoutingValue; +import com.android.settingslib.bluetooth.HapClientProfile; + +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 java.util.Collections; +import java.util.List; + +/** Tests for {@link BluetoothDetailsHearingDeviceInputRoutingController}. */ + +@RunWith(RobolectricTestRunner.class) +public class BluetoothDetailsHearingDeviceInputRoutingControllerTest extends + BluetoothDetailsControllerTestBase { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + private static final String TEST_ADDRESS = "55:66:77:88:99:AA"; + + @Mock + private BluetoothDevice mBluetoothDevice; + @Mock + private HapClientProfile mHapClientProfile; + @Spy + private AudioManager mAudioManager; + + private BluetoothDetailsHearingDeviceInputRoutingController mController; + + @Override + public void setUp() { + super.setUp(); + + mContext = spy(ApplicationProvider.getApplicationContext()); + mAudioManager = spy(mContext.getSystemService(AudioManager.class)); + when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager); + setupDevice(makeDefaultDeviceConfig()); + when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice); + PreferenceCategory deviceControls = new PreferenceCategory(mContext); + deviceControls.setKey(KEY_HEARING_DEVICE_GROUP); + mScreen.addPreference(deviceControls); + mController = new BluetoothDetailsHearingDeviceInputRoutingController(mContext, + mFragment, mCachedDevice, mLifecycle); + } + + @Test + public void init_getExpectedPreference() { + mController.init(mScreen); + + Preference pref = mScreen.findPreference(KEY_HEARING_DEVICE_INPUT_ROUTING); + assertThat(pref.getKey()).isEqualTo(KEY_HEARING_DEVICE_INPUT_ROUTING); + } + + @Test + public void init_setPreferredMicrophoneTrue_expectedSummary() { + when(mBluetoothDevice.isMicrophonePreferredForCalls()).thenReturn(true); + + mController.init(mScreen); + + Preference pref = mScreen.findPreference(KEY_HEARING_DEVICE_INPUT_ROUTING); + assertThat(pref.getSummary().toString()).isEqualTo(mContext.getString( + R.string.bluetooth_hearing_device_input_routing_hearing_device_option)); + } + + @Test + public void init_setPreferredMicrophoneFalse_expectedSummary() { + when(mBluetoothDevice.isMicrophonePreferredForCalls()).thenReturn(false); + mController.init(mScreen); + + Preference pref = mScreen.findPreference(KEY_HEARING_DEVICE_INPUT_ROUTING); + assertThat(pref.getSummary().toString()).isEqualTo(mContext.getString( + R.string.bluetooth_hearing_device_input_routing_builtin_option)); + } + + @Test + public void onInputRoutingUpdated_hearingDevice_setMicrophonePreferredForCallsTrue() { + mController.init(mScreen); + + mController.onInputRoutingUpdated(InputRoutingValue.HEARING_DEVICE); + + verify(mBluetoothDevice).setMicrophonePreferredForCalls(true); + } + + @Test + public void onInputRoutingUpdated_builtin_setMicrophonePreferredForCallsFalse() { + mController.init(mScreen); + + mController.onInputRoutingUpdated(InputRoutingValue.BUILTIN_MIC); + + verify(mBluetoothDevice).setMicrophonePreferredForCalls(false); + } + + @Test + public void isAvailable_validInput_supportHapProfile_returnTrue() { + when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); + AudioDeviceInfo[] mockInfo = new AudioDeviceInfo[] {mockTestAddressInfo(TEST_ADDRESS)}; + when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(mockInfo); + when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile)); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_notSupportHapProfile_returnFalse() { + when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); + AudioDeviceInfo[] mockInfo = new AudioDeviceInfo[] {mockTestAddressInfo(TEST_ADDRESS)}; + when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn(mockInfo); + when(mCachedDevice.getProfiles()).thenReturn(Collections.emptyList()); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_notValidInputDevice_returnFalse() { + when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); + when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)).thenReturn( + new AudioDeviceInfo[] {}); + when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile)); + + assertThat(mController.isAvailable()).isFalse(); + } + + private AudioDeviceInfo mockTestAddressInfo(String address) { + final AudioDeviceInfo info = mock(AudioDeviceInfo.class); + when(info.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET); + when(info.getAddress()).thenReturn(address); + return info; + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreferenceTest.java new file mode 100644 index 00000000000..e5778245ef4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceInputRoutingPreferenceTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 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.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RadioGroup; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settings.bluetooth.HearingDeviceInputRoutingPreference.InputRoutingValue; + +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.RobolectricTestRunner; + +/** Tests for {@link HearingDeviceInputRoutingPreference}. */ +@RunWith(RobolectricTestRunner.class) +public class HearingDeviceInputRoutingPreferenceTest { + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private HearingDeviceInputRoutingPreference mPreference; + private TestInputRoutingCallback mTestInputRoutingCallback; + private View mDialogView; + + @Before + public void setup() { + mDialogView = LayoutInflater.from(mContext).inflate( + R.layout.hearing_device_input_routing_dialog, null); + mTestInputRoutingCallback = spy(new TestInputRoutingCallback()); + mPreference = new HearingDeviceInputRoutingPreference(mContext); + } + + @Test + public void onClick_checkToBuiltinMic_callbackWithBuiltinSpeaker() { + mPreference.setChecked(InputRoutingValue.HEARING_DEVICE); + mPreference.setInputRoutingCallback(mTestInputRoutingCallback); + mPreference.onBindDialogView(mDialogView); + RadioGroup radioGroup = mDialogView.requireViewById(R.id.input_routing_group); + Dialog dialog = mPreference.getDialog(); + + radioGroup.check(R.id.input_from_builtin_mic); + mPreference.onClick(dialog, DialogInterface.BUTTON_POSITIVE); + + verify(mTestInputRoutingCallback).onInputRoutingUpdated(InputRoutingValue.BUILTIN_MIC); + } + + @Test + public void setChecked_checkNoChange_noCallback() { + mPreference.setChecked(InputRoutingValue.HEARING_DEVICE); + mPreference.setInputRoutingCallback(mTestInputRoutingCallback); + mPreference.onBindDialogView(mDialogView); + Dialog dialog = mPreference.getDialog(); + + mPreference.setChecked(InputRoutingValue.HEARING_DEVICE); + mPreference.onClick(dialog, DialogInterface.BUTTON_POSITIVE); + + verify(mTestInputRoutingCallback, never()).onInputRoutingUpdated(anyInt()); + } + + @Test + public void setChecked_builtinMic_expectedSummary() { + mPreference.setChecked(InputRoutingValue.BUILTIN_MIC); + + assertThat(mPreference.getSummary().toString()).isEqualTo( + mContext.getString(R.string.bluetooth_hearing_device_input_routing_builtin_option)); + } + + @Test + public void setChecked_hearingDevice_expectedSummary() { + mPreference.setChecked(InputRoutingValue.HEARING_DEVICE); + + assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString( + R.string.bluetooth_hearing_device_input_routing_hearing_device_option)); + } + + private static class TestInputRoutingCallback implements + HearingDeviceInputRoutingPreference.InputRoutingCallback { + + @Override + public void onInputRoutingUpdated(int selectedInputRoutingUiValue) {} + } +} diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeSettingsFragmentTest.java new file mode 100644 index 00000000000..4bd1daa5bdf --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeSettingsFragmentTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 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 android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settings.testutils.XmlTestUtils; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.util.List; + +/** Tests for {@link DarkModeSettingsFragment}. */ +@RunWith(RobolectricTestRunner.class) +public class DarkModeSettingsFragmentTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private DarkModeSettingsFragment mFragment; + + @Before + public void setUp() { + mFragment = new DarkModeSettingsFragment(); + } + + @Test + public void getMetricsCategory_returnsCorrectCategory() { + assertThat(mFragment.getMetricsCategory()).isEqualTo( + SettingsEnums.DARK_UI_SETTINGS); + } + + @Test + public void getPreferenceScreenResId_returnsCorrectXml() { + assertThat(mFragment.getPreferenceScreenResId()).isEqualTo( + R.xml.dark_mode_settings); + } + + @Test + public void getLogTag_returnsCorrectTag() { + assertThat(mFragment.getLogTag()).isEqualTo("DarkModeSettingsFrag"); + } + + @Test + @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR) + public void getNonIndexableKeys_forceInvertEnabled_existInXmlLayout() { + final List niks = DarkModeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + final List keys = + XmlTestUtils.getKeysFromPreferenceXml(mContext, + R.xml.dark_mode_settings); + + assertThat(niks).doesNotContain("toggle_force_invert"); + assertThat(keys).containsAtLeastElementsIn(niks); + } + + @Test + @RequiresFlagsDisabled(FLAG_FORCE_INVERT_COLOR) + public void getNonIndexableKeys_existInXmlLayout() { + final List niks = DarkModeSettingsFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + final List keys = + XmlTestUtils.getKeysFromPreferenceXml(mContext, + R.xml.dark_mode_settings); + + assertThat(niks).contains("toggle_force_invert"); + assertThat(keys).containsAtLeastElementsIn(niks); + } +} diff --git a/tests/spa_unit/src/com/android/settings/wifi/repository/WifiRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/wifi/repository/WifiRepositoryTest.kt index dae3617c37e..f39e70d9322 100644 --- a/tests/spa_unit/src/com/android/settings/wifi/repository/WifiRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/wifi/repository/WifiRepositoryTest.kt @@ -21,8 +21,9 @@ import android.content.Intent import android.net.wifi.WifiManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull +import com.android.settingslib.spa.testutils.lastWithTimeoutOrNull import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking import org.junit.Test @@ -33,16 +34,25 @@ class WifiRepositoryTest { private val context: Context = ApplicationProvider.getApplicationContext() - private val mockWifiStateChangedActionFlow = flowOf(Intent().apply { - putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED) - }) - - private val repository = WifiRepository(context, mockWifiStateChangedActionFlow) - @Test - fun wifiStateFlow() = runBlocking { - val wifiState = repository.wifiStateFlow().firstWithTimeoutOrNull() + fun wifiStateFlow_enabled() = runBlocking { + val wifiStateChangedIntent = + Intent().apply { + putExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_ENABLED) + } + val repository = WifiRepository(context, flowOf(wifiStateChangedIntent)) + + val wifiState = repository.wifiStateFlow().lastWithTimeoutOrNull() assertThat(wifiState).isEqualTo(WifiManager.WIFI_STATE_ENABLED) } + + @Test + fun wifiStateFlow_unknown() = runBlocking { + val repository = WifiRepository(context, emptyFlow()) + + val wifiState = repository.wifiStateFlow().lastWithTimeoutOrNull() + + assertThat(wifiState).isEqualTo(WifiManager.WIFI_STATE_UNKNOWN) + } } diff --git a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java index 8304e5d6083..e65a2491a7d 100644 --- a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java +++ b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java @@ -182,7 +182,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest { @Test public void updateState_PreferenceShouldEnabled() { mController.updateState(mPreference); - assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isEnabled()).isFalse(); } @Test diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java index b025abdf06a..4728c4541ef 100644 --- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java +++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressCategoryControllerTest.java @@ -24,12 +24,17 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.os.Looper; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.flags.Flags; + import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -45,6 +50,8 @@ public class TermsOfAddressCategoryControllerTest { private TermsOfAddressCategoryController mTermsOfAddressCategoryController; private Locale mCacheLocale; + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -65,6 +72,7 @@ public class TermsOfAddressCategoryControllerTest { } @Test + @DisableFlags(Flags.FLAG_REGIONAL_PREFERENCES_API_ENABLED) public void getAvailabilityStatus_returnAvailable() { Locale.setDefault(Locale.forLanguageTag("fr-FR"));