From 200da8978f45d2afeeaa8f5a5a03603102d7809e Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Fri, 4 May 2018 08:54:53 -0400 Subject: [PATCH 01/21] DND settings redesign Test: robotests Change-Id: I7b980218feea28e945994c8b7f8a934df6bc11f9 Bug: 78447976 --- AndroidManifest.xml | 21 +-- res/values/strings.xml | 77 +++++++-- res/xml/zen_mode_behavior_settings.xml | 70 --------- res/xml/zen_mode_calls_settings.xml | 43 +++++ .../zen_mode_msg_event_reminder_settings.xml | 46 ++++++ ...n_mode_restrict_notifications_settings.xml | 4 +- res/xml/zen_mode_settings.xml | 75 +++++---- res/xml/zen_mode_sound_vibration_settings.xml | 44 ++++++ .../core/gateway/SettingsGateway.java | 4 +- ...odeBehaviorCallsPreferenceController.java} | 9 +- ...odeBehaviorFooterPreferenceController.java | 73 ++++----- ...rMsgEventReminderPreferenceController.java | 53 +++++++ ...ModeBehaviorSoundPreferenceController.java | 52 ++++++ .../notification/ZenModeCallsSettings.java | 93 +++++++++++ ...a => ZenModeMsgEventReminderSettings.java} | 18 +-- .../notification/ZenModeSettings.java | 113 +++++++++---- .../ZenModeSoundVibrationSettings.java | 90 +++++++++++ ...BehaviorCallsPreferenceControllerTest.java | 79 ++++++++++ ...ehaviorFooterPreferenceControllerTest.java | 16 +- ...EventReminderPreferenceControllerTest.java | 79 ++++++++++ ...BehaviorSoundPreferenceControllerTest.java | 79 ++++++++++ .../notification/ZenModeSettingsTest.java | 148 ++++++++++++++---- 22 files changed, 1027 insertions(+), 259 deletions(-) delete mode 100644 res/xml/zen_mode_behavior_settings.xml create mode 100644 res/xml/zen_mode_calls_settings.xml create mode 100644 res/xml/zen_mode_msg_event_reminder_settings.xml create mode 100644 res/xml/zen_mode_sound_vibration_settings.xml rename src/com/android/settings/notification/{ZenModeBehaviorPreferenceController.java => ZenModeBehaviorCallsPreferenceController.java} (83%) create mode 100644 src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceController.java create mode 100644 src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceController.java create mode 100644 src/com/android/settings/notification/ZenModeCallsSettings.java rename src/com/android/settings/notification/{ZenModeBehaviorSettings.java => ZenModeMsgEventReminderSettings.java} (78%) create mode 100644 src/com/android/settings/notification/ZenModeSoundVibrationSettings.java create mode 100644 tests/robotests/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceControllerTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 52a18b9aa53..b59ee56e643 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -727,6 +727,10 @@ + + + + @@ -752,23 +756,6 @@ - - - - - - - - - Allow visual signals - - Restrict notifications + + When Do Not Disturb is turned on + Notifications - - When Do Not Disturb is turned on - Mute notifications + Show notifications silently - Show notifications but mute sounds & vibrations + Notifications will be muted - When new notifications arrive your phone won\u2019t make a sound or vibration + When notifications arrive, your phone won\u2019t make a sound or vibrate. - Hide & mute notifications + Hide notifications - Notifications will not appear at all + You won\u2019t see new or existing notifications - You won\u2019t see new or existing notifications when Do Not Disturb is on. However, notifications needed for basic phone activity and status will still appear. + Your phone won\u2019t show new or existing notifications, and won\u2019t make a sound or vibrate. Notifications won\u2019t appear when you swipe down from the top of your screen.\n\nKeep in mind, critical notifications for phone activity and status will still appear. Custom @@ -7362,6 +7361,35 @@ %d rules can turn on automatically + + Behavior + + Exceptions + + Schedule + + + Sound & vibration + + When Do Not Disturb is on, sound and vibration will be muted, except for the items you allow above. + + Mute all except + + Muted + + Not muted + + Muted, but allow %1$s + + Muted, but allow %1$s and %2$s + + Muted, but allow %1$s, %2$s, and %3$s + + + Messages, events & reminders + + When Do Not Disturb is on, messages, reminders, and events will muted, except for the items you allow above. You can adjust messages settings to allow your friends, family, or other contacts to reach you. + Update @@ -7893,14 +7921,17 @@ Calls + + When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you. + Messages - All messages + Messages - Selected messages + Some messages From anyone @@ -7911,6 +7942,15 @@ From starred contacts only + + From starred contacts and repeat callers + + + From contacts and repeat callers + + + From repeat callers only + None @@ -7930,14 +7970,23 @@ Events - All callers + anyone - Selected callers + contacts + + + starred contacts Repeat callers + + From %1$s only + + + From %1$s and %2$s + If the same person calls a second time within a %d minute period diff --git a/res/xml/zen_mode_behavior_settings.xml b/res/xml/zen_mode_behavior_settings.xml deleted file mode 100644 index 8426d9154c2..00000000000 --- a/res/xml/zen_mode_behavior_settings.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml new file mode 100644 index 00000000000..01ca499c44d --- /dev/null +++ b/res/xml/zen_mode_calls_settings.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/xml/zen_mode_msg_event_reminder_settings.xml b/res/xml/zen_mode_msg_event_reminder_settings.xml new file mode 100644 index 00000000000..40b25139af8 --- /dev/null +++ b/res/xml/zen_mode_msg_event_reminder_settings.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/zen_mode_restrict_notifications_settings.xml b/res/xml/zen_mode_restrict_notifications_settings.xml index d5243f62943..e024ab9d974 100644 --- a/res/xml/zen_mode_restrict_notifications_settings.xml +++ b/res/xml/zen_mode_restrict_notifications_settings.xml @@ -18,11 +18,11 @@ + android:title="@string/zen_mode_restrict_notifications_title"> + android:title="@string/zen_mode_settings_category"> - - - - - - - - - - - - - - - - + android:key="zen_mode_settings_category_behavior" + android:title="@string/zen_category_behavior"> + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/zen_mode_sound_vibration_settings.xml b/res/xml/zen_mode_sound_vibration_settings.xml new file mode 100644 index 00000000000..b3b81395ed9 --- /dev/null +++ b/res/xml/zen_mode_sound_vibration_settings.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index ced158eb3e0..aab3512cf15 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -106,9 +106,10 @@ import com.android.settings.notification.NotificationStation; import com.android.settings.notification.SoundSettings; import com.android.settings.notification.ZenAccessSettings; import com.android.settings.notification.ZenModeAutomationSettings; -import com.android.settings.notification.ZenModeBehaviorSettings; +import com.android.settings.notification.ZenModeMsgEventReminderSettings; import com.android.settings.notification.ZenModeBlockedEffectsSettings; import com.android.settings.notification.ZenModeEventRuleSettings; +import com.android.settings.notification.ZenModeRestrictNotificationsSettings; import com.android.settings.notification.ZenModeScheduleRuleSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.password.ChooseLockPassword; @@ -220,7 +221,6 @@ public class SettingsGateway { ApnSettings.class.getName(), ApnEditor.class.getName(), WifiCallingSettings.class.getName(), - ZenModeBehaviorSettings.class.getName(), ZenModeScheduleRuleSettings.class.getName(), ZenModeEventRuleSettings.class.getName(), ZenModeBlockedEffectsSettings.class.getName(), diff --git a/src/com/android/settings/notification/ZenModeBehaviorPreferenceController.java b/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceController.java similarity index 83% rename from src/com/android/settings/notification/ZenModeBehaviorPreferenceController.java rename to src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceController.java index 908ec04ad74..4ab14379e92 100644 --- a/src/com/android/settings/notification/ZenModeBehaviorPreferenceController.java +++ b/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceController.java @@ -22,13 +22,13 @@ import androidx.preference.Preference; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.lifecycle.Lifecycle; -public class ZenModeBehaviorPreferenceController extends +public class ZenModeBehaviorCallsPreferenceController extends AbstractZenModePreferenceController implements PreferenceControllerMixin { - protected static final String KEY_BEHAVIOR_SETTINGS = "zen_mode_behavior_settings"; + protected static final String KEY_BEHAVIOR_SETTINGS = "zen_mode_calls_settings"; private final ZenModeSettings.SummaryBuilder mSummaryBuilder; - public ZenModeBehaviorPreferenceController(Context context, Lifecycle lifecycle) { + public ZenModeBehaviorCallsPreferenceController(Context context, Lifecycle lifecycle) { super(context, KEY_BEHAVIOR_SETTINGS, lifecycle); mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context); } @@ -47,7 +47,6 @@ public class ZenModeBehaviorPreferenceController extends public void updateState(Preference preference) { super.updateState(preference); - preference.setSummary(mSummaryBuilder.getBehaviorSettingSummary(getPolicy(), - getZenMode())); + preference.setSummary(mSummaryBuilder.getCallsSettingSummary(getPolicy())); } } diff --git a/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceController.java b/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceController.java index a36c2661b86..1a6a3b4357c 100644 --- a/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceController.java +++ b/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceController.java @@ -16,8 +16,8 @@ package com.android.settings.notification; -import android.content.Context; import android.content.ComponentName; +import android.content.Context; import android.net.Uri; import android.provider.Settings; import android.service.notification.ZenModeConfig; @@ -30,14 +30,17 @@ import com.android.settingslib.core.lifecycle.Lifecycle; public class ZenModeBehaviorFooterPreferenceController extends AbstractZenModePreferenceController { protected static final String KEY = "footer_preference"; + private final int mTitleRes; - public ZenModeBehaviorFooterPreferenceController(Context context, Lifecycle lifecycle) { + public ZenModeBehaviorFooterPreferenceController(Context context, Lifecycle lifecycle, + int titleRes) { super(context, KEY, lifecycle); + mTitleRes = titleRes; } @Override public boolean isAvailable() { - return isDeprecatedZenMode(getZenMode()); + return true; } @Override @@ -48,45 +51,45 @@ public class ZenModeBehaviorFooterPreferenceController extends AbstractZenModePr @Override public void updateState(Preference preference) { super.updateState(preference); - - boolean isAvailable = isAvailable(); - preference.setVisible(isAvailable); - if (isAvailable) { - preference.setTitle(getFooterText()); - } - + preference.setTitle(getFooterText()); } protected String getFooterText() { - ZenModeConfig config = getZenModeConfig(); + if (isDeprecatedZenMode(getZenMode())) { + ZenModeConfig config = getZenModeConfig(); - // DND turned on by manual rule with deprecated zen mode - if (config.manualRule != null && - isDeprecatedZenMode(config.manualRule.zenMode)) { - final Uri id = config.manualRule.conditionId; - if (config.manualRule.enabler != null) { - // app triggered manual rule - String appOwner = mZenModeConfigWrapper.getOwnerCaption(config.manualRule.enabler); - if (!appOwner.isEmpty()) { - return mContext.getString(R.string.zen_mode_app_set_behavior, appOwner); - } - } else { - return mContext.getString(R.string.zen_mode_qs_set_behavior); - } - } - - // DND turned on by an automatic rule with deprecated zen mode - for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) { - if (automaticRule.isAutomaticActive() && isDeprecatedZenMode(automaticRule.zenMode)) { - ComponentName component = automaticRule.component; - if (component != null) { - return mContext.getString(R.string.zen_mode_app_set_behavior, - component.getPackageName()); + // DND turned on by manual rule with deprecated zen mode + if (config.manualRule != null && + isDeprecatedZenMode(config.manualRule.zenMode)) { + final Uri id = config.manualRule.conditionId; + if (config.manualRule.enabler != null) { + // app triggered manual rule + String appOwner = mZenModeConfigWrapper.getOwnerCaption( + config.manualRule.enabler); + if (!appOwner.isEmpty()) { + return mContext.getString(R.string.zen_mode_app_set_behavior, appOwner); + } + } else { + return mContext.getString(R.string.zen_mode_qs_set_behavior); } } - } - return mContext.getString(R.string.zen_mode_unknown_app_set_behavior); + // DND turned on by an automatic rule with deprecated zen mode + for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) { + if (automaticRule.isAutomaticActive() && isDeprecatedZenMode( + automaticRule.zenMode)) { + ComponentName component = automaticRule.component; + if (component != null) { + return mContext.getString(R.string.zen_mode_app_set_behavior, + component.getPackageName()); + } + } + } + + return mContext.getString(R.string.zen_mode_unknown_app_set_behavior); + } else { + return mContext.getString(mTitleRes); + } } private boolean isDeprecatedZenMode(int zenMode) { diff --git a/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceController.java b/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceController.java new file mode 100644 index 00000000000..d11baee8e8b --- /dev/null +++ b/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceController.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 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.notification; + +import android.content.Context; +import androidx.preference.Preference; + +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.core.lifecycle.Lifecycle; + +public class ZenModeBehaviorMsgEventReminderPreferenceController extends + AbstractZenModePreferenceController implements PreferenceControllerMixin { + + protected static final String KEY_BEHAVIOR_SETTINGS = "zen_mode_msg_event_reminder_settings"; + private final ZenModeSettings.SummaryBuilder mSummaryBuilder; + + public ZenModeBehaviorMsgEventReminderPreferenceController(Context context, + Lifecycle lifecycle) { + super(context, KEY_BEHAVIOR_SETTINGS, lifecycle); + mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context); + } + + @Override + public String getPreferenceKey() { + return KEY_BEHAVIOR_SETTINGS; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + preference.setSummary(mSummaryBuilder.getMsgEventReminderSettingSummary(getPolicy())); + } +} diff --git a/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceController.java b/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceController.java new file mode 100644 index 00000000000..3d250639e18 --- /dev/null +++ b/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceController.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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.notification; + +import android.content.Context; +import androidx.preference.Preference; + +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.core.lifecycle.Lifecycle; + +public class ZenModeBehaviorSoundPreferenceController extends + AbstractZenModePreferenceController implements PreferenceControllerMixin { + + protected static final String KEY_BEHAVIOR_SETTINGS = "zen_sound_vibration_settings"; + private final ZenModeSettings.SummaryBuilder mSummaryBuilder; + + public ZenModeBehaviorSoundPreferenceController(Context context, Lifecycle lifecycle) { + super(context, KEY_BEHAVIOR_SETTINGS, lifecycle); + mSummaryBuilder = new ZenModeSettings.SummaryBuilder(context); + } + + @Override + public String getPreferenceKey() { + return KEY_BEHAVIOR_SETTINGS; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + preference.setSummary(mSummaryBuilder.getSoundSettingSummary(getPolicy())); + } +} diff --git a/src/com/android/settings/notification/ZenModeCallsSettings.java b/src/com/android/settings/notification/ZenModeCallsSettings.java new file mode 100644 index 00000000000..3c7f0c96c9c --- /dev/null +++ b/src/com/android/settings/notification/ZenModeCallsSettings.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 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.notification; + +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +@SearchIndexable +public class ZenModeCallsSettings extends ZenModeSettingsBase implements Indexable { + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getLifecycle()); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { + List controllers = new ArrayList<>(); + controllers.add(new ZenModeCallsPreferenceController(context, lifecycle)); + // TODO: is a controller needed for a pref that just launches an external activity? + // or can the contacts app insert this setting themselves? + controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle, + context.getResources().getInteger(com.android.internal.R.integer + .config_zen_repeat_callers_threshold))); + controllers.add(new ZenModeBehaviorFooterPreferenceController( + context, lifecycle, R.string.zen_mode_calls_footer)); + return controllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.zen_mode_calls_settings; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.NOTIFICATION_ZEN_MODE_PRIORITY; + } + + /** + * For Search. + */ + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.zen_mode_calls_settings; + result.add(sir); + return result; + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + return keys; + } + + @Override + public List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, null); + } + }; +} diff --git a/src/com/android/settings/notification/ZenModeBehaviorSettings.java b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java similarity index 78% rename from src/com/android/settings/notification/ZenModeBehaviorSettings.java rename to src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java index 5a084e88e2d..5a00c47473c 100644 --- a/src/com/android/settings/notification/ZenModeBehaviorSettings.java +++ b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 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. @@ -31,7 +31,7 @@ import java.util.ArrayList; import java.util.List; @SearchIndexable -public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Indexable { +public class ZenModeMsgEventReminderSettings extends ZenModeSettingsBase implements Indexable { @Override protected List createPreferenceControllers(Context context) { @@ -41,23 +41,17 @@ public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Inde private static List buildPreferenceControllers(Context context, Lifecycle lifecycle) { List controllers = new ArrayList<>(); - controllers.add(new ZenModeAlarmsPreferenceController(context, lifecycle)); - controllers.add(new ZenModeMediaPreferenceController(context, lifecycle)); - controllers.add(new ZenModeSystemPreferenceController(context, lifecycle)); controllers.add(new ZenModeEventsPreferenceController(context, lifecycle)); controllers.add(new ZenModeRemindersPreferenceController(context, lifecycle)); controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle)); - controllers.add(new ZenModeCallsPreferenceController(context, lifecycle)); - controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle, - context.getResources().getInteger(com.android.internal.R.integer - .config_zen_repeat_callers_threshold))); - controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle)); + controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle, + R.string.zen_msg_event_reminder_footer)); return controllers; } @Override protected int getPreferenceScreenResId() { - return R.xml.zen_mode_behavior_settings; + return R.xml.zen_mode_msg_event_reminder_settings; } @Override @@ -77,7 +71,7 @@ public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Inde final ArrayList result = new ArrayList<>(); final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.zen_mode_behavior_settings; + sir.xmlResId = R.xml.zen_mode_msg_event_reminder_settings; result.add(sir); return result; } diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java index ddbfcb64879..3fb5a4b9be6 100644 --- a/src/com/android/settings/notification/ZenModeSettings.java +++ b/src/com/android/settings/notification/ZenModeSettings.java @@ -16,6 +16,15 @@ package com.android.settings.notification; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM; + import android.app.AutomaticZenRule; import android.app.FragmentManager; import android.app.NotificationManager; @@ -42,19 +51,13 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Predicate; @SearchIndexable public class ZenModeSettings extends ZenModeSettingsBase { - private static final String KEY_SOUND = "zen_effect_sound"; - @Override public void onResume() { super.onResume(); - CheckBoxPreference soundPreference = - (CheckBoxPreference) getPreferenceScreen().findPreference(KEY_SOUND); - if (soundPreference != null) { - soundPreference.setChecked(true); - } } @Override @@ -80,7 +83,9 @@ public class ZenModeSettings extends ZenModeSettingsBase { private static List buildPreferenceControllers(Context context, Lifecycle lifecycle, FragmentManager fragmentManager) { List controllers = new ArrayList<>(); - controllers.add(new ZenModeBehaviorPreferenceController(context, lifecycle)); + controllers.add(new ZenModeBehaviorMsgEventReminderPreferenceController(context, lifecycle)); + controllers.add(new ZenModeBehaviorSoundPreferenceController(context, lifecycle)); + controllers.add(new ZenModeBehaviorCallsPreferenceController(context, lifecycle)); controllers.add(new ZenModeBlockedEffectsPreferenceController(context, lifecycle)); controllers.add(new ZenModeDurationPreferenceController(context, lifecycle, fragmentManager)); @@ -100,19 +105,63 @@ public class ZenModeSettings extends ZenModeSettingsBase { // these should match NotificationManager.Policy#ALL_PRIORITY_CATEGORIES private static final int[] ALL_PRIORITY_CATEGORIES = { - Policy.PRIORITY_CATEGORY_ALARMS, - Policy.PRIORITY_CATEGORY_MEDIA, - Policy.PRIORITY_CATEGORY_SYSTEM, - Policy.PRIORITY_CATEGORY_REMINDERS, - Policy.PRIORITY_CATEGORY_EVENTS, - Policy.PRIORITY_CATEGORY_MESSAGES, - Policy.PRIORITY_CATEGORY_CALLS, - Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, + PRIORITY_CATEGORY_ALARMS, + PRIORITY_CATEGORY_MEDIA, + PRIORITY_CATEGORY_SYSTEM, + PRIORITY_CATEGORY_MESSAGES, + PRIORITY_CATEGORY_EVENTS, + PRIORITY_CATEGORY_REMINDERS, + PRIORITY_CATEGORY_CALLS, + PRIORITY_CATEGORY_REPEAT_CALLERS, }; - String getBehaviorSettingSummary(Policy policy, int zenMode) { - List enabledCategories = getEnabledCategories(policy); + String getSoundSettingSummary(Policy policy) { + List enabledCategories = getEnabledCategories(policy, + category -> PRIORITY_CATEGORY_ALARMS == category + || PRIORITY_CATEGORY_MEDIA == category + || PRIORITY_CATEGORY_SYSTEM == category); + int numCategories = enabledCategories.size(); + if (numCategories == 0) { + return mContext.getString(R.string.zen_sound_all_muted); + } else if (numCategories == 1) { + return mContext.getString(R.string.zen_sound_one_allowed, + enabledCategories.get(0).toLowerCase()); + } else if (numCategories == 2) { + return mContext.getString(R.string.zen_sound_two_allowed, + enabledCategories.get(0).toLowerCase(), + enabledCategories.get(1).toLowerCase()); + } else if (numCategories == 3) { + return mContext.getString(R.string.zen_sound_three_allowed, + enabledCategories.get(0).toLowerCase(), + enabledCategories.get(1).toLowerCase(), + enabledCategories.get(2).toLowerCase()); + } else { + return mContext.getString(R.string.zen_sound_none_muted); + } + } + String getCallsSettingSummary(Policy policy) { + List enabledCategories = getEnabledCategories(policy, + category -> PRIORITY_CATEGORY_CALLS == category + || PRIORITY_CATEGORY_REPEAT_CALLERS == category); + int numCategories = enabledCategories.size(); + if (numCategories == 0) { + return mContext.getString(R.string.zen_mode_no_exceptions); + } else if (numCategories == 1) { + return mContext.getString(R.string.zen_mode_calls_summary_one, + enabledCategories.get(0).toLowerCase()); + } else { + return mContext.getString(R.string.zen_mode_calls_summary_two, + enabledCategories.get(0).toLowerCase(), + enabledCategories.get(1).toLowerCase()); + } + } + + String getMsgEventReminderSettingSummary(Policy policy) { + List enabledCategories = getEnabledCategories(policy, + category -> PRIORITY_CATEGORY_EVENTS == category + || PRIORITY_CATEGORY_REMINDERS == category + || PRIORITY_CATEGORY_MESSAGES == category); int numCategories = enabledCategories.size(); if (numCategories == 0) { return mContext.getString(R.string.zen_mode_no_exceptions); @@ -201,22 +250,19 @@ public class ZenModeSettings extends ZenModeSettingsBase { return count; } - private List getEnabledCategories(Policy policy) { + private List getEnabledCategories(Policy policy, + Predicate filteredCategories) { List enabledCategories = new ArrayList<>(); for (int category : ALL_PRIORITY_CATEGORIES) { - if (isCategoryEnabled(policy, category)) { - if (category == Policy.PRIORITY_CATEGORY_ALARMS) { + if (filteredCategories.test(category) && isCategoryEnabled(policy, category)) { + if (category == PRIORITY_CATEGORY_ALARMS) { enabledCategories.add(mContext.getString(R.string.zen_mode_alarms)); - } else if (category == Policy.PRIORITY_CATEGORY_MEDIA) { + } else if (category == PRIORITY_CATEGORY_MEDIA) { enabledCategories.add(mContext.getString( R.string.zen_mode_media)); - } else if (category == Policy.PRIORITY_CATEGORY_SYSTEM) { + } else if (category == PRIORITY_CATEGORY_SYSTEM) { enabledCategories.add(mContext.getString( R.string.zen_mode_system)); - } else if (category == Policy.PRIORITY_CATEGORY_REMINDERS) { - enabledCategories.add(mContext.getString(R.string.zen_mode_reminders)); - } else if (category == Policy.PRIORITY_CATEGORY_EVENTS) { - enabledCategories.add(mContext.getString(R.string.zen_mode_events)); } else if (category == Policy.PRIORITY_CATEGORY_MESSAGES) { if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) { enabledCategories.add(mContext.getString( @@ -225,13 +271,20 @@ public class ZenModeSettings extends ZenModeSettingsBase { enabledCategories.add(mContext.getString( R.string.zen_mode_selected_messages)); } + } else if (category == Policy.PRIORITY_CATEGORY_EVENTS) { + enabledCategories.add(mContext.getString(R.string.zen_mode_events)); + } else if (category == Policy.PRIORITY_CATEGORY_REMINDERS) { + enabledCategories.add(mContext.getString(R.string.zen_mode_reminders)); } else if (category == Policy.PRIORITY_CATEGORY_CALLS) { if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_ANY) { enabledCategories.add(mContext.getString( R.string.zen_mode_all_callers)); + } else if (policy.priorityCallSenders == Policy.PRIORITY_SENDERS_CONTACTS){ + enabledCategories.add(mContext.getString( + R.string.zen_mode_contacts_callers)); } else { enabledCategories.add(mContext.getString( - R.string.zen_mode_selected_callers)); + R.string.zen_mode_starred_callers)); } } else if (category == Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) { if (!enabledCategories.contains(mContext.getString( @@ -248,10 +301,6 @@ public class ZenModeSettings extends ZenModeSettingsBase { private boolean isCategoryEnabled(Policy policy, int categoryType) { return (policy.priorityCategories & categoryType) != 0; } - - private boolean isEffectSuppressed(Policy policy, int effect) { - return (policy.suppressedVisualEffects & effect) != 0; - } } /** diff --git a/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java b/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java new file mode 100644 index 00000000000..b72460c8a34 --- /dev/null +++ b/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 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.notification; + +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +@SearchIndexable +public class ZenModeSoundVibrationSettings extends ZenModeSettingsBase implements Indexable { + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getLifecycle()); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { + List controllers = new ArrayList<>(); + controllers.add(new ZenModeAlarmsPreferenceController(context, lifecycle)); + controllers.add(new ZenModeMediaPreferenceController(context, lifecycle)); + controllers.add(new ZenModeSystemPreferenceController(context, lifecycle)); + controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle, + R.string.zen_sound_footer)); + return controllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.zen_mode_sound_vibration_settings; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.NOTIFICATION_ZEN_MODE_PRIORITY; + } + + /** + * For Search. + */ + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.zen_mode_sound_vibration_settings; + result.add(sir); + return result; + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + return keys; + } + + @Override + public List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, null); + } + }; +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceControllerTest.java new file mode 100644 index 00000000000..b3a4b90b098 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorCallsPreferenceControllerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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.notification; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import androidx.preference.Preference; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public final class ZenModeBehaviorCallsPreferenceControllerTest { + + private ZenModeBehaviorCallsPreferenceController mController; + @Mock + private NotificationManager mNotificationManager; + @Mock + private NotificationManager.Policy mPolicy; + + private Context mContext; + @Mock + private ZenModeBackend mBackend; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + + mContext = RuntimeEnvironment.application; + when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy); + + mController = new ZenModeBehaviorCallsPreferenceController( + mContext, mock(Lifecycle.class)); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + } + + @Test + public void testIsAvailable() { + assertTrue(mController.isAvailable()); + } + + @Test + public void testHasSummary() { + Preference pref = mock(Preference.class); + mController.updateState(pref); + verify(pref).setSummary(any()); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceControllerTest.java index 760efb281c5..0bf82144260 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorFooterPreferenceControllerTest.java @@ -41,6 +41,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import android.util.ArrayMap; +import com.android.settings.R; import com.android.settings.notification.AbstractZenModePreferenceController.ZenModeConfigWrapper; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -77,6 +78,7 @@ public class ZenModeBehaviorFooterPreferenceControllerTest { private Context mContext; private ContentResolver mContentResolver; + private int mTitleResId = R.string.zen_sound_title; @Before public void setup() { @@ -88,8 +90,8 @@ public class ZenModeBehaviorFooterPreferenceControllerTest { mContentResolver = RuntimeEnvironment.application.getContentResolver(); when(mNotificationManager.getZenModeConfig()).thenReturn(mZenModeConfig); - mController = - new ZenModeBehaviorFooterPreferenceController(mContext, mock(Lifecycle.class)); + mController = new ZenModeBehaviorFooterPreferenceController( + mContext, mock(Lifecycle.class), mTitleResId); ReflectionHelpers.setField(mController, "mZenModeConfigWrapper", mConfigWrapper); when(mPreferenceScreen.findPreference(mController.getPreferenceKey())) @@ -112,13 +114,13 @@ public class ZenModeBehaviorFooterPreferenceControllerTest { @Test public void priorityOnly_footerIsAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); - assertFalse(mController.isAvailable()); + assertTrue(mController.isAvailable()); } @Test - public void zenModeOff_footerIsNotAvailable() { + public void zenModeOff_footerIsAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF); - assertFalse(mController.isAvailable()); + assertTrue(mController.isAvailable()); } @Test @@ -126,7 +128,7 @@ public class ZenModeBehaviorFooterPreferenceControllerTest { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF); mController.updateState(mockPref); - verify(mockPref, never()).setTitle(any(String.class)); + verify(mockPref).setTitle(mContext.getString(mTitleResId)); } @Test @@ -134,7 +136,7 @@ public class ZenModeBehaviorFooterPreferenceControllerTest { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); mController.updateState(mockPref); - verify(mockPref, never()).setTitle(any(String.class)); + verify(mockPref).setTitle(mContext.getString(mTitleResId)); } @Test diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceControllerTest.java new file mode 100644 index 00000000000..e30fc71eff1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorMsgEventReminderPreferenceControllerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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.notification; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import androidx.preference.Preference; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public final class ZenModeBehaviorMsgEventReminderPreferenceControllerTest { + + private ZenModeBehaviorMsgEventReminderPreferenceController mController; + @Mock + private NotificationManager mNotificationManager; + @Mock + private NotificationManager.Policy mPolicy; + + private Context mContext; + @Mock + private ZenModeBackend mBackend; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + + mContext = RuntimeEnvironment.application; + when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy); + + mController = new ZenModeBehaviorMsgEventReminderPreferenceController( + mContext, mock(Lifecycle.class)); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + } + + @Test + public void testIsAvailable() { + assertTrue(mController.isAvailable()); + } + + @Test + public void testHasSummary() { + Preference pref = mock(Preference.class); + mController.updateState(pref); + verify(pref).setSummary(any()); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceControllerTest.java new file mode 100644 index 00000000000..d3fab8fdf26 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeBehaviorSoundPreferenceControllerTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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.notification; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import androidx.preference.Preference; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public final class ZenModeBehaviorSoundPreferenceControllerTest { + + private ZenModeBehaviorSoundPreferenceController mController; + @Mock + private NotificationManager mNotificationManager; + @Mock + private NotificationManager.Policy mPolicy; + + private Context mContext; + @Mock + private ZenModeBackend mBackend; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + + mContext = RuntimeEnvironment.application; + when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy); + + mController = new ZenModeBehaviorSoundPreferenceController( + mContext, mock(Lifecycle.class)); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + } + + @Test + public void testIsAvailable() { + assertTrue(mController.isAvailable()); + } + + @Test + public void testHasSummary() { + Preference pref = mock(Preference.class); + mController.updateState(pref); + verify(pref).setSummary(any()); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java index b26989d3475..5b2782fb6b7 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java @@ -20,9 +20,9 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import android.app.NotificationManager; +import android.app.NotificationManager.Policy; import android.content.Context; import android.provider.SearchIndexableResource; -import android.provider.Settings; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -46,54 +46,140 @@ public class ZenModeSettingsTest { mBuilder = new ZenModeSettings.SummaryBuilder(mContext); } - @Test - public void testGetBehaviorSettingSummary_noSoundsCanBypass() { - NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); - final String result = mBuilder.getBehaviorSettingSummary(policy, - Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); - - String totalSilence = mContext.getString(R.string.zen_mode_no_exceptions); - assertEquals(totalSilence, result); - } - - @Test - public void testGetBehaviorSettingSummary_alarmsAndMedia() { - NotificationManager.Policy policy = new NotificationManager.Policy( - NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS - | NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, - 0, 0); - final String result = mBuilder.getBehaviorSettingSummary(policy, - Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); - - String alarmsAndMedia = mContext.getString(R.string.join_two_items, - mContext.getString(R.string.zen_mode_alarms), - mContext.getString(R.string.zen_mode_media).toLowerCase()); - assertEquals(alarmsAndMedia, result); - } - @Test public void testBlockedEffectsSummary_none() { - NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0, 0); + Policy policy = new Policy(0, 0, 0, 0); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_muted), mBuilder.getBlockedEffectsSummary(policy)); } @Test public void testBlockedEffectsSummary_some() { - NotificationManager.Policy policy = new NotificationManager.Policy( - 0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK); + Policy policy = new Policy(0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_custom), mBuilder.getBlockedEffectsSummary(policy)); } @Test public void testBlockedEffectsSummary_all() { - NotificationManager.Policy policy = new NotificationManager.Policy( - 0, 0, 0, 511); + Policy policy = new Policy(0, 0, 0, 511); assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_hidden), mBuilder.getBlockedEffectsSummary(policy)); } + @Test + public void testGetMsgEventReminderSettingSummary_none() { + Policy policy = new Policy(0, 0, 0, 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)).isEqualTo("None"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_single() { + Policy policy = new Policy( + Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_EVENTS, 0 , 0 , 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)).isEqualTo("Events"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_someMsgs() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_MESSAGES, 0, + Policy.PRIORITY_SENDERS_CONTACTS , 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)).isEqualTo("Some messages"); + + policy = new Policy(Policy.PRIORITY_CATEGORY_MESSAGES, 0, + Policy.PRIORITY_SENDERS_STARRED , 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)).isEqualTo("Some messages"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_msgs() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_MESSAGES, 0, 0, 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)).isEqualTo("Messages"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_someMsgsAndOther() { + Policy policy = new Policy( + Policy.PRIORITY_CATEGORY_MESSAGES | Policy.PRIORITY_CATEGORY_REMINDERS, + 0, Policy.PRIORITY_SENDERS_CONTACTS , 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)) + .isEqualTo("Some messages and reminders"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_someMsgsAndAllOthers() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_EVENTS + | Policy.PRIORITY_CATEGORY_MESSAGES | Policy.PRIORITY_CATEGORY_REMINDERS, + 0, Policy.PRIORITY_SENDERS_CONTACTS , 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)) + .isEqualTo("Some messages, events, and reminders"); + } + + @Test + public void testGetMsgEventReminderSettingSummary_noMsgsAndOther() { + Policy policy = new Policy( + Policy.PRIORITY_CATEGORY_EVENTS | Policy.PRIORITY_CATEGORY_REMINDERS, + 0,0, 0); + assertThat(mBuilder.getMsgEventReminderSettingSummary(policy)) + .isEqualTo("Events and reminders"); + } + + @Test + public void testGetCallsSettingSummary_none() { + Policy policy = new Policy(0, 0, 0, 0); + assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("None"); + } + + @Test + public void testGetCallsSettingSummary_contacts() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS, + Policy.PRIORITY_SENDERS_CONTACTS, 0, 0); + assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From contacts only"); + } + + @Test + public void testGetCallsSettingSummary_repeatCallers() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0); + assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From repeat callers only"); + } + + @Test + public void testGetCallsSettingSummary_starredRepeatCallers() { + Policy policy = new Policy( + Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | Policy.PRIORITY_CATEGORY_CALLS, + Policy.PRIORITY_SENDERS_STARRED, 0, 0); + assertThat(mBuilder.getCallsSettingSummary(policy)) + .isEqualTo("From starred contacts and repeat callers"); + } + + @Test + public void testGetSoundSettingSummary_allOff() { + Policy policy = new Policy(0, 0, 0, 0); + assertThat(mBuilder.getSoundSettingSummary(policy)).isEqualTo("Muted"); + } + + @Test + public void testGetSoundSettingSummary_allOn() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_SYSTEM + | Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0); + assertThat(mBuilder.getSoundSettingSummary(policy)) + .isEqualTo("Muted, but allow alarms, media, and touch sounds"); + } + + @Test + public void testGetSoundSettingSummary_allOffButOne() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0); + assertThat(mBuilder.getSoundSettingSummary(policy)).isEqualTo("Muted, but allow media"); + } + + @Test + public void testGetSoundSettingSummary_allOffButTwo() { + Policy policy = new Policy(Policy.PRIORITY_CATEGORY_SYSTEM + | Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0); + assertThat(mBuilder.getSoundSettingSummary(policy)) + .isEqualTo("Muted, but allow media and touch sounds"); + } + @Test public void searchProvider_shouldIndexDefaultXml() { final List sir = ZenModeSettings.SEARCH_INDEX_DATA_PROVIDER From 3403c3729e0b3cabc35cb56be3f04db13b4cafa6 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 10 May 2018 13:28:00 -0400 Subject: [PATCH 02/21] Clear deprecated effects when saving zen policy - Deprecated effects are set in NotificationManagerService, so unset them before setting the NotificationPolicy - When user clicks on Custom, they are brought to the custom vis effects page instead of resetting custom values to presets Fixes: 79383781 Test: manual Test: NotificationManagerServiceTest testSetNotificationPolicy_preP_setOldNewFields Change-Id: Id6db9ce2aaeed6321389f8dbfbea65eda30c74ad --- .../settings/notification/ZenModeBackend.java | 16 +++++++++---- .../ZenModeRestrictNotificationsSettings.java | 1 - ...eVisEffectsCustomPreferenceController.java | 23 +++++++++++-------- ...EffectsCustomPreferenceControllerTest.java | 14 ----------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java index ece2a9e666c..cb8a048c90c 100644 --- a/src/com/android/settings/notification/ZenModeBackend.java +++ b/src/com/android/settings/notification/ZenModeBackend.java @@ -16,6 +16,9 @@ package com.android.settings.notification; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; + import android.app.ActivityManager; import android.app.AutomaticZenRule; import android.app.NotificationManager; @@ -146,19 +149,24 @@ public class ZenModeBackend { protected void savePolicy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders, int suppressedVisualEffects) { mPolicy = new NotificationManager.Policy(priorityCategories, priorityCallSenders, - priorityMessageSenders, - suppressedVisualEffects); + priorityMessageSenders, suppressedVisualEffects); mNotificationManager.setNotificationPolicy(mPolicy); } - protected int getNewSuppressedEffects(boolean suppress, int effectType) { + private int getNewSuppressedEffects(boolean suppress, int effectType) { int effects = mPolicy.suppressedVisualEffects; + if (suppress) { effects |= effectType; } else { effects &= ~effectType; } - return effects; + + return clearDeprecatedEffects(effects); + } + + private int clearDeprecatedEffects(int effects) { + return effects & ~(SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); } protected boolean isEffectAllowed(int effect) { diff --git a/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java b/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java index 966e932d144..a2a0ba7f008 100644 --- a/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java +++ b/src/com/android/settings/notification/ZenModeRestrictNotificationsSettings.java @@ -70,7 +70,6 @@ public class ZenModeRestrictNotificationsSettings extends ZenModeSettingsBase im custom.displayPreference(getPreferenceScreen()); if (mShowMenuSelected) { - custom.select(); metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, true); } else { metrics.action(mContext, ACTION_ZEN_SHOW_CUSTOM, false); diff --git a/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java index 550fda4c40a..5baf0fac11d 100644 --- a/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java +++ b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settings.notification; import android.app.NotificationManager.Policy; import android.content.Context; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -57,15 +58,12 @@ public class ZenModeVisEffectsCustomPreferenceController pref.setChecked(areCustomOptionsSelected()); pref.setOnGearClickListener(p -> { - new SubSettingLauncher(mContext) - .setDestination(ZenModeBlockedEffectsSettings.class.getName()) - .setTitleRes(R.string.zen_mode_what_to_block_title) - .setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS) - .launch(); + launchCustomSettings(); + }); pref.setOnRadioButtonClickListener(p -> { - select(); + launchCustomSettings(); }); } @@ -84,9 +82,14 @@ public class ZenModeVisEffectsCustomPreferenceController protected void select() { mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_CUSTOM, true); - mBackend.savePolicy(mBackend.mPolicy.priorityCategories, - mBackend.mPolicy.priorityCallSenders, - mBackend.mPolicy.priorityMessageSenders, - INTERRUPTIVE_EFFECTS); + } + + private void launchCustomSettings() { + select(); + new SubSettingLauncher(mContext) + .setDestination(ZenModeBlockedEffectsSettings.class.getName()) + .setTitleRes(R.string.zen_mode_what_to_block_title) + .setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS) + .launch(); } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java index 5de7697d1af..f3d92d17d21 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java @@ -150,18 +150,4 @@ public class ZenModeVisEffectsCustomPreferenceControllerTest { verify(mockPref).setOnGearClickListener(any()); verify(mockPref).setOnRadioButtonClickListener(any()); } - - @Test - public void select() { - int interruptiveSuppressed = SUPPRESSED_EFFECT_FULL_SCREEN_INTENT - | SUPPRESSED_EFFECT_AMBIENT - | SUPPRESSED_EFFECT_LIGHTS - | SUPPRESSED_EFFECT_PEEK; - mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); - mController.select(); - verify(mBackend).savePolicy(anyInt(), anyInt(), anyInt(), eq(interruptiveSuppressed)); - verify(mFeatureFactory.metricsFeatureProvider).action(eq(mContext), - eq(ACTION_ZEN_CUSTOM), - eq(true)); - } } From 94fecb94e9f869d620b79792a849d91238de9449 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Thu, 10 May 2018 10:26:07 -0700 Subject: [PATCH 03/21] OMS: rebase settings when overlays update When an overlay package has been upgraded, OMS needs to reconcile any previous settings about the overlay with the new state of affairs. Sometimes it is possible to rebase the OMS settings on the new information [e.g. the overlay has changed categories]; sometimes the OMS settings have to be scrapped [e.g. the overlay has changed target package]. Update OMS to do The Right Thing. Bug: 78809704 Test: manual (adb shell stop, adb push specially prepared overlays, adb shell start, adb exec-out cmd overlay dump) Test: ran unit tests Test: adb install out/target/product/walleye/data/app/SettingsUnitTests/SettingsUnitTests.apk Test: adb shell am instrument -w -e class com.android.settings.display.ThemePreferenceControllerTest com.android.settings.tests.unit/android.support.test.runner.AndroidJUnitRunner Test: NOTE: 3 of 4 failures both pre and post change; looks like there are issue with the unit tests themselves Change-Id: Icd1ae633dbee5b5ca957fa6b652af6209b4b1260 --- .../display/ThemePreferenceControllerTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java index e618343d8de..586c4486846 100644 --- a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java @@ -69,9 +69,9 @@ public class ThemePreferenceControllerTest { @Test public void testUpdateState() throws Exception { OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", - "", "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0, 0, true); OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", - "", "", 0, 0); + "", "", 0, 0, 0, true); when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> { ApplicationInfo info = mock(ApplicationInfo.class); if ("com.android.Theme1".equals(inv.getArguments()[0])) { @@ -105,9 +105,9 @@ public class ThemePreferenceControllerTest { @Test public void testUpdateState_withStaticOverlay() throws Exception { OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", - "", "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0, 0, true); OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", - "", "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0, 0, true); when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> { ApplicationInfo info = mock(ApplicationInfo.class); if ("com.android.Theme1".equals(inv.getArguments()[0])) { @@ -145,7 +145,7 @@ public class ThemePreferenceControllerTest { when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn( new PackageInfo()); when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())) - .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0))); + .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0, 0, false))); assertThat(mPreferenceController.isAvailable()).isFalse(); } @@ -154,8 +154,8 @@ public class ThemePreferenceControllerTest { when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn( new PackageInfo()); when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())) - .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0), - new OverlayInfo("", "", "", "", 0, 0))); + .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0, 0, true), + new OverlayInfo("", "", "", "", 0, 0, 0, true))); assertThat(mPreferenceController.isAvailable()).isTrue(); } From a76fd8b858b61fdfc27c2133d324a6d1146e4c0a Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Mon, 7 May 2018 13:34:59 -0700 Subject: [PATCH 04/21] Make it so client code does not tie tether to wifi The wifi service already handles turning off tethering if multi-interface is/isn't supported. We don't need to do tie wifi and tethering stuff together in the UI. Test: robotests still pass Bug: 79213401 Merged-In: I699dfe2d7646f248a54faa5a8429176697614cdf Change-Id: I699dfe2d7646f248a54faa5a8429176697614cdf --- .../android/settings/wifi/WifiEnabler.java | 29 ++++-------- .../shadow/ShadowRestrictedLockUtils.java | 46 ++++++++++++------- .../settings/wifi/WifiEnablerTest.java | 9 ++-- ...iMasterSwitchPreferenceControllerTest.java | 2 + 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java index cdb9292815f..fc71d742658 100644 --- a/src/com/android/settings/wifi/WifiEnabler.java +++ b/src/com/android/settings/wifi/WifiEnabler.java @@ -160,15 +160,14 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene setSwitchBarChecked(false); mSwitchWidget.setEnabled(true); } - if (mayDisableTethering(!mSwitchWidget.isChecked())) { - if (RestrictedLockUtils.hasBaseUserRestriction(mContext, - UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) { - mSwitchWidget.setEnabled(false); - } else { - final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext, - UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()); - mSwitchWidget.setDisabledByAdmin(admin); - } + + if (RestrictedLockUtils.hasBaseUserRestriction(mContext, + UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) { + mSwitchWidget.setEnabled(false); + } else { + final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext, + UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()); + mSwitchWidget.setDisabledByAdmin(admin); } } @@ -203,15 +202,11 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene // Show toast message if Wi-Fi is not allowed in airplane mode if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) { Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); - // Reset switch to off. No infinite check/listenenr loop. + // Reset switch to off. No infinite check/listener loop. mSwitchWidget.setChecked(false); return false; } - // Disable tethering if enabling Wifi - if (mayDisableTethering(isChecked)) { - mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI); - } if (isChecked) { mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON); } else { @@ -226,10 +221,4 @@ public class WifiEnabler implements SwitchWidgetController.OnSwitchChangeListene } return true; } - - private boolean mayDisableTethering(boolean isChecked) { - final int wifiApState = mWifiManager.getWifiApState(); - return isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || - (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED)); - } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java index c53f7712bf5..c0d61d20330 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java @@ -28,26 +28,26 @@ import org.robolectric.annotation.Resetter; @Implements(RestrictedLockUtils.class) public class ShadowRestrictedLockUtils { - private static boolean isRestricted; - private static String[] restrictedPkgs; - private static boolean adminSupportDetailsIntentLaunched; - private static int keyguardDisabledFeatures; + private static boolean sIsRestricted; + private static String[] sRestrictedPkgs; + private static boolean sAdminSupportDetailsIntentLaunched; + private static int sKeyguardDisabledFeatures; @Resetter public static void reset() { - isRestricted = false; - restrictedPkgs = null; - adminSupportDetailsIntentLaunched = false; - keyguardDisabledFeatures = 0; + sIsRestricted = false; + sRestrictedPkgs = null; + sAdminSupportDetailsIntentLaunched = false; + sKeyguardDisabledFeatures = 0; } @Implementation public static EnforcedAdmin checkIfMeteredDataRestricted(Context context, String packageName, int userId) { - if (isRestricted) { + if (sIsRestricted) { return new EnforcedAdmin(); } - if (ArrayUtils.contains(restrictedPkgs, packageName)) { + if (ArrayUtils.contains(sRestrictedPkgs, packageName)) { return new EnforcedAdmin(); } return null; @@ -55,32 +55,44 @@ public class ShadowRestrictedLockUtils { @Implementation public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) { - adminSupportDetailsIntentLaunched = true; + sAdminSupportDetailsIntentLaunched = true; } @Implementation public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context, int features, final @UserIdInt int userId) { - return (keyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin(); + return (sKeyguardDisabledFeatures & features) == 0 ? null : new EnforcedAdmin(); + } + + @Implementation + public static boolean hasBaseUserRestriction(Context context, + String userRestriction, int userId) { + return sIsRestricted; + } + + @Implementation + public static EnforcedAdmin checkIfRestrictionEnforced(Context context, + String userRestriction, int userId) { + return sIsRestricted ? new EnforcedAdmin() : null; } public static boolean hasAdminSupportDetailsIntentLaunched() { - return adminSupportDetailsIntentLaunched; + return sAdminSupportDetailsIntentLaunched; } public static void clearAdminSupportDetailsIntentLaunch() { - adminSupportDetailsIntentLaunched = false; + sAdminSupportDetailsIntentLaunched = false; } public static void setRestricted(boolean restricted) { - isRestricted = restricted; + sIsRestricted = restricted; } public static void setRestrictedPkgs(String... pkgs) { - restrictedPkgs = pkgs; + sRestrictedPkgs = pkgs; } public static void setKeyguardDisabledFeatures(int features) { - keyguardDisabledFeatures = features; + sKeyguardDisabledFeatures = features; } } diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java index 66cbd3011e0..75c9bb14a5e 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java @@ -16,6 +16,8 @@ package com.android.settings.wifi; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -25,6 +27,7 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -33,8 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = ShadowRestrictedLockUtils.class) public class WifiEnablerTest { @Mock @@ -59,8 +64,6 @@ public class WifiEnablerTest { when(mWifiManager.setWifiEnabled(true)).thenReturn(true); when(mWifiManager.getWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED); - mEnabler.onSwitchToggled(true); - - verify(mConnectivityManager).stopTethering(ConnectivityManager.TETHERING_WIFI); + assertThat(mEnabler.onSwitchToggled(true)).isTrue(); } } diff --git a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java index 3f8ee5adf33..cea86bfeaa2 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java @@ -36,6 +36,7 @@ import android.support.v7.preference.PreferenceScreen; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; import com.android.settings.widget.MasterSwitchPreference; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -48,6 +49,7 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = ShadowRestrictedLockUtils.class) public class WifiMasterSwitchPreferenceControllerTest { @Mock From f002dcf43b70140518c48296ab8161f53bd71214 Mon Sep 17 00:00:00 2001 From: Beverly Date: Wed, 9 May 2018 15:28:21 -0400 Subject: [PATCH 05/21] Add zen starred contacts preference Bug: 78447976 Test: ZenModeStarredContactsPreferenceControllerTest Change-Id: Ic9d1b08c3e80832b29ad8e223a34f35e2f763cf9 --- res/values/strings.xml | 9 ++ res/xml/zen_mode_calls_settings.xml | 4 +- .../zen_mode_msg_event_reminder_settings.xml | 4 + .../notification/ZenModeCallsSettings.java | 6 +- .../ZenModeMsgEventReminderSettings.java | 4 + ...deStarredContactsPreferenceController.java | 153 ++++++++++++++++++ ...arredContactsPreferenceControllerTest.java | 151 +++++++++++++++++ 7 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index ca80391d52e..ef4e5239882 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7924,6 +7924,15 @@ When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you. + + Starred contacts + + + + and 1 other + and %d others + + Messages diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml index 01ca499c44d..dd6fcc50c0b 100644 --- a/res/xml/zen_mode_calls_settings.xml +++ b/res/xml/zen_mode_calls_settings.xml @@ -30,7 +30,9 @@ android:entries="@array/zen_mode_contacts_entries" android:entryValues="@array/zen_mode_contacts_values"/> - + + + controllers = new ArrayList<>(); controllers.add(new ZenModeCallsPreferenceController(context, lifecycle)); - // TODO: is a controller needed for a pref that just launches an external activity? - // or can the contacts app insert this setting themselves? + controllers.add(new ZenModeStarredContactsPreferenceController(context, lifecycle, + PRIORITY_CATEGORY_CALLS, "zen_mode_starred_contacts_callers")); controllers.add(new ZenModeRepeatCallersPreferenceController(context, lifecycle, context.getResources().getInteger(com.android.internal.R.integer .config_zen_repeat_callers_threshold))); diff --git a/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java index 5a00c47473c..e3a721f11fb 100644 --- a/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java +++ b/src/com/android/settings/notification/ZenModeMsgEventReminderSettings.java @@ -16,6 +16,8 @@ package com.android.settings.notification; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; + import android.content.Context; import android.provider.SearchIndexableResource; @@ -44,6 +46,8 @@ public class ZenModeMsgEventReminderSettings extends ZenModeSettingsBase impleme controllers.add(new ZenModeEventsPreferenceController(context, lifecycle)); controllers.add(new ZenModeRemindersPreferenceController(context, lifecycle)); controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle)); + controllers.add(new ZenModeStarredContactsPreferenceController(context, lifecycle, + PRIORITY_CATEGORY_MESSAGES, "zen_mode_starred_contacts_messages")); controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle, R.string.zen_msg_event_reminder_footer)); return controllers; diff --git a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java new file mode 100644 index 00000000000..0996534b9d9 --- /dev/null +++ b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 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.notification; + +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; +import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.icu.text.ListFormatter; +import android.provider.Contacts; +import android.provider.ContactsContract; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.R; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.ArrayList; +import java.util.List; + +public class ZenModeStarredContactsPreferenceController extends + AbstractZenModePreferenceController implements Preference.OnPreferenceClickListener { + + protected static String KEY; + private Preference mPreference; + private final int mPriorityCategory; + private final PackageManager mPackageManager; + + @VisibleForTesting + Intent mStarredContactsIntent; + @VisibleForTesting + Intent mFallbackIntent; + + public ZenModeStarredContactsPreferenceController(Context context, Lifecycle lifecycle, int + priorityCategory, String key) { + super(context, key, lifecycle); + KEY = key; + + mPriorityCategory = priorityCategory; + mPackageManager = mContext.getPackageManager(); + + mStarredContactsIntent = new Intent(Contacts.Intents.UI.LIST_STARRED_ACTION); + + mFallbackIntent = new Intent(Intent.ACTION_MAIN); + mFallbackIntent.addCategory(Intent.CATEGORY_APP_CONTACTS); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(KEY); + mPreference.setOnPreferenceClickListener(this); + } + + @Override + public String getPreferenceKey() { + return KEY; + } + + @Override + public boolean isAvailable() { + if (mPriorityCategory == PRIORITY_CATEGORY_CALLS) { + return mBackend.isPriorityCategoryEnabled(PRIORITY_CATEGORY_CALLS) + && mBackend.getPriorityCallSenders() == PRIORITY_SENDERS_STARRED + && isIntentValid(); + } else if (mPriorityCategory == PRIORITY_CATEGORY_MESSAGES) { + return mBackend.isPriorityCategoryEnabled(PRIORITY_CATEGORY_MESSAGES) + && mBackend.getPriorityMessageSenders() == PRIORITY_SENDERS_STARRED + && isIntentValid(); + } else { + // invalid category + return false; + } + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + List starredContacts = getStarredContacts(); + int numStarredContacts = starredContacts.size(); + + List displayContacts = new ArrayList<>(); + + if (numStarredContacts == 0) { + displayContacts.add(mContext.getString(R.string.zen_mode_from_none)); + } else { + for (int i = 0; i < 2 && i < numStarredContacts; i++) { + displayContacts.add(starredContacts.get(i)); + } + + if (numStarredContacts == 3) { + displayContacts.add(starredContacts.get(2)); + } else if (numStarredContacts > 2) { + displayContacts.add(mContext.getResources().getQuantityString( + R.plurals.zen_mode_starred_contacts_summary_additional_contacts, + numStarredContacts - 2, numStarredContacts - 2)); + } + } + + mPreference.setSummary(ListFormatter.getInstance().format(displayContacts)); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (mStarredContactsIntent.resolveActivity(mPackageManager) != null) { + mContext.startActivity(mStarredContactsIntent); + } else { + mContext.startActivity(mFallbackIntent); + } + return true; + } + + private List getStarredContacts() { + List starredContacts = new ArrayList<>(); + + Cursor cursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, + new String[]{ContactsContract.Contacts.DISPLAY_NAME_PRIMARY}, + ContactsContract.Data.STARRED + "=1", null, + ContactsContract.Data.TIMES_CONTACTED); + + if (cursor.moveToFirst()) { + do { + starredContacts.add(cursor.getString(0)); + } while (cursor.moveToNext()); + } + return starredContacts; + } + + private boolean isIntentValid() { + return mStarredContactsIntent.resolveActivity(mPackageManager) != null + || mFallbackIntent.resolveActivity(mPackageManager) != null; + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java new file mode 100644 index 00000000000..9a2bccd6b15 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeStarredContactsPreferenceControllerTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2018 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.notification; + +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; +import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenModeStarredContactsPreferenceControllerTest { + + private ZenModeStarredContactsPreferenceController mCallsController; + private ZenModeStarredContactsPreferenceController mMessagesController; + + @Mock + private ZenModeBackend mBackend; + @Mock + private NotificationManager mNotificationManager; + @Mock + private Preference mockPref; + @Mock + private NotificationManager.Policy mPolicy; + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private Intent testIntent; + @Mock + private ComponentName mComponentName; + private Context mContext; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + + mContext = shadowApplication.getApplicationContext(); + when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy); + when(testIntent.resolveActivity(any())).thenReturn(mComponentName); + + mCallsController = new ZenModeStarredContactsPreferenceController( + mContext, mock(Lifecycle.class), PRIORITY_CATEGORY_CALLS, + "zen_mode_starred_contacts_callers"); + ReflectionHelpers.setField(mCallsController, "mBackend", mBackend); + ReflectionHelpers.setField(mCallsController, "mStarredContactsIntent", testIntent); + when(mPreferenceScreen.findPreference(mCallsController.getPreferenceKey())) + .thenReturn(mockPref); + mCallsController.displayPreference(mPreferenceScreen); + + mMessagesController = new ZenModeStarredContactsPreferenceController( + mContext, mock(Lifecycle.class), PRIORITY_CATEGORY_MESSAGES, + "zen_mode_starred_contacts_messages"); + ReflectionHelpers.setField(mMessagesController, "mBackend", mBackend); + ReflectionHelpers.setField(mMessagesController, "mStarredContactsIntent", testIntent); + when(mPreferenceScreen.findPreference(mMessagesController.getPreferenceKey())) + .thenReturn(mockPref); + mMessagesController.displayPreference(mPreferenceScreen); + } + + @Test + public void isAvailable_noCallers() { + when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)) + .thenReturn(false); + assertThat(mCallsController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_anyCallers() { + when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)) + .thenReturn(true); + when(mBackend.getPriorityCallSenders()) + .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_ANY); + + + assertThat(mCallsController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_starredCallers() { + when(mBackend.isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)) + .thenReturn(true); + when(mBackend.getPriorityCallSenders()) + .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED); + + assertThat(mCallsController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_noMessages() { + when(mBackend.isPriorityCategoryEnabled( + NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(false); + assertThat(mMessagesController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_anyMessages() { + when(mBackend.isPriorityCategoryEnabled( + NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(true); + when(mBackend.getPriorityMessageSenders()) + .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_ANY); + + assertThat(mMessagesController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_starredMessageContacts() { + when(mBackend.isPriorityCategoryEnabled( + NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenReturn(true); + when(mBackend.getPriorityMessageSenders()) + .thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED); + + assertThat(mMessagesController.isAvailable()).isTrue(); + } +} From c1ec77239955cd2e7715145a5fe57a3f0b450f4c Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Thu, 10 May 2018 16:20:05 -0700 Subject: [PATCH 06/21] Remove the padding for VideoPreference In old days, VideoPreference has special padding in landscape and no padding in protrait. This CL removes the padding dimen entirely. Change-Id: Ic0ecd27cf7e200bd8fda58a37643482f146793a8 Fixes: 79543761 Test: Screenshot --- res/layout/gesture_preference.xml | 104 ------------------------------ res/layout/video_preference.xml | 3 +- res/values-land/dimens.xml | 3 - res/values/dimens.xml | 1 - 4 files changed, 1 insertion(+), 110 deletions(-) delete mode 100644 res/layout/gesture_preference.xml diff --git a/res/layout/gesture_preference.xml b/res/layout/gesture_preference.xml deleted file mode 100644 index ccbc42ad256..00000000000 --- a/res/layout/gesture_preference.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/layout/video_preference.xml b/res/layout/video_preference.xml index 55bc7a506df..b71a1b5872e 100644 --- a/res/layout/video_preference.xml +++ b/res/layout/video_preference.xml @@ -28,8 +28,7 @@ + android:layout_height="240dp"> 160dp - - 35dp - diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f95de27f525..e0b8c48d47f 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -288,7 +288,6 @@ 20dp 36dp - 0dp 14sp From 6f70289b25b4d9bb2d81fd4c304ca782c2f50210 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Thu, 10 May 2018 17:57:50 +0800 Subject: [PATCH 07/21] Update string from "Add device" to "Pair new device" in Setting > Connected devices * Replace string ID from "connected_device_add_device_title" to "bluetooth_pairing_pref_title" in Connected devices * Reuse ID and change string "Add device" back * BACKUP_MESSAGE_ID=7803521577708810621 Bug: 79298885 Test: make -j50 RunSettingsRoboTests Change-Id: I29f72002c0ece4981d5a523c8649a78acb80730d --- res/values/strings.xml | 4 ++-- res/xml/connected_devices.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 00748369ab5..e01c10c1c80 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -413,8 +413,8 @@ Currently connected Saved devices - - Pair new device + + Add device Bluetooth will turn on to pair diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index 1e9d97eaa90..6d25c584b85 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -32,7 +32,7 @@ Date: Thu, 3 May 2018 13:40:52 +0800 Subject: [PATCH 08/21] Use another callback to notify the updater that UI should be updated Replace onConnectionStateChanged callback with onProfileConnectionStateChanged. While updater is notified, isFilterMatched(cachedDevice) will decide whether to add/remove from UI based on audio profiles and audio mode. Bug: 76447449 Test: make RunSettingsRoboTests -j28 Change-Id: Icfba1ce2297e4638679158f9f99bae276940d885 --- .../AvailableMediaBluetoothDeviceUpdater.java | 14 ++++--- .../bluetooth/BluetoothDeviceUpdater.java | 5 +++ .../ConnectedBluetoothDeviceUpdater.java | 14 +++---- .../SavedBluetoothDeviceUpdater.java | 9 +++-- .../AudioSwitchPreferenceController.java | 7 +++- ...ilableMediaBluetoothDeviceUpdaterTest.java | 35 +++++++++--------- .../ConnectedBluetoothDeviceUpdaterTest.java | 37 ++++++++++--------- .../SavedBluetoothDeviceUpdaterTest.java | 18 ++++----- 8 files changed, 78 insertions(+), 61 deletions(-) diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index 1e4b693f97f..c8e6f26038f 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -16,11 +16,11 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothProfile; -import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.media.AudioManager; import android.support.annotation.VisibleForTesting; import android.util.Log; + import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -57,18 +57,20 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater } @Override - public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { + public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, + int bluetoothProfile) { if (DBG) { - Log.d(TAG,"onConnectionStateChanged() device : " + - cachedDevice.getName() + ", state : " + state); + Log.d(TAG, "onProfileConnectionStateChanged() device: " + + cachedDevice.getName() + ", state: " + state + ", bluetoothProfile: " + + bluetoothProfile); } - if (state == BluetoothAdapter.STATE_CONNECTED) { + if (state == BluetoothProfile.STATE_CONNECTED) { if (isFilterMatched(cachedDevice)) { addPreference(cachedDevice); } else { removePreference(cachedDevice); } - } else if (state == BluetoothAdapter.STATE_DISCONNECTED) { + } else if (state == BluetoothProfile.STATE_DISCONNECTED) { removePreference(cachedDevice); } } diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java index dfcbfca1e06..8937b177a64 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java @@ -161,6 +161,11 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback, public void onAudioModeChanged() { } + @Override + public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, + int bluetoothProfile) { + } + @Override public void onServiceConnected() { // When bluetooth service connected update the UI diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 11702bcefc2..d43290c9566 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -15,7 +15,6 @@ */ package com.android.settings.bluetooth; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; @@ -60,19 +59,20 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { } @Override - public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { + public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, + int bluetoothProfile) { if (DBG) { - Log.d(TAG,"onConnectionStateChanged() device : " + - cachedDevice.getName() + ", state : " + state); + Log.d(TAG, "onProfileConnectionStateChanged() device: " + + cachedDevice.getName() + ", state: " + state + ", bluetoothProfile: " + + bluetoothProfile); } - - if (state == BluetoothAdapter.STATE_CONNECTED) { + if (state == BluetoothProfile.STATE_CONNECTED) { if (isFilterMatched(cachedDevice)) { addPreference(cachedDevice); } else { removePreference(cachedDevice); } - } else if (state == BluetoothAdapter.STATE_DISCONNECTED) { + } else if (state == BluetoothProfile.STATE_DISCONNECTED) { removePreference(cachedDevice); } } diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java index c25a43babfb..34cb5746c60 100644 --- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java @@ -15,8 +15,8 @@ */ package com.android.settings.bluetooth; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.content.Context; import android.support.annotation.VisibleForTesting; @@ -43,10 +43,11 @@ public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { } @Override - public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { - if (state == BluetoothAdapter.STATE_CONNECTED) { + public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, + int bluetoothProfile) { + if (state == BluetoothProfile.STATE_CONNECTED) { removePreference(cachedDevice); - } else if (state == BluetoothAdapter.STATE_DISCONNECTED) { + } else if (state == BluetoothProfile.STATE_DISCONNECTED) { addPreference(cachedDevice); } } diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index 81479c9e872..dde2b3012ed 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -161,7 +161,6 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont */ @Override public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { - updateState(mPreference); } @Override @@ -174,6 +173,12 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont updateState(mPreference); } + @Override + public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, + int bluetoothProfile) { + updateState(mPreference); + } + @Override public void onBluetoothStateChanged(int bluetoothState) { } diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java index fbc698c548b..ed9501554eb 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java @@ -15,11 +15,11 @@ */ package com.android.settings.bluetooth; -import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothDevice; import android.content.Context; - import android.media.AudioManager; + import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -150,60 +150,61 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { } @Test - public void onConnectionStateChanged_a2dpDeviceConnected_notInCall_addPreference() { + public void onProfileConnectionStateChanged_a2dpDeviceConnected_notInCall_addPreference() { mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_a2dpDeviceConnected_inCall_removePreference() { + public void onProfileConnectionStateChanged_a2dpDeviceConnected_inCall_removePreference() { mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + @Test - public void onConnectionStateChanged_hfpDeviceConnected_notInCall_removePreference() { + public void onProfileConnectionStateChanged_hfpDeviceConnected_notInCall_removePreference() { mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_hfpDeviceConnected_inCall_addPreference() { + public void onProfileConnectionStateChanged_hfpDeviceConnected_inCall_addPreference() { mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_deviceDisconnected_removePreference() { - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_DISCONNECTED); + public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java index 56e638a9ed1..483df01a6b8 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java @@ -16,6 +16,7 @@ package com.android.settings.bluetooth; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -23,11 +24,11 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothDevice; import android.content.Context; - import android.media.AudioManager; + import com.android.settings.connecteddevice.DevicePreferenceCallback; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -75,6 +76,7 @@ public class ConnectedBluetoothDeviceUpdaterTest { private Collection cachedDevices; private ShadowAudioManager mShadowAudioManager; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -151,60 +153,61 @@ public class ConnectedBluetoothDeviceUpdaterTest { } @Test - public void onConnectionStateChanged_a2dpDeviceConnected_inCall_addPreference() { + public void onProfileConnectionStateChanged_a2dpDeviceConnected_inCall_addPreference() { mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_a2dpDeviceConnected_notInCall_removePreference() { + public void onProfileConnectionStateChanged_a2dpDeviceConnected_notInCall_removePreference() { mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isA2dpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + @Test - public void onConnectionStateChanged_hfpDeviceConnected_inCall_removePreference() { + public void onProfileConnectionStateChanged_hfpDeviceConnected_inCall_removePreference() { mShadowAudioManager.setMode(AudioManager.MODE_IN_CALL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_hfpDeviceConnected_notInCall_addPreference() { + public void onProfileConnectionStateChanged_hfpDeviceConnected_notInCall_addPreference() { mShadowAudioManager.setMode(AudioManager.MODE_NORMAL); when(mBluetoothDeviceUpdater. isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isHfpDevice()).thenReturn(true); - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_CONNECTED); + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } @Test - public void onConnectionStateChanged_deviceDisconnected_removePreference() { - mBluetoothDeviceUpdater.onConnectionStateChanged(mCachedBluetoothDevice, - BluetoothAdapter.STATE_DISCONNECTED); + public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() { + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java index e0ba82916b3..fae014f7b10 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothDevice; import android.content.Context; @@ -76,7 +76,7 @@ public class SavedBluetoothDeviceUpdaterTest { } @Test - public void testUpdate_filterMatch_addPreference() { + public void update_filterMatch_addPreference() { doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState(); doReturn(false).when(mBluetoothDevice).isConnected(); @@ -86,7 +86,7 @@ public class SavedBluetoothDeviceUpdaterTest { } @Test - public void testUpdate_filterNotMatch_removePreference() { + public void update_filterNotMatch_removePreference() { doReturn(BluetoothDevice.BOND_NONE).when(mBluetoothDevice).getBondState(); doReturn(true).when(mBluetoothDevice).isConnected(); @@ -96,17 +96,17 @@ public class SavedBluetoothDeviceUpdaterTest { } @Test - public void testOnConnectionStateChanged_deviceConnected_removePreference() { - mBluetoothDeviceUpdater - .onConnectionStateChanged(mCachedBluetoothDevice, BluetoothAdapter.STATE_CONNECTED); + public void onProfileConnectionStateChanged_deviceConnected_removePreference() { + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } @Test - public void testOnConnectionStateChanged_deviceDisconnected_addPreference() { - mBluetoothDeviceUpdater - .onConnectionStateChanged(mCachedBluetoothDevice, BluetoothAdapter.STATE_DISCONNECTED); + public void onProfileConnectionStateChanged_deviceDisconnected_addPreference() { + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP); verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } From 86b5ade6e2c4972371827fa7e74dc6967a5b4d92 Mon Sep 17 00:00:00 2001 From: timhypeng Date: Fri, 11 May 2018 14:16:35 +0800 Subject: [PATCH 09/21] Add discoverable footer preference string when bluetooth is off Bug: 79294219 Test: build pass Change-Id: Iea8c75bed099466060405d81b793404619059642 --- res/values/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 00748369ab5..e38f377ef3b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -388,6 +388,8 @@ Visible as \u201C^1\u201D to other devices + + Turn on Bluetooth to connect to other devices. Your devices From ae2893db10cdd6e021ac44103ecf83d8b1595e06 Mon Sep 17 00:00:00 2001 From: AL Ho Date: Fri, 11 May 2018 14:58:10 +0800 Subject: [PATCH 10/21] Update Accessibility vibration settings. - Get notification vibration and haptic feedback intensity respectively. - Use xliffs to compose these strings. - Use the version that passed in Vibrator.class to get Vibrator instance. - Refactor switch/case part in getSummary() of VibrationIntensityPreferenceController. Let AccessibilitySettings and VibrationIntensityPreferenceController both call it. - Add robolectric test for method: updateVibrationSummary(). - Refine test method, use real preference and test summary value. - Remove redundancy. Bug: 75322064 Test: make ROBOTEST_FILTER=AccessibilitySettingsTest RunSettingsRoboTests Change-Id: Ia3c7447b1ab1e336b36ad439800b673821417e48 Merged-In: Ia3c7447b1ab1e336b36ad439800b673821417e48 --- res/values/strings.xml | 3 ++ .../accessibility/AccessibilitySettings.java | 31 +++++++++++++-- ...ibrationIntensityPreferenceController.java | 11 ++++-- .../AccessibilitySettingsTest.java | 39 ++++++++++++++++++- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index b10df976544..b7ef7f77088 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4633,6 +4633,9 @@ Very long delay (%1$d ms) + + Ring %1$s, touch %2$s + Ring & notification set to off diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index de1732c9600..cd92a9587f9 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -33,6 +33,7 @@ import android.os.UserHandle; import android.os.Vibrator; import android.provider.SearchIndexableResource; import android.provider.Settings; +import androidx.annotation.VisibleForTesting; import androidx.preference.SwitchPreference; import androidx.core.content.ContextCompat; import androidx.preference.ListPreference; @@ -749,12 +750,34 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements pref.setSummary(entries[index]); } - private void updateVibrationSummary(Preference pref) { - Vibrator vibrator = getContext().getSystemService(Vibrator.class); - final int intensity = Settings.System.getInt(getContext().getContentResolver(), + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + void updateVibrationSummary(Preference pref) { + final Context context = getContext(); + final Vibrator vibrator = context.getSystemService(Vibrator.class); + + final int ringIntensity = Settings.System.getInt(context.getContentResolver(), Settings.System.NOTIFICATION_VIBRATION_INTENSITY, vibrator.getDefaultNotificationVibrationIntensity()); - mVibrationPreferenceScreen.setSummary(getVibrationSummary(getContext(), intensity)); + CharSequence ringIntensityString = + VibrationIntensityPreferenceController.getIntensityString(context, ringIntensity); + + final int touchIntensity = Settings.System.getInt(context.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_INTENSITY, + vibrator.getDefaultHapticFeedbackIntensity()); + CharSequence touchIntensityString = + VibrationIntensityPreferenceController.getIntensityString(context, touchIntensity); + + if (mVibrationPreferenceScreen == null) { + mVibrationPreferenceScreen = findPreference(VIBRATION_PREFERENCE_SCREEN); + } + + if (ringIntensity == touchIntensity) { + mVibrationPreferenceScreen.setSummary(ringIntensityString); + } else { + mVibrationPreferenceScreen.setSummary( + getString(R.string.accessibility_vibration_summary, + ringIntensityString, touchIntensityString)); + } } private String getVibrationSummary(Context context, @VibrationIntensity int intensity) { diff --git a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java index 34516b412cf..e99e32fe656 100644 --- a/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java +++ b/src/com/android/settings/accessibility/VibrationIntensityPreferenceController.java @@ -77,16 +77,19 @@ public abstract class VibrationIntensityPreferenceController extends BasePrefere public CharSequence getSummary() { final int intensity = Settings.System.getInt(mContext.getContentResolver(), mSettingKey, getDefaultIntensity()); + return getIntensityString(mContext, intensity); + } + public static CharSequence getIntensityString(Context context, int intensity) { switch (intensity) { case Vibrator.VIBRATION_INTENSITY_OFF: - return mContext.getText(R.string.accessibility_vibration_intensity_off); + return context.getText(R.string.accessibility_vibration_intensity_off); case Vibrator.VIBRATION_INTENSITY_LOW: - return mContext.getText(R.string.accessibility_vibration_intensity_low); + return context.getText(R.string.accessibility_vibration_intensity_low); case Vibrator.VIBRATION_INTENSITY_MEDIUM: - return mContext.getText(R.string.accessibility_vibration_intensity_medium); + return context.getText(R.string.accessibility_vibration_intensity_medium); case Vibrator.VIBRATION_INTENSITY_HIGH: - return mContext.getText(R.string.accessibility_vibration_intensity_high); + return context.getText(R.string.accessibility_vibration_intensity_high); default: return ""; } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index f257f549436..a4907dadac1 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -18,7 +18,15 @@ package com.android.settings.accessibility; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + import android.content.Context; +import android.os.Vibrator; +import android.provider.Settings; +import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -26,6 +34,8 @@ import com.android.settings.testutils.XmlTestUtils; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; @@ -45,4 +55,31 @@ public class AccessibilitySettingsTest { assertThat(keys).containsAllIn(niks); } -} \ No newline at end of file + + @Test + public void testUpdateVibrationSummary_shouldUpdateSummary() { + MockitoAnnotations.initMocks(this); + final Context mContext = RuntimeEnvironment.application; + final AccessibilitySettings mSettings = spy(new AccessibilitySettings()); + + final Preference mVibrationPreferenceScreen = new Preference(mContext); + doReturn(mVibrationPreferenceScreen).when(mSettings).findPreference(anyString()); + + doReturn(mContext).when(mSettings).getContext(); + + mVibrationPreferenceScreen.setKey("vibration_preference_screen"); + + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.NOTIFICATION_VIBRATION_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_INTENSITY, + Vibrator.VIBRATION_INTENSITY_OFF); + + mSettings.updateVibrationSummary(mVibrationPreferenceScreen); + assertThat(mVibrationPreferenceScreen.getSummary()).isEqualTo( + VibrationIntensityPreferenceController.getIntensityString(mContext, + Vibrator.VIBRATION_INTENSITY_OFF)); + } +} From 156fd91fbd1ae1eb601a51432a13767fb244669e Mon Sep 17 00:00:00 2001 From: ryanywlin Date: Wed, 25 Apr 2018 10:56:36 +0800 Subject: [PATCH 11/21] Add call volume in sound settings * Add call volume slider * move "Take call" controller from "Ring volume" to "Call volume" Bug: 77254162 Test: make -j50 RunSettingsRoboTests Change-Id: I3443021c1557f42293e9b7772fe9072e5a966cf8 --- res/drawable/ic_local_phone_24_lib.xml | 28 ++++++ res/layout/preference_volume_slider.xml | 4 +- res/values/bools.xml | 3 + res/xml/sound_settings.xml | 29 ++++-- .../CallVolumePreferenceController.java | 55 +++++++++++ .../settings/notification/SoundSettings.java | 1 + .../notification/VolumeSeekBarPreference.java | 8 +- .../CallVolumePreferenceControllerTest.java | 95 +++++++++++++++++++ .../VolumeSeekBarPreferenceTest.java | 5 +- .../testutils/shadow/ShadowAudioManager.java | 10 +- 10 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 res/drawable/ic_local_phone_24_lib.xml create mode 100644 src/com/android/settings/notification/CallVolumePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/notification/CallVolumePreferenceControllerTest.java diff --git a/res/drawable/ic_local_phone_24_lib.xml b/res/drawable/ic_local_phone_24_lib.xml new file mode 100644 index 00000000000..45748028d22 --- /dev/null +++ b/res/drawable/ic_local_phone_24_lib.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/res/layout/preference_volume_slider.xml b/res/layout/preference_volume_slider.xml index 89ecec02c5b..5e5d595108a 100644 --- a/res/layout/preference_volume_slider.xml +++ b/res/layout/preference_volume_slider.xml @@ -45,8 +45,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:layout_marginTop="8dip" - android:layout_marginBottom="8dip"> + android:layout_marginTop="16dip" + android:layout_marginBottom="16dip"> true + + true + true diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml index 15fbcc84d41..61f529ff33d 100644 --- a/res/xml/sound_settings.xml +++ b/res/xml/sound_settings.xml @@ -38,12 +38,29 @@ android:order="-175" settings:controller="com.android.settings.sound.MediaOutputPreferenceController"/> + + + + + + @@ -51,15 +68,7 @@ - - - + android:order="-155"/> mDeviceCallbacks = new ArrayList(); @Implementation @@ -104,4 +105,11 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag public void reset() { mDeviceCallbacks.clear(); } + + public void setBluetoothScoOn(boolean bluetoothScoOn) { + mBluetoothScoOn = bluetoothScoOn; + } + + @Implementation + public boolean isBluetoothScoOn() { return mBluetoothScoOn; } } From ef301823d34ce291ab5ec820578e2d75c2a9d520 Mon Sep 17 00:00:00 2001 From: ryanywlin Date: Fri, 11 May 2018 20:25:13 +0800 Subject: [PATCH 12/21] Implement getProfileId() method in the subclass Add getProfileId() method in LocalBluetoothProfile interface, implement this method in subclass. Bug: 76447449 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothDetailsProfilesControllerTest -j28 Change-Id: I8082716b7cdaf7394ee2f8a4b636058716af7bb1 --- .../bluetooth/BluetoothDetailsProfilesControllerTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java index 53fc1e6928b..2f77af62f6e 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java @@ -155,6 +155,11 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont return true; } + @Override + public int getProfileId() { + return 0; + } + @Override public int getOrdinal() { return 0; From b715d6b6757b3b37adf2e7689b3acdeffc4c68bd Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Fri, 11 May 2018 10:59:58 -0700 Subject: [PATCH 13/21] Rename settings category. - from night light to night display. Change-Id: I2d6c8d931793439dc3b028b4b7a46c21444e10a0 Fixes: 79530682 Test: make RunSettingsRoboTests --- .../android/settings/dashboard/DashboardFragmentRegistry.java | 2 +- .../android/settings/display/NightDisplaySettingsTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index 5e45c43dfbb..cd478fc43ad 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -100,7 +100,7 @@ public class DashboardFragmentRegistry { PARENT_TO_CATEGORY_KEY_MAP.put(GestureSettings.class.getName(), CategoryKey.CATEGORY_GESTURES); PARENT_TO_CATEGORY_KEY_MAP.put(NightDisplaySettings.class.getName(), - CategoryKey.CATEGORY_NIGHT_LIGHT); + CategoryKey.CATEGORY_NIGHT_DISPLAY); CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size()); diff --git a/tests/robotests/src/com/android/settings/display/NightDisplaySettingsTest.java b/tests/robotests/src/com/android/settings/display/NightDisplaySettingsTest.java index e3f90929d2d..6942fd84d6c 100644 --- a/tests/robotests/src/com/android/settings/display/NightDisplaySettingsTest.java +++ b/tests/robotests/src/com/android/settings/display/NightDisplaySettingsTest.java @@ -48,8 +48,8 @@ public class NightDisplaySettingsTest { } @Test - public void getCategoryKey_isCategoryNightLight() { + public void getCategoryKey_isCategoryNightDisplay() { NightDisplaySettings settings = new NightDisplaySettings(); - assertThat(settings.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_NIGHT_LIGHT); + assertThat(settings.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_NIGHT_DISPLAY); } } From ea8406f75d626d6ca78dbe44c52090616b7625c2 Mon Sep 17 00:00:00 2001 From: Irina Dumitrescu Date: Fri, 11 May 2018 19:03:42 +0100 Subject: [PATCH 14/21] Make local variables final where possible in CredentialStorage This speeds up the run-time of credential settings. Test: this is tested at compile time. Change-Id: I77d577cace07826596eb40223a36a8d327b3d72b --- .../android/settings/CredentialStorage.java | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java index ffbd2ce409b..c037c9f0a2c 100644 --- a/src/com/android/settings/CredentialStorage.java +++ b/src/com/android/settings/CredentialStorage.java @@ -127,9 +127,9 @@ public final class CredentialStorage extends Activity { protected void onResume() { super.onResume(); - Intent intent = getIntent(); - String action = intent.getAction(); - UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); + final Intent intent = getIntent(); + final String action = intent.getAction(); + final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { if (ACTION_RESET.equals(action)) { new ResetDialog(); @@ -208,18 +208,18 @@ public final class CredentialStorage extends Activity { * Returns true if the currently set key guard matches our minimum quality requirements. */ private boolean checkKeyGuardQuality() { - int credentialOwner = + final int credentialOwner = UserManager.get(this).getCredentialOwnerProfile(UserHandle.myUserId()); - int quality = new LockPatternUtils(this).getActivePasswordQuality(credentialOwner); + final int quality = new LockPatternUtils(this).getActivePasswordQuality(credentialOwner); return (quality >= MIN_PASSWORD_QUALITY); } private boolean isHardwareBackedKey(byte[] keyData) { try { - ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData)); - PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); - String algOid = pki.getAlgorithmId().getAlgorithm().getId(); - String algName = new AlgorithmId(new ObjectIdentifier(algOid)).getName(); + final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData)); + final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); + final String algOid = pki.getAlgorithmId().getAlgorithm().getId(); + final String algName = new AlgorithmId(new ObjectIdentifier(algOid)).getName(); return KeyChain.isBoundKeyAlgorithm(algName); } catch (IOException e) { @@ -236,14 +236,13 @@ public final class CredentialStorage extends Activity { return; } - Bundle bundle = mInstallBundle; + final Bundle bundle = mInstallBundle; mInstallBundle = null; final int uid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, KeyStore.UID_SELF); if (uid != KeyStore.UID_SELF && !UserHandle.isSameUser(uid, Process.myUid())) { - int dstUserId = UserHandle.getUserId(uid); - int myUserId = UserHandle.myUserId(); + final int dstUserId = UserHandle.getUserId(uid); // Restrict install target to the wifi uid. if (uid != Process.WIFI_UID) { @@ -252,7 +251,7 @@ public final class CredentialStorage extends Activity { return; } - Intent installIntent = new Intent(ACTION_INSTALL) + final Intent installIntent = new Intent(ACTION_INSTALL) .setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) .putExtras(bundle); startActivityAsUser(installIntent, new UserHandle(dstUserId)); @@ -260,8 +259,8 @@ public final class CredentialStorage extends Activity { } if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) { - String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME); - byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA); + final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME); + final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA); int flags = KeyStore.FLAG_ENCRYPTED; if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) { @@ -287,11 +286,11 @@ public final class CredentialStorage extends Activity { } } - int flags = KeyStore.FLAG_NONE; + final int flags = KeyStore.FLAG_NONE; if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) { - String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME); - byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA); + final String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME); + final byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA); if (!mKeyStore.put(certName, certData, uid, flags)) { Log.e(TAG, "Failed to install " + certName + " as uid " + uid); @@ -300,8 +299,8 @@ public final class CredentialStorage extends Activity { } if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) { - String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME); - byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA); + final String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME); + final byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA); if (!mKeyStore.put(caListName, caListData, uid, flags)) { Log.e(TAG, "Failed to install " + caListName + " as uid " + uid); @@ -310,7 +309,7 @@ public final class CredentialStorage extends Activity { } // Send the broadcast. - Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED); + final Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED); sendBroadcast(broadcast); setResult(RESULT_OK); @@ -324,7 +323,7 @@ public final class CredentialStorage extends Activity { private boolean mResetConfirmed; private ResetDialog() { - AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) + final AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) .setTitle(android.R.string.dialog_alert_title) .setMessage(R.string.credentials_reset_hint) .setPositiveButton(android.R.string.ok, this) @@ -364,7 +363,7 @@ public final class CredentialStorage extends Activity { new LockPatternUtils(CredentialStorage.this).resetKeyStore(UserHandle.myUserId()); try { - KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this); + final KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this); try { return keyChainConnection.getService().reset(); } catch (RemoteException e) { @@ -393,7 +392,7 @@ public final class CredentialStorage extends Activity { } private void clearLegacyVpnIfEstablished() { - boolean isDone = VpnUtils.disconnectLegacyVpn(getApplicationContext()); + final boolean isDone = VpnUtils.disconnectLegacyVpn(getApplicationContext()); if (isDone) { Toast.makeText(CredentialStorage.this, R.string.vpn_disconnected, Toast.LENGTH_SHORT).show(); @@ -407,7 +406,7 @@ public final class CredentialStorage extends Activity { private class MarkKeyAsUserSelectable extends AsyncTask { final String mAlias; - public MarkKeyAsUserSelectable(String alias) { + MarkKeyAsUserSelectable(String alias) { mAlias = alias; } @@ -440,7 +439,7 @@ public final class CredentialStorage extends Activity { final int launchedFromUserId; try { - int launchedFromUid = android.app.ActivityManager.getService() + final int launchedFromUid = android.app.ActivityManager.getService() .getLaunchedFromUid(getActivityToken()); if (launchedFromUid == -1) { Log.e(TAG, ACTION_INSTALL + " must be started with startActivityForResult"); @@ -456,8 +455,8 @@ public final class CredentialStorage extends Activity { return false; } - UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); - UserInfo parentInfo = userManager.getProfileParent(launchedFromUserId); + final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); + final UserInfo parentInfo = userManager.getProfileParent(launchedFromUserId); if (parentInfo == null || parentInfo.id != UserHandle.myUserId()) { // Caller is not running in a profile of this user return false; @@ -469,7 +468,7 @@ public final class CredentialStorage extends Activity { * Confirm existing key guard, returning password via onActivityResult. */ private boolean confirmKeyGuard(int requestCode) { - Resources res = getResources(); + final Resources res = getResources(); boolean launched = new ChooseLockSettingsHelper(this) .launchConfirmationActivity(requestCode, res.getText(R.string.credentials_title), true); @@ -485,7 +484,7 @@ public final class CredentialStorage extends Activity { */ if (requestCode == CONFIRM_KEY_GUARD_REQUEST) { if (resultCode == Activity.RESULT_OK) { - String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); + final String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); if (!TextUtils.isEmpty(password)) { // success mKeyStore.unlock(password); @@ -520,9 +519,10 @@ public final class CredentialStorage extends Activity { private final TextView mError; private UnlockDialog() { - View view = View.inflate(CredentialStorage.this, R.layout.credentials_dialog, null); + final View view = View.inflate( + CredentialStorage.this, R.layout.credentials_dialog, null); - CharSequence text; + final CharSequence text; if (mRetriesRemaining == -1) { text = getResources().getText(R.string.credentials_unlock_hint); } else if (mRetriesRemaining > 3) { @@ -539,7 +539,7 @@ public final class CredentialStorage extends Activity { mOldPassword.addTextChangedListener(this); mError = (TextView) view.findViewById(R.id.error); - AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) + final AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) .setView(view) .setTitle(R.string.credentials_unlock) .setPositiveButton(android.R.string.ok, this) @@ -575,7 +575,7 @@ public final class CredentialStorage extends Activity { mUnlockConfirmed = false; mError.setVisibility(View.VISIBLE); mKeyStore.unlock(mOldPassword.getText().toString()); - int error = mKeyStore.getLastError(); + final int error = mKeyStore.getLastError(); if (error == KeyStore.NO_ERROR) { mRetriesRemaining = -1; Toast.makeText(CredentialStorage.this, From 80376a5b4632f21340e02d7b474efa3f088a1fdc Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 10 May 2018 14:11:49 -0700 Subject: [PATCH 15/21] Make pref unsearchable for more availibility status. Bug: 72748524 Test: robotest Change-Id: I12b13ac3503f851857787df98a2d2f599c71b9b7 --- .../core/BasePreferenceController.java | 18 ++++---- .../LockdownButtonPreferenceController.java | 5 +-- .../slices/SettingsSliceProvider.java | 4 +- .../core/BasePreferenceControllerTest.java | 43 ++++++++++++++++++- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java index ec934917596..88ba32952a7 100644 --- a/src/com/android/settings/core/BasePreferenceController.java +++ b/src/com/android/settings/core/BasePreferenceController.java @@ -187,6 +187,7 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl public final boolean isAvailable() { final int availabilityStatus = getAvailabilityStatus(); return (availabilityStatus == AVAILABLE + || availabilityStatus == AVAILABLE_UNSEARCHABLE || availabilityStatus == DISABLED_DEPENDENT_SETTING); } @@ -230,16 +231,15 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl * Called by SearchIndexProvider#getNonIndexableKeys */ public void updateNonIndexableKeys(List keys) { - if (this instanceof AbstractPreferenceController) { - if (!isAvailable()) { - final String key = getPreferenceKey(); - if (TextUtils.isEmpty(key)) { - Log.w(TAG, - "Skipping updateNonIndexableKeys due to empty key " + this.toString()); - return; - } - keys.add(key); + final boolean shouldSuppressFromSearch = !isAvailable() + || getAvailabilityStatus() == AVAILABLE_UNSEARCHABLE; + if (shouldSuppressFromSearch) { + final String key = getPreferenceKey(); + if (TextUtils.isEmpty(key)) { + Log.w(TAG, "Skipping updateNonIndexableKeys due to empty key " + toString()); + return; } + keys.add(key); } } diff --git a/src/com/android/settings/security/LockdownButtonPreferenceController.java b/src/com/android/settings/security/LockdownButtonPreferenceController.java index dd6e0d0f7c2..5b29868f06d 100644 --- a/src/com/android/settings/security/LockdownButtonPreferenceController.java +++ b/src/com/android/settings/security/LockdownButtonPreferenceController.java @@ -21,7 +21,6 @@ import android.os.UserHandle; import android.provider.Settings; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.core.BasePreferenceController; import com.android.settings.core.TogglePreferenceController; public class LockdownButtonPreferenceController extends TogglePreferenceController { @@ -36,9 +35,9 @@ public class LockdownButtonPreferenceController extends TogglePreferenceControll @Override public int getAvailabilityStatus() { if (mLockPatternUtils.isSecure(UserHandle.myUserId())) { - return BasePreferenceController.AVAILABLE; + return AVAILABLE; } else { - return BasePreferenceController.DISABLED_FOR_USER; + return DISABLED_FOR_USER; } } diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 179af6e815d..edeb2b5f28c 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -27,9 +27,7 @@ import android.graphics.drawable.Icon; import android.net.Uri; import android.net.wifi.WifiManager; import android.provider.Settings; -import androidx.annotation.VisibleForTesting; import android.provider.SettingsSlicesContract; -import androidx.core.graphics.drawable.IconCompat; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -45,6 +43,8 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import androidx.annotation.VisibleForTesting; +import androidx.core.graphics.drawable.IconCompat; import androidx.slice.Slice; import androidx.slice.SliceProvider; import androidx.slice.builders.ListBuilder; diff --git a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java index 611c1b5fb46..d5e8e15cfa2 100644 --- a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java @@ -16,12 +16,12 @@ package com.android.settings.core; import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; import static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -36,8 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RuntimeEnvironment; +import java.util.ArrayList; +import java.util.List; + import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; @RunWith(SettingsRobolectricTestRunner.class) @@ -72,6 +74,13 @@ public class BasePreferenceControllerTest { assertThat(mPreferenceController.isAvailable()).isTrue(); } + @Test + public void isAvailable_availableStatusUnSearchable_returnsTrue() { + mPreferenceController.setAvailability(AVAILABLE_UNSEARCHABLE); + + assertThat(mPreferenceController.isAvailable()).isTrue(); + } + @Test public void isAvailable_availableStatusUnsupportedOnDevice_returnsFalse() { mPreferenceController.setAvailability(UNSUPPORTED_ON_DEVICE); @@ -159,6 +168,36 @@ public class BasePreferenceControllerTest { assertThat(preference.isEnabled()).isFalse(); } + @Test + public void updateNonIndexableKeys_controllerUnavailable_shouldAddKey() { + final List keys = new ArrayList<>(); + mPreferenceController.setAvailability(UNSUPPORTED_ON_DEVICE); + + mPreferenceController.updateNonIndexableKeys(keys); + + assertThat(keys).containsExactly(mPreferenceController.getPreferenceKey()); + } + + @Test + public void updateNonIndexableKeys_controllerUnsearchable_shouldAddKey() { + final List keys = new ArrayList<>(); + mPreferenceController.setAvailability(AVAILABLE_UNSEARCHABLE); + + mPreferenceController.updateNonIndexableKeys(keys); + + assertThat(keys).containsExactly(mPreferenceController.getPreferenceKey()); + } + + @Test + public void updateNonIndexableKeys_controllerAvailable_shouldNotAddKey() { + final List keys = new ArrayList<>(); + mPreferenceController.setAvailability(AVAILABLE); + + mPreferenceController.updateNonIndexableKeys(keys); + + assertThat(keys).isEmpty(); + } + private class FakeBasePreferenceController extends BasePreferenceController { public int mAvailable; From ea04e32eed77867938b17706f0f6c9cf32b9f2c6 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 11 May 2018 13:32:32 -0700 Subject: [PATCH 16/21] Update screen title for lock screen preferences. Bug: 71892510 Test: visual Change-Id: I4abe0c2370f10bb68e668c07a033852601b4c2ab --- res/values/strings.xml | 8 +++++--- .../settings/security/LockscreenDashboardFragment.java | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 8fb972d5026..5704c22fddd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -849,9 +849,10 @@ Device encrypted Device not encrypted - - Lock screen preferences - + + Lock screen display + + What to show Set My Location, screen unlock, SIM card lock, credential storage lock @@ -2645,6 +2646,7 @@ Always on / Increased battery usage New notifications + When to show diff --git a/src/com/android/settings/security/LockscreenDashboardFragment.java b/src/com/android/settings/security/LockscreenDashboardFragment.java index c9ed2c2af77..1cabb92ae19 100644 --- a/src/com/android/settings/security/LockscreenDashboardFragment.java +++ b/src/com/android/settings/security/LockscreenDashboardFragment.java @@ -18,7 +18,6 @@ package com.android.settings.security; import android.content.Context; import android.provider.SearchIndexableResource; -import androidx.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -34,6 +33,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import androidx.annotation.VisibleForTesting; + /** * Settings screen for lock screen preference */ From d4e7eedfc9344abe36e6e79fc3cd7126321287cc Mon Sep 17 00:00:00 2001 From: Beverly Date: Wed, 9 May 2018 15:27:45 -0400 Subject: [PATCH 17/21] DO NOT MERGE Add DND Settings suggestion Test: SettingsSuggestionsTest, ZenOnboardingActivityTest Change-Id: Ie78c9cf8287ee56bc4596efe20d27f8eb432ab6c Bug: 78445134 --- AndroidManifest.xml | 22 ++++- res/drawable/ic_zen.xml | 12 +-- res/values/strings.xml | 6 ++ .../SuggestionFeatureProviderImpl.java | 5 +- .../settings/notification/ZenModeBackend.java | 3 + .../notification/ZenOnboardingActivity.java | 88 +++++++++++++++++- .../notification/ZenSuggestionActivity.java | 24 +++++ .../ZenOnboardingActivityTest.java | 89 ++++++++++++++++++- .../suggestions/SettingsSuggestionsTest.java | 10 +++ .../NewDeviceIntroSuggestionActivityTest.java | 2 +- 10 files changed, 246 insertions(+), 15 deletions(-) create mode 100644 src/com/android/settings/notification/ZenSuggestionActivity.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 060429e9007..d55493cdbd0 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -742,6 +742,27 @@ android:value="true" /> + + + + + + + + + + + + + + - + android:viewportHeight="24.0" + android:viewportWidth="24.0" + android:height="24dp" + android:width="24dp" > + android:fillColor="?android:attr/colorControlActivated" + android:pathData="M 12 2 C 6.48 2 2 6.48 2 12 s 4.48 10 10 10 10 -4.48 10 -10 S 17.52 2 12 2 z m 4 11 H 8 c -.55 0 -1 -.45 -1 -1 s .45 -1 1 -1 h 8c.55 0 1 .45 1 1 s -.45 1 -1 1z" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index 8bdfb5f857a..da957918836 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9874,6 +9874,12 @@ + + Update Do Not Disturb + + + Hide notifications to stay focused + What\'s new and exciting? diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java index d0c0b253baa..257e8c39024 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.service.settings.suggestions.Suggestion; import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; import android.util.Log; import android.util.Pair; @@ -32,6 +31,8 @@ import com.android.settings.Settings.NightDisplaySuggestionActivity; import com.android.settings.display.NightDisplayPreferenceController; import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity; import com.android.settings.fingerprint.FingerprintSuggestionActivity; +import com.android.settings.notification.ZenOnboardingActivity; +import com.android.settings.notification.ZenSuggestionActivity; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ScreenLockSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity; @@ -88,6 +89,8 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider return NightDisplayPreferenceController.isSuggestionComplete(context); } else if (className.equals(NewDeviceIntroSuggestionActivity.class.getName())) { return NewDeviceIntroSuggestionActivity.isSuggestionComplete(context); + } else if (className.equals(ZenSuggestionActivity.class.getName())) { + return ZenOnboardingActivity.isSuggestionComplete(context); } return false; } diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java index d5792564cc2..9e2b650346a 100644 --- a/src/com/android/settings/notification/ZenModeBackend.java +++ b/src/com/android/settings/notification/ZenModeBackend.java @@ -135,6 +135,9 @@ public class ZenModeBackend { } protected void saveVisualEffectsPolicy(int category, boolean suppress) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + int suppressedEffects = getNewSuppressedEffects(suppress, category); savePolicy(mPolicy.priorityCategories, mPolicy.priorityCallSenders, mPolicy.priorityMessageSenders, suppressedEffects); diff --git a/src/com/android/settings/notification/ZenOnboardingActivity.java b/src/com/android/settings/notification/ZenOnboardingActivity.java index 9d71f54c712..ff86ef6ff34 100644 --- a/src/com/android/settings/notification/ZenOnboardingActivity.java +++ b/src/com/android/settings/notification/ZenOnboardingActivity.java @@ -19,16 +19,33 @@ package com.android.settings.notification; import android.app.Activity; import android.app.NotificationManager; import android.app.NotificationManager.Policy; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.VisibleForTesting; +import android.provider.Settings; +import android.text.format.DateUtils; +import android.util.Log; import android.view.View; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; +import com.android.settings.overlay.FeatureFactory; public class ZenOnboardingActivity extends Activity { + private static final String TAG = "ZenOnboardingActivity"; + + @VisibleForTesting + static final String PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME = + "pref_zen_suggestion_first_display_time_ms"; + @VisibleForTesting + static final String PREF_KEY_SUGGESTION_VIEWED = "pref_zen_suggestion_viewed"; + @VisibleForTesting + static final long ALWAYS_SHOW_THRESHOLD = DateUtils.DAY_IN_MILLIS * 14; + private NotificationManager mNm; private MetricsLogger mMetrics; @@ -38,6 +55,10 @@ public class ZenOnboardingActivity extends Activity { setNotificationManager(getSystemService(NotificationManager.class)); setMetricsLogger(new MetricsLogger()); + Context context = getApplicationContext(); + Settings.Global.putInt(context.getContentResolver(), + Settings.Global.ZEN_SETTINGS_SUGGESTION_VIEWED, 1); + setupUI(); } @@ -60,20 +81,79 @@ public class ZenOnboardingActivity extends Activity { public void close(View button) { mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); + + Settings.Global.putInt(getApplicationContext().getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + finishAndRemoveTask(); } public void save(View button) { mMetrics.action(MetricsEvent.ACTION_ZEN_ONBOARDING_OK); - Policy policy = mNm.getNotificationPolicy(); + NotificationManager.Policy policy = mNm.getNotificationPolicy(); - Policy newPolicy = new NotificationManager.Policy( + NotificationManager.Policy newPolicy = new NotificationManager.Policy( Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | policy.priorityCategories, Policy.PRIORITY_SENDERS_STARRED, policy.priorityMessageSenders, - Policy.getAllSuppressedVisualEffects()); + NotificationManager.Policy.getAllSuppressedVisualEffects()); mNm.setNotificationPolicy(newPolicy); + Settings.Global.putInt(getApplicationContext().getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 1); + finishAndRemoveTask(); } + + public static boolean isSuggestionComplete(Context context) { + if (wasZenUpdated(context)) { + return true; + } + + if (showSuggestion(context) || withinShowTimeThreshold(context)) { + return false; + } + + return true; + } + + private static boolean wasZenUpdated(Context context) { + // ZEN_SETTINGS_UPDATED is true for: + // - fresh P+ device + // - if zen visual effects values were changed by the user in Settings + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, 0) != 0; + } + + private static boolean showSuggestion(Context context) { + // SHOW_ZEN_SETTINGS_SUGGESTION is by default true, but false when: + // - user manually turns on dnd + + // SHOW_ZEN_SETTINGS_SUGGESTION is also true when: + // - automatic rule has started DND and user has not seen the first use dialog + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, 0) != 0; + + } + + private static boolean withinShowTimeThreshold(Context context) { + final SuggestionFeatureProvider featureProvider = FeatureFactory.getFactory(context) + .getSuggestionFeatureProvider(context); + final SharedPreferences prefs = featureProvider.getSharedPrefs(context); + final long currentTimeMs = System.currentTimeMillis(); + final long firstDisplayTimeMs; + + if (!prefs.contains(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME)) { + firstDisplayTimeMs = currentTimeMs; + prefs.edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, currentTimeMs).commit(); + } else { + firstDisplayTimeMs = prefs.getLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, -1); + } + + final long showTimeMs = firstDisplayTimeMs + ALWAYS_SHOW_THRESHOLD; + final boolean stillShow = currentTimeMs < showTimeMs; + + Log.d(TAG, "still show zen suggestion based on time: " + stillShow); + return stillShow; + } } diff --git a/src/com/android/settings/notification/ZenSuggestionActivity.java b/src/com/android/settings/notification/ZenSuggestionActivity.java new file mode 100644 index 00000000000..9d2148c7e50 --- /dev/null +++ b/src/com/android/settings/notification/ZenSuggestionActivity.java @@ -0,0 +1,24 @@ +package com.android.settings.notification; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.provider.Settings; + +public class ZenSuggestionActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // start up zen settings activity + Intent settingsIntent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); + startActivity(settingsIntent); + + // start up onboarding activity + Intent onboardingActivity = new Intent(Settings.ZEN_MODE_ONBOARDING); + startActivity(onboardingActivity); + + finish(); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java index 7bc93713977..b4d3700bece 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenOnboardingActivityTest.java @@ -29,6 +29,12 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OF import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static com.android.settings.notification.ZenOnboardingActivity.ALWAYS_SHOW_THRESHOLD; +import static com.android.settings.notification.ZenOnboardingActivity.PREF_KEY_SUGGESTION_VIEWED; +import static com.android.settings.notification.ZenOnboardingActivity + .PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME; +import static com.android.settings.notification.ZenOnboardingActivity.isSuggestionComplete; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -39,20 +45,22 @@ import static org.mockito.Mockito.when; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; +import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class ZenOnboardingActivityTest { @@ -64,6 +72,9 @@ public class ZenOnboardingActivityTest { ZenOnboardingActivity mActivity; + private Context mContext; + private FakeFeatureFactory mFeatureFactory; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -75,6 +86,11 @@ public class ZenOnboardingActivityTest { mActivity.setMetricsLogger(mMetricsLogger); mActivity.setupUI(); + + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mFeatureFactory.suggestionsFeatureProvider.getSharedPrefs(any(Context.class))) + .thenReturn(getSharedPreferences()); } @Test @@ -124,4 +140,73 @@ public class ZenOnboardingActivityTest { verify(mNm, never()).setNotificationPolicy(any()); } + + @Test + public void isSuggestionComplete_zenUpdated() { + setZenUpdated(true); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(true); + assertThat(isSuggestionComplete(mContext)).isTrue(); + } + + @Test + public void isSuggestionComplete_withinTimeThreshold() { + setZenUpdated(false); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(true); + assertThat(isSuggestionComplete(mContext)).isFalse(); + } + + @Test + public void isSuggestionComplete_showSettingsSuggestionTrue() { + setZenUpdated(false); + setShowSettingsSuggestion(true); + setWithinTimeThreshold(false); + assertThat(isSuggestionComplete(mContext)).isFalse(); + } + + @Test + public void isSuggestionComplete_showSettingsSuggestionFalse_notWithinTimeThreshold() { + setZenUpdated(false); + setShowSettingsSuggestion(false); + setWithinTimeThreshold(false); + assertThat(isSuggestionComplete(mContext)).isTrue(); + } + + private void setZenUpdated(boolean updated) { + int zenUpdated = 0; + if (updated) { + zenUpdated = 1; + } + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.ZEN_SETTINGS_UPDATED, zenUpdated); + } + + private void setWithinTimeThreshold(boolean withinTime) { + long firstTime = System.currentTimeMillis(); + + if (withinTime) { + firstTime -= ALWAYS_SHOW_THRESHOLD / 2; + } else { + firstTime -= ALWAYS_SHOW_THRESHOLD * 2; + } + + getSharedPreferences().edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, + firstTime).commit(); + } + + private void setShowSettingsSuggestion(boolean show) { + int showZenSuggestion = 0; + if (show) { + showZenSuggestion = 1; + } + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.SHOW_ZEN_SETTINGS_SUGGESTION, showZenSuggestion); + } + + private SharedPreferences getSharedPreferences() { + return mContext.getSharedPreferences("test_zen_sugg", Context.MODE_PRIVATE); + } } diff --git a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java index bb14667fce8..c6583c7eb03 100644 --- a/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java +++ b/tests/robotests/src/com/android/settings/suggestions/SettingsSuggestionsTest.java @@ -30,6 +30,8 @@ import com.android.settings.R; import com.android.settings.Settings; import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity; import com.android.settings.fingerprint.FingerprintSuggestionActivity; +import com.android.settings.notification.ZenOnboardingActivity; +import com.android.settings.notification.ZenSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.wallpaper.WallpaperSuggestionActivity; @@ -82,6 +84,14 @@ public class SettingsSuggestionsTest { R.string.night_display_suggestion_summary); } + @Test + public void zenSuggestion_isValid() { + assertSuggestionEquals( + ZenSuggestionActivity.class.getName(), + R.string.zen_suggestion_title, + R.string.zen_suggestion_summary); + } + @Test public void newDeviceIntroSuggestion_isValid() { assertSuggestionEquals( diff --git a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java index 15975689c7e..286676dd0d0 100644 --- a/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java +++ b/tests/robotests/src/com/android/settings/support/NewDeviceIntroSuggestionActivityTest.java @@ -78,7 +78,7 @@ public class NewDeviceIntroSuggestionActivityTest { final long currentTime = System.currentTimeMillis(); getSharedPreferences().edit().putLong(PREF_KEY_SUGGGESTION_FIRST_DISPLAY_TIME, - currentTime - 2 * PERMANENT_DISMISS_THRESHOLD); + currentTime - 2 * PERMANENT_DISMISS_THRESHOLD).commit(); assertThat(isSuggestionComplete(mContext)).isTrue(); } From 0f447022cf8808ae3879547b326a97d4d0296b99 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Thu, 10 May 2018 20:11:26 -0700 Subject: [PATCH 18/21] Unrestricting app when put on power whitelist Power whitelisting and background restrictions are opposing rules, so to keep apps out of confusing states, unrestricting an app whenever it is put on the power whitelist. Test: atest RunSettingsRoboTests:HighPowerDetailTest Bug: 77924141 Change-Id: I4952ac6c893bc7e98aa1b6ad3a86906fc299dea5 --- res/values/strings.xml | 2 +- .../ManageApplications.java | 2 +- .../settings/fuelgauge/HighPowerDetail.java | 23 +++++++++++--- .../fuelgauge/HighPowerDetailTest.java | 31 +++++++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index c8dad37afa6..5f45a3f348c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8698,7 +8698,7 @@ Optimize - May drain your battery more quickly + May drain your battery more quickly. App will no longer be restricted from using background battery. Recommended for better battery life diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 301e71bfe4b..328d4a28146 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -545,7 +545,7 @@ public class ManageApplications extends InstrumentedFragment startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings); break; case LIST_TYPE_HIGH_POWER: - HighPowerDetail.show(this, mCurrentPkgName, INSTALLED_APP_DETAILS); + HighPowerDetail.show(this, mCurrentUid, mCurrentPkgName, INSTALLED_APP_DETAILS); break; case LIST_TYPE_OVERLAY: startAppInfoFragment(DrawOverlayDetails.class, R.string.overlay_settings); diff --git a/src/com/android/settings/fuelgauge/HighPowerDetail.java b/src/com/android/settings/fuelgauge/HighPowerDetail.java index 9cafbcba491..4f707008953 100644 --- a/src/com/android/settings/fuelgauge/HighPowerDetail.java +++ b/src/com/android/settings/fuelgauge/HighPowerDetail.java @@ -17,6 +17,7 @@ package com.android.settings.fuelgauge; import android.app.AlertDialog; +import android.app.AppOpsManager; import android.app.Dialog; import android.app.Fragment; import android.content.Context; @@ -43,12 +44,18 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli private static final String ARG_DEFAULT_ON = "default_on"; - private final PowerWhitelistBackend mBackend = PowerWhitelistBackend.getInstance(); - - private String mPackageName; + @VisibleForTesting + PowerWhitelistBackend mBackend; + @VisibleForTesting + BatteryUtils mBatteryUtils; + @VisibleForTesting + String mPackageName; + @VisibleForTesting + int mPackageUid; private CharSequence mLabel; private boolean mDefaultOn; - private boolean mIsEnabled; + @VisibleForTesting + boolean mIsEnabled; private Checkable mOptionOn; private Checkable mOptionOff; @@ -60,8 +67,11 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mBatteryUtils = BatteryUtils.getInstance(getContext()); + mBackend = PowerWhitelistBackend.getInstance(); mPackageName = getArguments().getString(AppInfoBase.ARG_PACKAGE_NAME); + mPackageUid = getArguments().getInt(AppInfoBase.ARG_PACKAGE_UID); PackageManager pm = getContext().getPackageManager(); try { mLabel = pm.getApplicationInfo(mPackageName, 0).loadLabel(pm); @@ -129,6 +139,8 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli if (newValue != oldValue) { logSpecialPermissionChange(newValue, mPackageName, getContext()); if (newValue) { + mBatteryUtils.setForceAppStandby(mPackageUid, mPackageName, + AppOpsManager.MODE_ALLOWED); mBackend.addApp(mPackageName); } else { mBackend.removeApp(mPackageName); @@ -165,10 +177,11 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli : R.string.high_power_off); } - public static void show(Fragment caller, String packageName, int requestCode) { + public static void show(Fragment caller, int uid, String packageName, int requestCode) { HighPowerDetail fragment = new HighPowerDetail(); Bundle args = new Bundle(); args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); + args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid); fragment.setArguments(args); fragment.setTargetFragment(caller, requestCode); fragment.show(caller.getFragmentManager(), HighPowerDetail.class.getSimpleName()); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/HighPowerDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/HighPowerDetailTest.java index 8029c5539ef..1817325e15a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/HighPowerDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/HighPowerDetailTest.java @@ -18,27 +18,49 @@ package com.android.settings.fuelgauge; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.content.Context; +import android.content.DialogInterface; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.fuelgauge.PowerWhitelistBackend; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class HighPowerDetailTest { + private static final int TEST_UID = 12000; + private static final String TEST_PACKAGE = "com.test.package"; private FakeFeatureFactory mFeatureFactory; + private HighPowerDetail mFragment; + + @Mock + private PowerWhitelistBackend mPowerWhitelistBackend; + @Mock + private BatteryUtils mBatteryUtils; @Before public void setUp() { mFeatureFactory = FakeFeatureFactory.setupForTest(); + + MockitoAnnotations.initMocks(this); + mFragment = spy(new HighPowerDetail()); + mFragment.mBackend = mPowerWhitelistBackend; + mFragment.mBatteryUtils = mBatteryUtils; + mFragment.mPackageUid = TEST_UID; + mFragment.mPackageName = TEST_PACKAGE; } @Test @@ -53,4 +75,13 @@ public class HighPowerDetailTest { verify(mFeatureFactory.metricsFeatureProvider).action(any(Context.class), eq(MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_BATTERY_ALLOW), eq("app")); } + + @Test + public void onClick_appAddedToDozeWhitelist_getsUnrestricted() { + mFragment.mIsEnabled = true; + when(mPowerWhitelistBackend.isWhitelisted(TEST_PACKAGE)).thenReturn(false); + mFragment.onClick(null, DialogInterface.BUTTON_POSITIVE); + verify(mBatteryUtils).setForceAppStandby(TEST_UID, TEST_PACKAGE, + AppOpsManager.MODE_ALLOWED); + } } From 362d783a17837fd50850c5af90cc1ebdbb22d375 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Fri, 11 May 2018 13:00:23 -0700 Subject: [PATCH 19/21] Update the initial expanded count for apps and notifications. - increase it by 1 to accomodate the injected setting. Change-Id: I0e131c87ffbf2b296b66717b2c6f160abb3b3269 Fixes: 77823915 Test: visual --- res/xml/app_and_notification.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/xml/app_and_notification.xml b/res/xml/app_and_notification.xml index e3319e9b235..53e575f6f9a 100644 --- a/res/xml/app_and_notification.xml +++ b/res/xml/app_and_notification.xml @@ -20,7 +20,8 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="apps_and_notification_screen" android:title="@string/app_and_notification_dashboard_title" - settings:initialExpandedChildrenCount="7"> + settings:initialExpandedChildrenCount="8"> + Date: Thu, 10 May 2018 18:07:27 +0000 Subject: [PATCH 20/21] Add help uri for restricted apps page Bug: 77299457 Test: Build Change-Id: I46c208f9805f47a4f42e44338ea5dce0451dd671 --- res/values/strings.xml | 3 +++ src/com/android/settings/fuelgauge/RestrictedAppDetails.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 5c33e9c0700..d06995a37c9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9865,6 +9865,9 @@ + + + diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java index 23b4067a007..5a7f4bad8bd 100644 --- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java +++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java @@ -122,6 +122,11 @@ public class RestrictedAppDetails extends DashboardFragment { return MetricsProto.MetricsEvent.FUELGAUGE_RESTRICTED_APP_DETAILS; } + @Override + public int getHelpResource() { + return R.string.help_uri_restricted_apps; + } + @VisibleForTesting void refreshUi() { mRestrictedAppListGroup.removeAll(); From d2b295ba36a7b8e237c3792abd177020d1046227 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Wed, 9 May 2018 17:27:17 -0700 Subject: [PATCH 21/21] Update the battery broadcast receiver. Add a type for battery receiver, then in callback client know for which reason it been invoked: 1. battery level change 2. battery saver state change 3. battery plug state change So in this CL, we won't update battery tip for battery level change, then battery tip won't be dismissed by itself. Also note in onResume() we will manually update battery tip. So if user stay in battery settings page and close the screen, once he opens it we will still force update everything. Fixes: 79171742 Test: RunSettingsRoboTests Change-Id: I997844216fd8267e545d74e0d434de9e338f76a1 --- .../fuelgauge/BatteryBroadcastReceiver.java | 35 +++++++++--- .../fuelgauge/PowerUsageAdvanced.java | 7 ++- .../settings/fuelgauge/PowerUsageBase.java | 55 ++++++++++++------- .../settings/fuelgauge/PowerUsageSummary.java | 25 ++++----- .../BatteryBroadcastReceiverTest.java | 13 +++-- .../fuelgauge/PowerUsageAdvancedTest.java | 3 +- .../fuelgauge/PowerUsageBaseTest.java | 2 +- .../fuelgauge/PowerUsageSummaryTest.java | 26 +++++---- 8 files changed, 103 insertions(+), 63 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java index c051604d113..bd64dd3d4c7 100644 --- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java @@ -21,9 +21,15 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.PowerManager; + +import androidx.annotation.IntDef; import androidx.annotation.VisibleForTesting; import com.android.settings.Utils; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Use this broadcastReceiver to listen to the battery change, and it will invoke @@ -43,7 +49,19 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { * Battery saver(e.g. off->on) */ public interface OnBatteryChangedListener { - void onBatteryChanged(); + void onBatteryChanged(@BatteryUpdateType int type); + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({BatteryUpdateType.MANUAL, + BatteryUpdateType.BATTERY_LEVEL, + BatteryUpdateType.BATTERY_SAVER, + BatteryUpdateType.BATTERY_STATUS}) + public @interface BatteryUpdateType { + int MANUAL = 0; + int BATTERY_LEVEL = 1; + int BATTERY_SAVER = 2; + int BATTERY_STATUS = 3; } @VisibleForTesting @@ -85,14 +103,17 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { final String batteryLevel = Utils.getBatteryPercentage(intent); final String batteryStatus = Utils.getBatteryStatus( mContext.getResources(), intent); - if (forceUpdate || !batteryLevel.equals(mBatteryLevel) || !batteryStatus.equals( - mBatteryStatus)) { - mBatteryLevel = batteryLevel; - mBatteryStatus = batteryStatus; - mBatteryListener.onBatteryChanged(); + if (forceUpdate) { + mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL); + } else if(!batteryLevel.equals(mBatteryLevel)) { + mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL); + } else if (!batteryStatus.equals(mBatteryStatus)) { + mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS); } + mBatteryLevel = batteryLevel; + mBatteryStatus = batteryStatus; } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) { - mBatteryListener.onBatteryChanged(); + mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER); } } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java index a318e160918..74098ffb9a0 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -13,6 +13,8 @@ */ package com.android.settings.fuelgauge; +import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; + import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -33,6 +35,7 @@ import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.utils.StringUtil; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -108,7 +111,7 @@ public class PowerUsageAdvanced extends PowerUsageBase { mMetricsFeatureProvider.action(getContext(), MetricsProto.MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, mShowAllApps); - restartBatteryStatsLoader(); + restartBatteryStatsLoader(BatteryUpdateType.MANUAL); return true; default: return super.onOptionsItemSelected(item); @@ -140,7 +143,7 @@ public class PowerUsageAdvanced extends PowerUsageBase { } @Override - protected void refreshUi() { + protected void refreshUi(@BatteryUpdateType int refreshType) { final Context context = getContext(); if (context == null) { return; diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java index f924e46b0f3..aa029191a86 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageBase.java +++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java @@ -15,6 +15,8 @@ */ package com.android.settings.fuelgauge; +import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.*; + import android.app.Activity; import android.app.LoaderManager; import android.content.Context; @@ -26,18 +28,17 @@ import android.view.Menu; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.dashboard.DashboardFragment; -import com.android.settingslib.utils.AsyncLoader; /** * Common base class for things that need to show the battery usage graph. */ -public abstract class PowerUsageBase extends DashboardFragment - implements LoaderManager.LoaderCallbacks { +public abstract class PowerUsageBase extends DashboardFragment { // +1 to allow ordering for PowerUsageSummary. @VisibleForTesting static final int MENU_STATS_REFRESH = Menu.FIRST + 1; private static final String TAG = "PowerUsageBase"; + private static final String KEY_REFRESH_TYPE = "refresh_type"; protected BatteryStatsHelper mStatsHelper; protected UserManager mUm; @@ -57,8 +58,8 @@ public abstract class PowerUsageBase extends DashboardFragment setHasOptionsMenu(true); mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext()); - mBatteryBroadcastReceiver.setBatteryChangedListener(() -> { - restartBatteryStatsLoader(); + mBatteryBroadcastReceiver.setBatteryChangedListener(type -> { + restartBatteryStatsLoader(type); }); } @@ -81,11 +82,14 @@ public abstract class PowerUsageBase extends DashboardFragment mBatteryBroadcastReceiver.unRegister(); } - protected void restartBatteryStatsLoader() { - getLoaderManager().restartLoader(0, Bundle.EMPTY, this); + protected void restartBatteryStatsLoader(int refreshType) { + final Bundle bundle = new Bundle(); + bundle.putInt(KEY_REFRESH_TYPE, refreshType); + + getLoaderManager().restartLoader(0, bundle, new PowerLoaderCallback()); } - protected abstract void refreshUi(); + protected abstract void refreshUi(@BatteryUpdateType int refreshType); protected void updatePreference(BatteryHistoryPreference historyPref) { final long startTime = System.currentTimeMillis(); @@ -93,21 +97,30 @@ public abstract class PowerUsageBase extends DashboardFragment BatteryUtils.logRuntime(TAG, "updatePreference", startTime); } - @Override - public Loader onCreateLoader(int id, - Bundle args) { - return new BatteryStatsHelperLoader(getContext()); - } + /** + * {@link android.app.LoaderManager.LoaderCallbacks} for {@link PowerUsageBase} to load + * the {@link BatteryStatsHelper} + */ + public class PowerLoaderCallback implements LoaderManager.LoaderCallbacks { + private int mRefreshType; - @Override - public void onLoadFinished(Loader loader, - BatteryStatsHelper statsHelper) { - mStatsHelper = statsHelper; - refreshUi(); - } + @Override + public Loader onCreateLoader(int id, + Bundle args) { + mRefreshType = args.getInt(KEY_REFRESH_TYPE); + return new BatteryStatsHelperLoader(getContext()); + } - @Override - public void onLoaderReset(Loader loader) { + @Override + public void onLoadFinished(Loader loader, + BatteryStatsHelper statsHelper) { + mStatsHelper = statsHelper; + refreshUi(mRefreshType); + } + @Override + public void onLoaderReset(Loader loader) { + + } } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index af69cee2d0f..82cd16a796b 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -16,6 +16,8 @@ package com.android.settings.fuelgauge; +import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; + import android.app.Activity; import android.app.LoaderManager; import android.app.LoaderManager.LoaderCallbacks; @@ -279,7 +281,7 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList } else { mStatsType = BatteryStats.STATS_SINCE_CHARGED; } - refreshUi(); + refreshUi(BatteryUpdateType.MANUAL); return true; case MENU_ADVANCED_BATTERY: new SubSettingLauncher(getContext()) @@ -293,14 +295,15 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList } } - protected void refreshUi() { + protected void refreshUi(@BatteryUpdateType int refreshType) { final Context context = getContext(); if (context == null) { return; } - // Only skip BatteryTipLoader for the first time when device is rotated - if (mNeedUpdateBatteryTip) { + // Skip BatteryTipLoader if device is rotated or only battery level change + if (mNeedUpdateBatteryTip + && refreshType != BatteryUpdateType.BATTERY_LEVEL) { restartBatteryTipLoader(); } else { mNeedUpdateBatteryTip = true; @@ -399,8 +402,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList } @Override - protected void restartBatteryStatsLoader() { - restartBatteryStatsLoader(true /* clearHeader */); + protected void restartBatteryStatsLoader(@BatteryUpdateType int refreshType) { + super.restartBatteryStatsLoader(refreshType); + mBatteryHeaderPreferenceController.quickUpdateHeaderPreference(); } @Override @@ -409,13 +413,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList mBatteryTipPreferenceController.saveInstanceState(outState); } - void restartBatteryStatsLoader(boolean clearHeader) { - super.restartBatteryStatsLoader(); - if (clearHeader) { - mBatteryHeaderPreferenceController.quickUpdateHeaderPreference(); - } - } - @Override public void onBatteryTipHandled(BatteryTip batteryTip) { restartBatteryTipLoader(); @@ -430,7 +427,7 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList mContext = context; mLoader = loader; mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext); - mBatteryBroadcastReceiver.setBatteryChangedListener(() -> { + mBatteryBroadcastReceiver.setBatteryChangedListener(type -> { BatteryInfo.getBatteryInfo(mContext, new BatteryInfo.Callback() { @Override public void onBatteryInfoLoaded(BatteryInfo info) { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java index 3fdbe837425..4583dd1b3b4 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java @@ -15,8 +15,11 @@ */ package com.android.settings.fuelgauge; +import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -70,14 +73,14 @@ public class BatteryBroadcastReceiverTest { } @Test - public void testOnReceive_batteryDataChanged_dataUpdated() { + public void testOnReceive_batteryLevelChanged_dataUpdated() { mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent); assertThat(mBatteryBroadcastReceiver.mBatteryLevel) .isEqualTo(Utils.getBatteryPercentage(mChargingIntent)); assertThat(mBatteryBroadcastReceiver.mBatteryStatus) .isEqualTo(Utils.getBatteryStatus(mContext.getResources(), mChargingIntent)); - verify(mBatteryListener).onBatteryChanged(); + verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL); } @Test @@ -85,7 +88,7 @@ public class BatteryBroadcastReceiverTest { mBatteryBroadcastReceiver.onReceive(mContext, new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); - verify(mBatteryListener).onBatteryChanged(); + verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_SAVER); } @Test @@ -100,7 +103,7 @@ public class BatteryBroadcastReceiverTest { assertThat(mBatteryBroadcastReceiver.mBatteryLevel).isEqualTo(batteryLevel); assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(batteryStatus); - verify(mBatteryListener, never()).onBatteryChanged(); + verify(mBatteryListener, never()).onBatteryChanged(anyInt()); } @Test @@ -115,6 +118,6 @@ public class BatteryBroadcastReceiverTest { assertThat(mBatteryBroadcastReceiver.mBatteryStatus) .isEqualTo(Utils.getBatteryStatus(mContext.getResources(), mChargingIntent)); // 2 times because register will force update the battery - verify(mBatteryListener, times(2)).onBatteryChanged(); + verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java index 8a7e7a04687..ffa49d4f253 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -86,7 +87,7 @@ public class PowerUsageAdvancedTest { @Test public void testOptionsMenu_menuAppToggle_metricEventInvoked() { mFragment.mShowAllApps = false; - doNothing().when(mFragment).restartBatteryStatsLoader(); + doNothing().when(mFragment).restartBatteryStatsLoader(anyInt()); mFragment.onOptionsItemSelected(mToggleAppsMenu); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java index d9f572deefa..eb683c072e0 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java @@ -74,7 +74,7 @@ public class PowerUsageBaseTest { } @Override - protected void refreshUi() { + protected void refreshUi(int refreshType) { // Do nothing } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index b48f00e295b..07341a14656 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -149,7 +149,7 @@ public class PowerUsageSummaryTest { mFragment.initFeatureProvider(); mBatteryMeterView = new BatteryMeterView(mRealContext); mBatteryMeterView.mDrawable = new BatteryMeterView.BatteryMeterDrawable(mRealContext, 0); - doNothing().when(mFragment).restartBatteryStatsLoader(); + doNothing().when(mFragment).restartBatteryStatsLoader(anyInt()); doReturn(mock(LoaderManager.class)).when(mFragment).getLoaderManager(); doReturn(MENU_ADVANCED_BATTERY).when(mAdvancedPageMenu).getItemId(); @@ -316,15 +316,6 @@ public class PowerUsageSummaryTest { verify(mSummary1, times(2)).setOnLongClickListener(any(View.OnLongClickListener.class)); } - @Test - public void restartBatteryStatsLoader_notClearHeader_quickUpdateNotInvoked() { - mFragment.mBatteryHeaderPreferenceController = mBatteryHeaderPreferenceController; - - mFragment.restartBatteryStatsLoader(false /* clearHeader */); - - verify(mBatteryHeaderPreferenceController, never()).quickUpdateHeaderPreference(); - } - @Test public void optionsMenu_advancedPageEnabled() { when(mFeatureFactory.powerUsageFeatureProvider.isPowerAccountingToggleEnabled()) @@ -360,7 +351,18 @@ public class PowerUsageSummaryTest { when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(false); mFragment.updateBatteryTipFlag(new Bundle()); - mFragment.refreshUi(); + mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL); + + verify(mFragment, never()).restartBatteryTipLoader(); + } + + @Test + public void refreshUi_batteryLevelChanged_doNotUpdateBatteryTip() { + mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class); + when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true); + mFragment.updateBatteryTipFlag(new Bundle()); + + mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_LEVEL); verify(mFragment, never()).restartBatteryTipLoader(); } @@ -371,7 +373,7 @@ public class PowerUsageSummaryTest { when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true); mFragment.updateBatteryTipFlag(new Bundle()); - mFragment.refreshUi(); + mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL); verify(mFragment).restartBatteryTipLoader(); }