From d077ca6dd9a973ef9025f77de2b86b8e12bd2c8a Mon Sep 17 00:00:00 2001 From: Chun-Ku Lin Date: Thu, 29 Aug 2024 20:33:18 +0000 Subject: [PATCH 1/7] Pass null looper if the looper is not prepared in the calling thread **Root cause** The PreferenceController can be constructed by the SettingsSearchIndexablesProvider where the looper of the thread is not prepared. This result in not able to construct the PreferenceController that will be used as part of the SettingsSearch. Currently, if the SettingsSearchIndexablesProvider is not able to construct the PreferenceController defined in xml, it would just silently failed. Test: atest SettingsUnitTests Test: atest SettingsRoboTests Flag: EXEMPT low risk bugfix Bug: 352622249 Change-Id: I72a4ce24ec6842b9efe067e3cb7d1c73cd98a566 --- .../KeyboardVibrationTogglePreferenceController.java | 4 +++- .../VibrationMainSwitchPreferenceController.java | 4 +++- .../settings/accessibility/VibrationPreferenceConfig.java | 3 ++- .../VibrationRampingRingerTogglePreferenceController.java | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java index 818eb5e4bab..45a19b78bdf 100644 --- a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java +++ b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java @@ -27,6 +27,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.VibrationAttributes; import android.os.Vibrator; import android.provider.Settings; @@ -69,7 +70,8 @@ public class KeyboardVibrationTogglePreferenceController extends TogglePreferenc public KeyboardVibrationTogglePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mVibrator = context.getSystemService(Vibrator.class); - mContentObserver = new ContentObserver(new Handler(/* async= */ true)) { + Handler handler = Looper.myLooper() != null ? new Handler(/* async= */ true) : null; + mContentObserver = new ContentObserver(handler) { @Override public void onChange(boolean selfChange, Uri uri) { if (uri.equals(MAIN_VIBRATION_SWITCH_URI)) { diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java b/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java index db184bf9d73..5b553e3df61 100644 --- a/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java +++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java @@ -23,6 +23,7 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.VibrationAttributes; import android.os.Vibrator; import android.provider.Settings; @@ -49,7 +50,8 @@ public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchP public VibrationMainSwitchPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mVibrator = context.getSystemService(Vibrator.class); - mSettingObserver = new ContentObserver(new Handler(/* async= */ true)) { + Handler handler = Looper.myLooper() != null ? new Handler(/* async= */ true) : null; + mSettingObserver = new ContentObserver(handler) { @Override public void onChange(boolean selfChange, Uri uri) { updateState(mSwitchPreference); diff --git a/src/com/android/settings/accessibility/VibrationPreferenceConfig.java b/src/com/android/settings/accessibility/VibrationPreferenceConfig.java index ec1fab1af72..3887cece9fe 100644 --- a/src/com/android/settings/accessibility/VibrationPreferenceConfig.java +++ b/src/com/android/settings/accessibility/VibrationPreferenceConfig.java @@ -27,6 +27,7 @@ import android.database.ContentObserver; import android.media.AudioManager; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; @@ -165,7 +166,7 @@ public abstract class VibrationPreferenceConfig { /** Creates observer for given preference. */ public SettingObserver(VibrationPreferenceConfig preferenceConfig) { - super(new Handler(/* async= */ true)); + super(Looper.myLooper() != null ? new Handler(/* async= */ true) : null); mUri = Settings.System.getUriFor(preferenceConfig.getSettingKey()); if (preferenceConfig.isRestrictedByRingerModeSilent()) { diff --git a/src/com/android/settings/accessibility/VibrationRampingRingerTogglePreferenceController.java b/src/com/android/settings/accessibility/VibrationRampingRingerTogglePreferenceController.java index 149bed35373..69b1e1503f6 100644 --- a/src/com/android/settings/accessibility/VibrationRampingRingerTogglePreferenceController.java +++ b/src/com/android/settings/accessibility/VibrationRampingRingerTogglePreferenceController.java @@ -21,6 +21,7 @@ import android.database.ContentObserver; import android.media.AudioManager; import android.net.Uri; import android.os.Handler; +import android.os.Looper; import android.os.Vibrator; import android.provider.DeviceConfig; import android.provider.Settings; @@ -74,7 +75,8 @@ public class VibrationRampingRingerTogglePreferenceController mRingVibrationPreferenceConfig = new RingVibrationPreferenceConfig(context); mRingSettingObserver = new VibrationPreferenceConfig.SettingObserver( mRingVibrationPreferenceConfig); - mSettingObserver = new ContentObserver(new Handler(/* async= */ true)) { + Handler handler = Looper.myLooper() != null ? new Handler(/* async= */ true) : null; + mSettingObserver = new ContentObserver(handler) { @Override public void onChange(boolean selfChange, Uri uri) { updateState(mPreference); From f4be805b6da965af84f9f990fe8e6e294aa23193 Mon Sep 17 00:00:00 2001 From: Chun-Ku Lin Date: Fri, 30 Aug 2024 00:28:04 +0000 Subject: [PATCH 2/7] Use the correct package name for DevelopmentMemtagFooterPreferenceController The package name doesn't match the one used in development_memtag_page.xml. This would result in the controller can't be found when the DashboardFragment trying to instantiate the controller defined in xml. Bug: 245624194 Flag: EXEMPT low risk bugfix Test: Examing the log and verify there is no "Cannot instantiate controller from reflection" for DevelopmentMemtagFooterPreferenceController Change-Id: I63ba96d587525c08cf1409883e2bd09bc85bfc41 --- .../DevelopmentMemtagFooterPreferenceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java b/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java index a5612ca82b2..f2c9f59392d 100644 --- a/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java +++ b/src/com/android/settings/development/DevelopmentMemtagFooterPreferenceController.java @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.settings.security; +package com.android.settings.development; import android.content.Context; import android.text.TextUtils; From 50c954923f34c88ad4460817b4ca64e8fabc2cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= Date: Fri, 30 Aug 2024 11:03:45 +0200 Subject: [PATCH 3/7] Support (non-editable) display of DND with a filter != PRIORITY Whenever setInterruptionFilter() is called with NONE or ALARMS, the Do Not Disturb mode now shows the current policy (nothing allowed or alarms/media allowed), instead of the normal PRIORITY policy. This policy is read-only in the UI since it cannot be customized. This should be, or at least become, pretty rare (with small exceptions, apps targeting V that call setInterruptionFilter() will use an implicit mode instead of changing the global zen mode, plus using these filters is quite nonstandard in itself). Fixes: 361586248 Test: atest & manual (toggling DND via cmd shell) Flag: android.app.modes_ui Change-Id: If2439480235d30aa310ad8925341183b9761784c --- ...nterruptionFilterPreferenceController.java | 6 +- .../modes/SetupInterstitialActivity.java | 2 +- .../ZenModeAppsLinkPreferenceController.java | 4 +- ...ModeDisplayEffectPreferenceController.java | 2 +- ...enModeDisplayLinkPreferenceController.java | 2 +- ...enModeExitAtAlarmPreferenceController.java | 3 +- .../notification/modes/ZenModeFragment.java | 2 +- ...nModeNotifVisLinkPreferenceController.java | 2 +- .../ZenModeOtherLinkPreferenceController.java | 4 +- ...ZenModePeopleLinkPreferenceController.java | 4 +- .../modes/ZenModeSummaryHelper.java | 68 +++++++++---------- ...ModeTriggerUpdatePreferenceController.java | 4 +- .../ZenModesListPreferenceController.java | 2 +- ...ruptionFilterPreferenceControllerTest.java | 21 ++++++ ...nModeAppsLinkPreferenceControllerTest.java | 15 ++++ ...deDisplayLinkPreferenceControllerTest.java | 22 ++++++ ...deExitAtAlarmPreferenceControllerTest.java | 4 ++ ...ModeOtherLinkPreferenceControllerTest.java | 22 ++++++ ...odePeopleLinkPreferenceControllerTest.java | 15 ++++ 19 files changed, 151 insertions(+), 53 deletions(-) diff --git a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java index d69b3173fef..e5c65707bb1 100644 --- a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java +++ b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java @@ -44,8 +44,8 @@ class InterruptionFilterPreferenceController extends AbstractZenModePreferenceCo @Override public void updateState(Preference preference, @NonNull ZenMode zenMode) { - preference.setEnabled(zenMode.isEnabled()); - boolean allowingAll = zenMode.getRule().getInterruptionFilter() == INTERRUPTION_FILTER_ALL; + preference.setEnabled(zenMode.isEnabled() && zenMode.canEditPolicy()); + boolean allowingAll = zenMode.getInterruptionFilter() == INTERRUPTION_FILTER_ALL; ((TwoStatePreference) preference).setChecked(allowingAll); preference.setSummary(allowingAll @@ -57,7 +57,7 @@ class InterruptionFilterPreferenceController extends AbstractZenModePreferenceCo public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { final boolean allowAll = ((Boolean) newValue); return saveMode(zenMode -> { - zenMode.getRule().setInterruptionFilter(allowAll + zenMode.setInterruptionFilter(allowAll ? INTERRUPTION_FILTER_ALL : INTERRUPTION_FILTER_PRIORITY); return zenMode; diff --git a/src/com/android/settings/notification/modes/SetupInterstitialActivity.java b/src/com/android/settings/notification/modes/SetupInterstitialActivity.java index c5beb36c11c..fcd5fd5cf00 100644 --- a/src/com/android/settings/notification/modes/SetupInterstitialActivity.java +++ b/src/com/android/settings/notification/modes/SetupInterstitialActivity.java @@ -228,7 +228,7 @@ public class SetupInterstitialActivity extends FragmentActivity { return false; } - modeToUpdate.getRule().setEnabled(true); + modeToUpdate.setEnabled(true); mBackend.updateMode(modeToUpdate); return true; } diff --git a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java index 7b17f0c77e6..c133f515f30 100644 --- a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java @@ -92,7 +92,7 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr @Override public boolean isAvailable(ZenMode zenMode) { - return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL; + return zenMode.getInterruptionFilter() != INTERRUPTION_FILTER_ALL; } @Override @@ -102,7 +102,7 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr preference.setIntent( ZenSubSettingLauncher.forModeFragment(mContext, ZenModeAppsFragment.class, zenMode.getId(), SettingsEnums.ZEN_PRIORITY_MODE).toIntent()); - preference.setEnabled(zenMode.isEnabled()); + preference.setEnabled(zenMode.isEnabled() && zenMode.canEditPolicy()); mZenMode = zenMode; mPreference = (CircularIconsPreference) preference; diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java index b0d395296e9..afd9b76b88a 100644 --- a/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java @@ -74,7 +74,7 @@ class ZenModeDisplayEffectPreferenceController extends AbstractZenModePreference updatedEffects.setShouldUseNightMode(allow); break; } - zenMode.getRule().setDeviceEffects(updatedEffects.build()); + zenMode.setDeviceEffects(updatedEffects.build()); return zenMode; }); } diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java index 57dce89a35c..14c8cb6435b 100644 --- a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java @@ -45,7 +45,7 @@ class ZenModeDisplayLinkPreferenceController extends AbstractZenModePreferenceCo preference.setIntent( ZenSubSettingLauncher.forModeFragment(mContext, ZenModeDisplayFragment.class, zenMode.getId(), SettingsEnums.ZEN_PRIORITY_MODE).toIntent()); - preference.setEnabled(zenMode.isEnabled()); + preference.setEnabled(zenMode.isEnabled() && zenMode.canEditPolicy()); } @Override diff --git a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java index 326bc97715b..18e3fc15c09 100644 --- a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java @@ -50,7 +50,8 @@ class ZenModeExitAtAlarmPreferenceController extends if (mSchedule.exitAtAlarm != exitAtAlarm) { mSchedule.exitAtAlarm = exitAtAlarm; return saveMode(mode -> { - mode.getRule().setConditionId(ZenModeConfig.toScheduleConditionId(mSchedule)); + mode.setCustomModeConditionId(mContext, + ZenModeConfig.toScheduleConditionId(mSchedule)); return mode; }); } diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java index 8eef7083995..08075b464df 100644 --- a/src/com/android/settings/notification/modes/ZenModeFragment.java +++ b/src/com/android/settings/notification/modes/ZenModeFragment.java @@ -171,7 +171,7 @@ public class ZenModeFragment extends ZenModeFragmentBase { } else if (menuItem.getItemId() == DELETE_MODE) { new AlertDialog.Builder(mContext) .setTitle(mContext.getString(R.string.zen_mode_delete_mode_confirmation, - mZenMode.getRule().getName())) + mZenMode.getName())) .setPositiveButton(R.string.zen_mode_schedule_delete, (dialog, which) -> { // start finishing before calling removeMode() so that we diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java index cd1e8c7d3ba..f08a05da256 100644 --- a/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java @@ -41,7 +41,7 @@ class ZenModeNotifVisLinkPreferenceController extends AbstractZenModePreferenceC @Override public boolean isAvailable(ZenMode zenMode) { - return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL; + return zenMode.getInterruptionFilter() != INTERRUPTION_FILTER_ALL; } @Override diff --git a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java index 9613d98eb1e..9adc7681f41 100644 --- a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java @@ -61,7 +61,7 @@ class ZenModeOtherLinkPreferenceController extends AbstractZenModePreferenceCont @Override public boolean isAvailable(ZenMode zenMode) { - return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL; + return zenMode.getInterruptionFilter() != INTERRUPTION_FILTER_ALL; } @Override @@ -70,7 +70,7 @@ class ZenModeOtherLinkPreferenceController extends AbstractZenModePreferenceCont ZenSubSettingLauncher.forModeFragment(mContext, ZenModeOtherFragment.class, zenMode.getId(), SettingsEnums.ZEN_PRIORITY_MODE).toIntent()); - preference.setEnabled(zenMode.isEnabled()); + preference.setEnabled(zenMode.isEnabled() && zenMode.canEditPolicy()); preference.setSummary(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)); ((CircularIconsPreference) preference).setIcons(getSoundIcons(zenMode.getPolicy())); } diff --git a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java index bf554711637..c635ad80028 100644 --- a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java @@ -84,7 +84,7 @@ class ZenModePeopleLinkPreferenceController extends AbstractZenModePreferenceCon @Override public boolean isAvailable(ZenMode zenMode) { - return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL; + return zenMode.getInterruptionFilter() != INTERRUPTION_FILTER_ALL; } @Override @@ -94,7 +94,7 @@ class ZenModePeopleLinkPreferenceController extends AbstractZenModePreferenceCon ZenSubSettingLauncher.forModeFragment(mContext, ZenModePeopleFragment.class, zenMode.getId(), SettingsEnums.ZEN_PRIORITY_MODE).toIntent()); - preference.setEnabled(zenMode.isEnabled()); + preference.setEnabled(zenMode.isEnabled() && zenMode.canEditPolicy()); preference.setSummary(mSummaryHelper.getPeopleSummary(zenMode.getPolicy())); ((CircularIconsPreference) preference).setIcons(getPeopleIcons(zenMode.getPolicy()), PEOPLE_ITEM_EQUIVALENCE); diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java index c5300da0cee..483b8f07d20 100644 --- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java +++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java @@ -209,48 +209,46 @@ class ZenModeSummaryHelper { boolean isFirst = true; List enabledEffects = new ArrayList<>(); if (!zenMode.getPolicy().shouldShowAllVisualEffects() - && zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL) { + && zenMode.getInterruptionFilter() != INTERRUPTION_FILTER_ALL) { enabledEffects.add(getBlockedEffectsSummary(zenMode)); isFirst = false; } - ZenDeviceEffects currEffects = zenMode.getRule().getDeviceEffects(); - if (currEffects != null) { - if (currEffects.shouldDisplayGrayscale()) { - if (isFirst) { - enabledEffects.add(mContext.getString(R.string.mode_grayscale_title)); - } else { - enabledEffects.add(mContext.getString( - R.string.mode_grayscale_title_secondary_list)); - } - isFirst = false; + ZenDeviceEffects currEffects = zenMode.getDeviceEffects(); + if (currEffects.shouldDisplayGrayscale()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_grayscale_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_grayscale_title_secondary_list)); } - if (currEffects.shouldSuppressAmbientDisplay()) { - if (isFirst) { - enabledEffects.add(mContext.getString(R.string.mode_aod_title)); - } else { - enabledEffects.add(mContext.getString( - R.string.mode_aod_title_secondary_list)); - } - isFirst = false; + isFirst = false; + } + if (currEffects.shouldSuppressAmbientDisplay()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_aod_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_aod_title_secondary_list)); } - if (currEffects.shouldDimWallpaper()) { - if (isFirst) { - enabledEffects.add(mContext.getString(R.string.mode_wallpaper_title)); - } else { - enabledEffects.add(mContext.getString( - R.string.mode_wallpaper_title_secondary_list)); - } - isFirst = false; + isFirst = false; + } + if (currEffects.shouldDimWallpaper()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_wallpaper_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_wallpaper_title_secondary_list)); } - if (currEffects.shouldUseNightMode()) { - if (isFirst) { - enabledEffects.add(mContext.getString(R.string.mode_dark_theme_title)); - } else { - enabledEffects.add(mContext.getString( - R.string.mode_dark_theme_title_secondary_list)); - } - isFirst = false; + isFirst = false; + } + if (currEffects.shouldUseNightMode()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_dark_theme_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_dark_theme_title_secondary_list)); } + isFirst = false; } int numCategories = enabledEffects.size(); diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java index f2302c0b335..193363585f1 100644 --- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java @@ -87,7 +87,7 @@ class ZenModeTriggerUpdatePreferenceController extends AbstractZenModePreference mModeName = zenMode.getName(); PrimarySwitchPreference triggerPref = (PrimarySwitchPreference) preference; - triggerPref.setChecked(zenMode.getRule().isEnabled()); + triggerPref.setChecked(zenMode.isEnabled()); triggerPref.setOnPreferenceChangeListener(mSwitchChangeListener); if (zenMode.isSystemOwned()) { setUpForSystemOwnedTrigger(triggerPref, zenMode); @@ -213,7 +213,7 @@ class ZenModeTriggerUpdatePreferenceController extends AbstractZenModePreference private void setModeEnabled(boolean enabled) { saveMode((zenMode) -> { - if (enabled != zenMode.getRule().isEnabled()) { + if (enabled != zenMode.isEnabled()) { zenMode.getRule().setEnabled(enabled); } return zenMode; diff --git a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java index 5e36469f39c..75d4ee3aaaa 100644 --- a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java @@ -118,7 +118,7 @@ class ZenModesListPreferenceController extends BasePreferenceController for (ZenMode mode : mBackend.getModes()) { SearchIndexableRaw data = new SearchIndexableRaw(mContext); data.key = mode.getId(); - data.title = mode.getRule().getName(); + data.title = mode.getName(); data.screenTitle = res.getString(R.string.zen_modes_list_title); rawData.add(data); } diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java index 777d213142f..8653d958a6a 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.notification.modes; import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.service.notification.ZenPolicy.STATE_DISALLOW; @@ -67,6 +68,26 @@ public final class InterruptionFilterPreferenceControllerTest { mController = new InterruptionFilterPreferenceController(mContext, "something", mBackend); } + @Test + public void updateState_dnd_enabled() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE; + + mController.updateState(preference, dnd); + + verify(preference).setEnabled(true); + } + + @Test + public void updateState_specialDnd_disabled() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true); + + mController.updateState(preference, specialDnd); + + verify(preference).setEnabled(false); + } + @Test public void testUpdateState_disabled() { TwoStatePreference preference = mock(TwoStatePreference.class); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java index 4148fa3cd33..fa83f309db1 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java @@ -16,6 +16,7 @@ package com.android.settings.notification.modes; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID; @@ -149,6 +150,20 @@ public final class ZenModeAppsLinkPreferenceControllerTest { assertThat(mController.isAvailable()).isTrue(); } + @Test + public void updateState_dnd_enabled() { + ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE; + mController.updateState(mPreference, dnd); + assertThat(mPreference.isEnabled()).isTrue(); + } + + @Test + public void updateState_specialDnd_disabled() { + ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true); + mController.updateState(mPreference, specialDnd); + assertThat(mPreference.isEnabled()).isFalse(); + } + @Test public void testUpdateState_disabled() { ZenMode zenMode = new TestModeBuilder() diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java index 7cf0109d436..05486e09d3c 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.notification.modes; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -63,6 +65,26 @@ public final class ZenModeDisplayLinkPreferenceControllerTest { mContext, "something", mBackend, mHelperBackend); } + @Test + public void updateState_dnd_enabled() { + Preference preference = mock(Preference.class); + ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE; + + mController.updateState(preference, dnd); + + verify(preference).setEnabled(true); + } + + @Test + public void updateState_specialDnd_disabled() { + Preference preference = mock(Preference.class); + ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true); + + mController.updateState(preference, specialDnd); + + verify(preference).setEnabled(false); + } + @Test public void testUpdateState_disabled() { Preference preference = mock(Preference.class); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java index 3efa5f0e7aa..c949fb8adc1 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.notification.modes; +import static android.service.notification.SystemZenRules.PACKAGE_ANDROID; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; @@ -77,6 +79,7 @@ public class ZenModeExitAtAlarmPreferenceControllerTest { scheduleInfo.exitAtAlarm = false; ZenMode mode = new TestModeBuilder() + .setPackage(PACKAGE_ANDROID) .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo)) .build(); @@ -105,6 +108,7 @@ public class ZenModeExitAtAlarmPreferenceControllerTest { scheduleInfo.exitAtAlarm = true; ZenMode mode = new TestModeBuilder() + .setPackage(PACKAGE_ANDROID) .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo)) .build(); mPrefController.updateZenMode(preference, mode); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java index 3db70fa67bc..38790b2729c 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.notification.modes; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; @@ -61,6 +63,26 @@ public final class ZenModeOtherLinkPreferenceControllerTest { mContext, "something", mHelperBackend); } + @Test + public void updateState_dnd_enabled() { + CircularIconsPreference preference = mock(CircularIconsPreference.class); + ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE; + + mController.updateState(preference, dnd); + + verify(preference).setEnabled(true); + } + + @Test + public void updateState_specialDnd_disabled() { + CircularIconsPreference preference = mock(CircularIconsPreference.class); + ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true); + + mController.updateState(preference, specialDnd); + + verify(preference).setEnabled(false); + } + @Test public void updateState_disabled() { CircularIconsPreference pref = mock(CircularIconsPreference.class); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java index 8555d710fa0..85fd0043039 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java @@ -16,6 +16,7 @@ package com.android.settings.notification.modes; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS; @@ -116,6 +117,20 @@ public final class ZenModePeopleLinkPreferenceControllerTest { anyBoolean())).thenReturn(new ColorDrawable(Color.BLACK)); } + @Test + public void updateState_dnd_enabled() { + ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE; + mController.updateState(mPreference, dnd); + assertThat(mPreference.isEnabled()).isTrue(); + } + + @Test + public void updateState_specialDnd_disabled() { + ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true); + mController.updateState(mPreference, specialDnd); + assertThat(mPreference.isEnabled()).isFalse(); + } + @Test public void updateState_disabled() { ZenMode zenMode = new TestModeBuilder() From 355ee0a1ee65686391d62a984f357196ae476994 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Mon, 2 Sep 2024 17:54:41 +0800 Subject: [PATCH 4/7] Refine CrossSimCalling updating Currently, this setting depends on whether wifi calling is supported, since wifi calling could takes some time to provision after sim is turned on, this state could be wrong when set cross sim calling. Use wifiCallingReadyFlow() to retrieve the latest state, and update setting when state changes. Fix: 352736998 Fix: 348529996 Flag: EXEMPT bug fix Test: manual - by turn on / off sim Change-Id: Id4b099e0c5d7cf47b007f37e6f278d1c46e58659 --- .../telephony/ims/ImsMmTelRepository.kt | 9 +-- .../wificalling/CrossSimCallingViewModel.kt | 75 +++++++++++++------ .../wificalling/WifiCallingRepository.kt | 9 --- .../wificalling/WifiCallingRepositoryTest.kt | 16 ---- 4 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt b/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt index c5d1200a1d4..e8912048f58 100644 --- a/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt +++ b/src/com/android/settings/network/telephony/ims/ImsMmTelRepository.kt @@ -27,6 +27,7 @@ import android.telephony.ims.ImsStateCallback import android.telephony.ims.RegistrationManager import android.telephony.ims.feature.MmTelFeature import android.util.Log +import androidx.annotation.VisibleForTesting import kotlin.coroutines.resume import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor @@ -53,11 +54,6 @@ interface ImsMmTelRepository { @AccessNetworkConstants.TransportType transportType: Int, ): Flow - suspend fun isSupported( - @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int, - @AccessNetworkConstants.TransportType transportType: Int, - ): Boolean - suspend fun setCrossSimCallingEnabled(enabled: Boolean) } @@ -143,7 +139,8 @@ class ImsMmTelRepositoryImpl( override fun isSupportedFlow(capability: Int, transportType: Int): Flow = imsReadyFlow().map { imsReady -> imsReady && isSupported(capability, transportType) } - override suspend fun isSupported( + @VisibleForTesting + suspend fun isSupported( @MmTelFeature.MmTelCapabilities.MmTelCapability capability: Int, @AccessNetworkConstants.TransportType transportType: Int, ): Boolean = withContext(Dispatchers.Default) { diff --git a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt index dda147b549e..cab27caa2b8 100644 --- a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt +++ b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt @@ -21,6 +21,7 @@ import android.app.settings.SettingsEnums import android.telephony.CarrierConfigManager import android.telephony.SubscriptionManager import android.telephony.TelephonyManager +import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.android.settings.R @@ -34,6 +35,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -43,9 +45,8 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.plus @OptIn(ExperimentalCoroutinesApi::class) -class CrossSimCallingViewModel( - private val application: Application, -) : AndroidViewModel(application) { +class CrossSimCallingViewModel(private val application: Application) : + AndroidViewModel(application) { private val subscriptionRepository = SubscriptionRepository(application) private val dataSubscriptionRepository = DataSubscriptionRepository(application) @@ -61,38 +62,45 @@ class CrossSimCallingViewModel( subscriptionRepository.activeSubscriptionIdListFlow(), dataSubscriptionRepository.defaultDataSubscriptionIdFlow(), ) { activeSubIds, defaultDataSubId -> - activeSubIds to crossSimCallNewEnabled(activeSubIds, defaultDataSubId) + updatableSubIdsFlow(activeSubIds) to + crossSimCallNewEnabledFlow(activeSubIds, defaultDataSubId) } - .flatMapLatest { (activeSubIds, newEnabledFlow) -> - newEnabledFlow.map { newEnabled -> activeSubIds to newEnabled } + .flatMapLatest { (updatableSubIdsFlow, crossSimCallNewEnabledFlow) -> + combine(updatableSubIdsFlow, crossSimCallNewEnabledFlow) { + updatableSubIds, + newEnabled -> + updatableSubIds to newEnabled + } } .distinctUntilChanged() - .onEach { (activeSubIds, newEnabled) -> - updateCrossSimCalling(activeSubIds, newEnabled) + .conflate() + .onEach { (updatableSubIds, newEnabled) -> + Log.d(TAG, "updatableSubIds: $updatableSubIds newEnabled: $newEnabled") + updateCrossSimCalling(updatableSubIds, newEnabled) } .launchIn(scope) } } - private suspend fun updateCrossSimCalling(activeSubIds: List, newEnabled: Boolean) { - metricsFeatureProvider.action( - application, - SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT, - newEnabled, - ) - activeSubIds - .filter { subId -> crossSimAvailable(subId) } - .forEach { subId -> - ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled) + private fun updatableSubIdsFlow(activeSubIds: List): Flow> { + val updatableSubIdFlows = + activeSubIds.map { subId -> + WifiCallingRepository(application, subId).wifiCallingReadyFlow().map { isReady -> + subId.takeIf { isReady && isCrossSimImsAvailable(subId) } + } } + return combine(updatableSubIdFlows) { subIds -> subIds.filterNotNull() } + .distinctUntilChanged() + .conflate() } - private suspend fun crossSimAvailable(subId: Int): Boolean = - WifiCallingRepository(application, subId).isWifiCallingSupported() && - carrierConfigRepository.getBoolean( - subId, CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL) + private fun isCrossSimImsAvailable(subId: Int) = + carrierConfigRepository.getBoolean( + subId, + CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, + ) - private fun crossSimCallNewEnabled( + private fun crossSimCallNewEnabledFlow( activeSubscriptionIdList: List, defaultDataSubId: Int, ): Flow { @@ -102,8 +110,27 @@ class CrossSimCallingViewModel( .filter { subId -> subId != defaultDataSubId } .map { subId -> mobileDataRepository.isMobileDataPolicyEnabledFlow( - subId, TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) + subId, + TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, + ) } return combine(isMobileDataPolicyEnabledFlows) { true in it } + .distinctUntilChanged() + .conflate() + } + + private suspend fun updateCrossSimCalling(subIds: List, newEnabled: Boolean) { + metricsFeatureProvider.action( + application, + SettingsEnums.ACTION_UPDATE_CROSS_SIM_CALLING_ON_AUTO_DATA_SWITCH_EVENT, + newEnabled, + ) + for (subId in subIds) { + ImsMmTelRepositoryImpl(application, subId).setCrossSimCallingEnabled(newEnabled) + } + } + + companion object { + private const val TAG = "CrossSimCallingVM" } } diff --git a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt index 6af0559adb1..a6a47fadb34 100644 --- a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt +++ b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt @@ -29,9 +29,7 @@ import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl import com.android.settings.network.telephony.telephonyManager import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.withContext interface IWifiCallingRepository { /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */ @@ -75,11 +73,4 @@ constructor( tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN, ) - - suspend fun isWifiCallingSupported(): Boolean = withContext(Dispatchers.Default) { - imsMmTelRepository.isSupported( - capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, - transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN, - ) - } } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt index f0a23eb92c9..9b71465a4db 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/wificalling/WifiCallingRepositoryTest.kt @@ -102,22 +102,6 @@ class WifiCallingRepositoryTest { assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) } - @Test - fun isWifiCallingSupported() = runBlocking { - mockImsMmTelRepository.stub { - onBlocking { - isSupported( - capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, - transportType = AccessNetworkConstants.TRANSPORT_TYPE_WLAN, - ) - } doReturn true - } - - val isSupported = repository.isWifiCallingSupported() - - assertThat(isSupported).isTrue() - } - private fun mockUseWfcHomeModeForRoaming(config: Boolean) { mockCarrierConfigManager.stub { on { From f6ce11eb4bf166fafd6487c129a0156cd2fb1146 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Mon, 2 Sep 2024 18:00:22 +0800 Subject: [PATCH 5/7] [Audiosharing] Add new strings Test: atest Flag: com.android.settingslib.flags.enable_le_audio_sharing Bug: 305620450 Change-Id: I15c6a0dd701d091e763429be91d77c281538b604 --- res-product/values/strings.xml | 8 ++++++++ res/values/strings.xml | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml index 83963cbee14..d5ef1c888f6 100644 --- a/res-product/values/strings.xml +++ b/res-product/values/strings.xml @@ -758,8 +758,16 @@ To listen to an audio stream, first connect headphones that support LE Audio to this phone. To listen to an audio stream, first connect headphones that support LE Audio to this tablet. To listen to an audio stream, first connect headphones that support LE Audio to this device. + + To listen to an audio stream, first connect headphones that support LE Audio to this phone. Learn more + To listen to an audio stream, first connect headphones that support LE Audio to this tablet. Learn more + To listen to an audio stream, first connect headphones that support LE Audio to this device. Learn more This phone doesn\'t support LE Audio, which is needed to listen to audio streams. This tablet doesn\'t support LE Audio, which is needed to listen to audio streams. This device doesn\'t support LE Audio, which is needed to listen to audio streams. + + To start sharing audio, first connect LE Audio headphones to your phone. Learn more about compatible devices + To start sharing audio, first connect LE Audio headphones to your tablet. Learn more about compatible devices + To start sharing audio, first connect LE Audio headphones to your device. Learn more about compatible devices diff --git a/res/values/strings.xml b/res/values/strings.xml index 7b7dd196e91..5a4f55bc22c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13749,6 +13749,8 @@ Connect a compatible device To start sharing audio, first connect LE Audio headphones to your phone + + Switch to %1$s Connect to a LE audio stream @@ -13838,6 +13840,8 @@ Can\u0027t edit password while sharing. To change the password, first turn off audio sharing. QR code scanner + + Need help? From db89eaa0a2471c419d22da299564c12e211fae72 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Mon, 2 Sep 2024 18:50:13 +0800 Subject: [PATCH 6/7] [Audiosharing] Update cancel btn label. When broadcast is off, the negative btn of share audio dialog should be "Switch to xxx" Test: atest Flag: com.android.settingslib.flags.enable_le_audio_sharing Bug: 305620450 Change-Id: I8006e2901b8f859d1ee86cbf12d81401e004aa0f --- .../AudioSharingJoinDialogFragment.java | 6 +++++- .../AudioSharingJoinDialogFragmentTest.java | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java index 95712411627..ef461ebf1a0 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java @@ -158,7 +158,11 @@ public class AudioSharingJoinDialogFragment extends InstrumentedDialogFragment { dismiss(); }) .setCustomNegativeButton( - R.string.audio_sharing_no_thanks_button_label, + getMetricsCategory() == SettingsEnums.DIALOG_START_AUDIO_SHARING + ? getString( + R.string.audio_sharing_switch_active_button_label, + newDeviceName) + : getString(R.string.audio_sharing_no_thanks_button_label), v -> { if (sListener != null) { sListener.onCancelClick(); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java index 2310d75d876..32f9e83cbc8 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragmentTest.java @@ -31,6 +31,7 @@ import android.content.Context; import android.platform.test.flag.junit.SetFlagsRule; import android.util.Pair; import android.view.View; +import android.widget.Button; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; @@ -180,6 +181,7 @@ public class AudioSharingJoinDialogFragmentTest { @Test public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + when(mBroadcast.isEnabled(null)).thenReturn(true); AudioSharingJoinDialogFragment.show( mParent, new ArrayList<>(), @@ -192,6 +194,10 @@ public class AudioSharingJoinDialogFragmentTest { assertThat(dialog.isShowing()).isTrue(); ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); assertThat(shadowDialog.getMessage().toString()).isEqualTo(TEST_DEVICE_NAME2); + Button btnView = dialog.findViewById(R.id.negative_btn); + assertThat(btnView).isNotNull(); + assertThat(btnView.getText().toString()) + .isEqualTo(mParent.getString(R.string.audio_sharing_no_thanks_button_label)); } @Test @@ -212,6 +218,13 @@ public class AudioSharingJoinDialogFragmentTest { R.string.audio_sharing_share_dialog_subtitle, TEST_DEVICE_NAME1, TEST_DEVICE_NAME2)); + Button btnView = dialog.findViewById(R.id.negative_btn); + assertThat(btnView).isNotNull(); + assertThat(btnView.getText().toString()) + .isEqualTo( + mParent.getString( + R.string.audio_sharing_switch_active_button_label, + TEST_DEVICE_NAME2)); } @Test From ed519640fafab8be09c1c6b3b7a4ad749e7b6964 Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Mon, 2 Sep 2024 06:10:56 +0000 Subject: [PATCH 7/7] Add hearing device related logs in Settings 1. The HAC toggle on/off event 2. The "See more devices" button click in hearing device pairing page 3. The preset changed event in Bluetooth device details page Flag: EXEMPT, simple log Bug: 361206470 Test: manually check on go/atomviewer Test: atest BluetoothDetailsHearingAidsPresetsControllerTest Change-Id: I743ea136ec4cb3370c0463df865db830e73e7997 --- ...HearingAidCompatibilityPreferenceController.java | 3 +++ ...ViewAllBluetoothDevicesPreferenceController.java | 3 +++ ...luetoothDetailsHearingAidsPresetsController.java | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java b/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java index 727cdd53d57..821fddd956f 100644 --- a/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java +++ b/src/com/android/settings/accessibility/HearingAidCompatibilityPreferenceController.java @@ -25,6 +25,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.flags.Flags; import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.overlay.FeatureFactory; /** Preference controller for Hearing Aid Compatibility (HAC) settings */ public class HearingAidCompatibilityPreferenceController extends TogglePreferenceController { @@ -73,6 +74,8 @@ public class HearingAidCompatibilityPreferenceController extends TogglePreferenc @Override public boolean setChecked(boolean isChecked) { + FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().changed( + getMetricsCategory(), getPreferenceKey(), isChecked ? 1 : 0); setAudioParameterHacEnabled(isChecked); return Settings.System.putInt(mContext.getContentResolver(), Settings.System.HEARING_AID, (isChecked ? HAC_ENABLED : HAC_DISABLED)); diff --git a/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceController.java b/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceController.java index 622d5d8d3c4..b35575e2b2f 100644 --- a/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceController.java +++ b/src/com/android/settings/accessibility/ViewAllBluetoothDevicesPreferenceController.java @@ -26,6 +26,7 @@ import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.overlay.FeatureFactory; /** Preference controller for all bluetooth device preference. */ public class ViewAllBluetoothDevicesPreferenceController extends BasePreferenceController { @@ -52,6 +53,8 @@ public class ViewAllBluetoothDevicesPreferenceController extends BasePreferenceC @Override public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), getPreferenceKey())) { + FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().clicked( + getMetricsCategory(), getPreferenceKey()); launchConnectedDevicePage(); return true; } diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingAidsPresetsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingAidsPresetsController.java index f7ccc610870..25a99eda5a2 100644 --- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingAidsPresetsController.java +++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingAidsPresetsController.java @@ -38,6 +38,7 @@ import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.HapClientProfile; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -111,6 +112,7 @@ public class BluetoothDetailsHearingAidsPresetsController extends final int index = listPreference.findIndexOfValue(value); final String presetName = listPreference.getEntries()[index].toString(); final int presetIndex = Integer.parseInt(value); + logPresetChangedIfNeeded(); listPreference.setSummary(presetName); if (DEBUG) { Log.d(TAG, "onPreferenceChange" @@ -373,4 +375,15 @@ public class BluetoothDetailsHearingAidsPresetsController extends mHapClientProfile.selectPreset(memberDevice.getDevice(), presetIndex); } } + + private void logPresetChangedIfNeeded() { + if (mPreference == null || mPreference.getEntries() == null) { + return; + } + if (mFragment instanceof BluetoothDeviceDetailsFragment) { + int category = ((BluetoothDeviceDetailsFragment) mFragment).getMetricsCategory(); + FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().changed(category, + getPreferenceKey(), mPreference.getEntries().length); + } + } }