Merge "Fallback Home doesn't restart on keyboard change" into tm-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5877b13..e621ca9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -9,7 +9,9 @@
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGE" />
+ <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+ <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/res/layout/dream_preview_button.xml b/res/layout/dream_preview_button.xml
index b347863..f4d7ca1 100644
--- a/res/layout/dream_preview_button.xml
+++ b/res/layout/dream_preview_button.xml
@@ -24,10 +24,10 @@
android:layout_height="wrap_content"
android:text="@string/dream_preview_button_title"
android:textAllCaps="false"
- android:textColor="?androidprv:attr/textColorOnAccent"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:theme="@style/Theme.CollapsingToolbar.Settings"
android:layout_marginBottom="16dp"
android:layout_gravity="bottom|center"
app:backgroundTint="?androidprv:attr/colorAccentPrimaryVariant"
- app:iconTint="?androidprv:attr/textColorOnAccent"
+ app:iconTint="?android:attr/textColorPrimaryInverse"
app:icon="@drawable/dream_preview_icon"/>
diff --git a/res/layout/settings_homepage_app_bar_regular_phone_layout.xml b/res/layout/settings_homepage_app_bar_regular_phone_layout.xml
index 110376b..f817dd4 100644
--- a/res/layout/settings_homepage_app_bar_regular_phone_layout.xml
+++ b/res/layout/settings_homepage_app_bar_regular_phone_layout.xml
@@ -19,6 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
android:orientation="vertical">
<ImageView
diff --git a/res/layout/settings_homepage_app_bar_two_pane_layout.xml b/res/layout/settings_homepage_app_bar_two_pane_layout.xml
index 3777f61..4178632 100644
--- a/res/layout/settings_homepage_app_bar_two_pane_layout.xml
+++ b/res/layout/settings_homepage_app_bar_two_pane_layout.xml
@@ -17,8 +17,11 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:background="?androidprv:attr/colorSurface"
android:orientation="vertical">
<FrameLayout
@@ -29,7 +32,6 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
android:orientation="horizontal">
<include layout="@layout/search_bar_two_pane_version"/>
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index f0aafe1..3de5a8a 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -61,7 +61,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
+ app:layout_scrollFlags="scroll|exitUntilCollapsed">
<include
android:id="@+id/homepage_app_bar_regular_phone_view"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7726b40..43c1acd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1301,6 +1301,13 @@
<!-- Summary of the preferences item to control encryption, when encryption is active -->
<string name="encrypted_summary">Encrypted</string>
+ <!-- Title of the issue card in Safety Center when no screen lock is set [CHAR LIMIT=50] -->
+ <string name="no_screen_lock_issue_title">Set a screen lock</string>
+ <!-- Summary of the issue card in Safety Center when no screen lock is set [CHAR LIMIT=NONE] -->
+ <string name="no_screen_lock_issue_summary">For added security, set a PIN, pattern, or password for this device.</string>
+ <!-- Action label for the issue card in Safety Center when no screen lock is set [CHAR LIMIT=50] -->
+ <string name="no_screen_lock_issue_action_label">Set screen lock</string>
+
<!-- Unlock Picker Settings --><skip />
<!-- Security Picker --><skip />
@@ -8308,7 +8315,7 @@
<string name="keywords_system_update_settings">upgrade, android</string>
<!-- List of synonyms for the Do Not Disturb setting, used to match in settings search. Do Not Disturb turns of notification volume, notifications, vibrations, among other things on the device. [CHAR LIMIT=NONE] -->
- <string name="keywords_zen_mode_settings">dnd, schedule, notifications, block, silence, vibrate, sleep, work, focus, sound, mute, day, weekday, weekend, weeknight, event, do not disturb</string>
+ <string name="keywords_zen_mode_settings">dnd, schedule, notifications, block, silence, vibrate, sleep, work, focus, sound, mute, day, weekday, weekend, weeknight, event</string>
<!-- List of synonyms for the display timeout (how long until the screen turns off) setting, used to match in settings search [CHAR LIMIT=NONE] -->
<string name="keywords_screen_timeout">screen, lock time, timeout, lockscreen</string>
@@ -8390,7 +8397,7 @@
<string name="sound_settings_summary">Ring & notification volume at <xliff:g id="percentage" example="2%">%1$s</xliff:g></string>
<!-- Summary for sound settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
- <string name="sound_dashboard_summary" translatable="false">Volume, vibration, Priority mode</string>
+ <string name="sound_dashboard_summary">Volume, vibration, Do Not Disturb</string>
<!-- Sound: Dashboard summary indicating the volume of ringtone when at 0% with vibrate enabled. [CHAR LIMIT=100] -->
<string name="sound_settings_summary_vibrate">Ringer set to vibrate</string>
@@ -8470,6 +8477,9 @@
<!-- Sound: Other sounds: Title for the option enabling touch sounds. [CHAR LIMIT=30] -->
<string name="touch_sounds_title">Touch sounds</string>
+ <!-- Sound: Other sounds: Title for the option enabling the vibrate icon. [CHAR LIMIT=50] -->
+ <string name="vibrate_icon_title">Always show icon when in vibrate mode</string>
+
<!-- Sound: Other sounds: Title for the option enabling dock audio media. [CHAR LIMIT=50] -->
<string name="dock_audio_media_title">Dock speaker plays</string>
@@ -8497,8 +8507,8 @@
<!-- Setting summary for controlling how caption text display in real time [CHAR LIMIT=NONE]-->
<string name="live_caption_summary">Automatically caption media</string>
- <!-- Sound: Summary for the Priority mode option that describes how many automatic rules (schedules) are enabled [CHAR LIMIT=NONE]-->
- <string name="zen_mode_settings_schedules_summary" translatable="false">
+ <!-- Sound: Summary for the Do not Disturb option that describes how many automatic rules (schedules) are enabled [CHAR LIMIT=NONE]-->
+ <string name="zen_mode_settings_schedules_summary">
{count, plural,
=0 {None}
=1 {1 schedule set}
@@ -8506,8 +8516,8 @@
}
</string>
- <!-- Sound: Title for the Priority mode option and associated settings page. [CHAR LIMIT=50]-->
- <string name="zen_mode_settings_title" translatable="false">Priority mode</string>
+ <!-- Sound: Title for the Do not Disturb option and associated settings page. [CHAR LIMIT=50]-->
+ <string name="zen_mode_settings_title">Do Not Disturb</string>
<!-- Sound: Summary for the Do not Disturb option and associated settings page. [CHAR LIMIT=240]-->
<string name="zen_mode_settings_summary">Only get notified by important people and apps</string>
@@ -8515,11 +8525,11 @@
<!-- Subtitle for the Do not Disturb slice. [CHAR LIMIT=50]-->
<string name="zen_mode_slice_subtitle">Limit interruptions</string>
- <!-- Do not disturb: Title for the Priority mode dialog to turn on Priority mode. [CHAR LIMIT=50]-->
- <string name="zen_mode_settings_turn_on_dialog_title" translatable="false">Turn on Priority mode</string>
+ <!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]-->
+ <string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string>
- <!-- Priority mode: Specifies alarms and media can bypass Priority mode. [CHAR LIMIT=100] -->
- <string name="zen_mode_behavior_alarms_only" translatable="false">Alarms and media sounds</string>
+ <!-- Do not disturb: Specifies alarms and media can bypass DND. [CHAR LIMIT=100] -->
+ <string name="zen_mode_behavior_alarms_only">Alarms and media sounds can interrupt</string>
<!-- Do not disturb: Title for the zen mode automation option in Settings. [CHAR LIMIT=40] -->
<string name="zen_mode_automation_settings_title">Schedules</string>
@@ -8545,11 +8555,11 @@
<!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=46] -->
<string name="zen_mode_automation_suggestion_title">Silence phone at certain times</string>
- <!-- Priority mode: Summary for the zen mode automation option Suggestion. [CHAR LIMIT=55] -->
- <string name="zen_mode_automation_suggestion_summary" translatable="false">Set Priority mode rules</string>
+ <!-- Do not disturb: Summary for the zen mode automation option Suggestion. [CHAR LIMIT=55] -->
+ <string name="zen_mode_automation_suggestion_summary">Set Do Not Disturb rules</string>
- <!-- Priority mode: Header for the Priority mode automatic rules. [CHAR LIMIT=55] -->
- <string name="zen_mode_schedule_title" translatable="false">Turn on Priority mode automatically</string>
+ <!-- Do not disturb: Header for the Do Not Disturb automatic rules. [CHAR LIMIT=55] -->
+ <string name="zen_mode_schedule_title">Schedule</string>
<!-- Do not disturb: Switch toggle to toggle whether to use an automatic dnd rule or not [CHAR LIMIT=40] -->
<string name="zen_mode_use_automatic_rule">Use schedule</string>
@@ -8557,8 +8567,8 @@
<!-- Do not disturb: Zen mode combined summary + condition line [CHAR LIMIT=60] -->
<string name="zen_mode_summary_combination"><xliff:g id="mode" example="Priority only">%1$s</xliff:g>: <xliff:g id="exit condition" example="Until you turn this off">%2$s</xliff:g></string>
- <!-- Priority mode: zen settings screens category title [CHAR LIMIT=100] -->
- <string name="zen_mode_settings_category" translatable="false">Allow sounds when Priority mode is on</string>
+ <!-- Do not disturb: zen settings screens category title [CHAR LIMIT=100] -->
+ <string name="zen_mode_settings_category">Allow interruptions that make sound</string>
<!-- Do not disturb: Title for the Visual interruptions option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_visual_interruptions_settings_title">Block visual disturbances</string>
@@ -8566,10 +8576,10 @@
<!-- Do not disturb: Subtitle for the Visual signals option to toggle on/off visual signals/alerts when the screen is on/when screen is off. [CHAR LIMIT=30] -->
<string name="zen_mode_visual_signals_settings_subtitle">Allow visual signals</string>
- <!-- Priority mode: low-priority notifications settings title [CHAR LIMIT=80] -->
- <string name="zen_mode_restrict_notifications_title" translatable="false">Display options for low-priority notifications</string>
- <!-- Priority mode: low-priority notifications screen category title [CHAR LIMIT=100] -->
- <string name="zen_mode_restrict_notifications_category" translatable="false">When Priority mode is on</string>
+ <!-- Do not disturb: restrict notifications settings title [CHAR LIMIT=80] -->
+ <string name="zen_mode_restrict_notifications_title">Display options for hidden notifications</string>
+ <!-- Do not disturb: Hide notifications screen category title [CHAR LIMIT=100] -->
+ <string name="zen_mode_restrict_notifications_category">When Do Not Disturb is on</string>
<!-- Do not disturb: Mute notifications option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_mute">No sound from notifications</string>
<!-- Do not disturb:Mute notifications summary [CHAR LIMIT=NONE] -->
@@ -8580,20 +8590,20 @@
<string name="zen_mode_restrict_notifications_hide">No visuals or sound from notifications</string>
<!-- Do not disturb: Hide notifications summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_hide_summary">You won\u2019t see or hear notifications</string>
- <!-- Priority mode: Hide notifications footer [CHAR LIMIT=NONE] -->
- <string name="zen_mode_restrict_notifications_hide_footer" translatable="false">Your phone won\u2019t show, vibrate or make sound for new or existing notifications. Keep in mind, critical notifications for phone activity and status will still appear.\n\nWhen you turn off Priority mode, find missed notifications by swiping down from the top of your screen.</string>
+ <!-- Do not disturb: Hide notifications footer [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_restrict_notifications_hide_footer">Your phone won\u2019t show, vibrate or make sound for new or existing notifications. Keep in mind, critical notifications for phone activity and status will still appear.\n\nWhen you turn off Do Not Disturb, find missed notifications by swiping down from the top of your screen.</string>
<!-- Do not disturb: Custom settings option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_custom">Custom</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_enable_custom">Enable custom setting</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_disable_custom">Remove custom setting</string>
- <!-- Priority mode: restrict notifications page, menu option [CHAR LIMIT=60] -->
- <string name="zen_mode_restrict_notifications_summary_muted" translatable="false">No sound from notifications</string>
- <!-- Priority mode: restrict notifications page, menu option [CHAR LIMIT=60] -->
- <string name="zen_mode_restrict_notifications_summary_custom" translatable="false">Partially hidden</string>
- <!-- Priority mode: restrict notifications page, menu option [CHAR LIMIT=100] -->
- <string name="zen_mode_restrict_notifications_summary_hidden" translatable="false">No visuals or sound from notifications</string>
+ <!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
+ <string name="zen_mode_restrict_notifications_summary_muted">No sound from notifications</string>
+ <!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
+ <string name="zen_mode_restrict_notifications_summary_custom">Partially hidden</string>
+ <!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=100] -->
+ <string name="zen_mode_restrict_notifications_summary_hidden">No visuals or sound from notifications</string>
<!-- Do not disturb: what to block title [CHAR LIMIT = 60] -->
<string name="zen_mode_what_to_block_title">Custom restrictions</string>
@@ -8644,26 +8654,26 @@
<!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
<string name="zen_mode_enable_dialog_turn_on">Turn on</string>
- <!-- Priority mode: Label for button that will turn on zen mode. [CHAR LIMIT=30] -->
- <string name="zen_mode_button_turn_on" translatable="false">Turn on</string>
+ <!-- Do not disturb: Label for button that will turn on zen mode. [CHAR LIMIT=30] -->
+ <string name="zen_mode_button_turn_on">Turn on now</string>
- <!-- Priority mode: Label for button that will turn off zen mode. [CHAR LIMIT=30] -->
- <string name="zen_mode_button_turn_off" translatable="false">Turn off</string>
+ <!-- Do not disturb: Label for button that will turn off zen mode. [CHAR LIMIT=30] -->
+ <string name="zen_mode_button_turn_off">Turn off now</string>
- <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing end time of Priority mode -->
- <string name="zen_mode_settings_dnd_manual_end_time" translatable="false">Priority mode is on until <xliff:g id="formatted_time" example="7:00 AM">%s</xliff:g></string>
+ <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing end time of DND -->
+ <string name="zen_mode_settings_dnd_manual_end_time">Do Not Disturb is on until <xliff:g id="formatted_time" example="7:00 AM">%s</xliff:g></string>
- <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing length of Priority mode -->
- <string name="zen_mode_settings_dnd_manual_indefinite" translatable="false">Priority mode will stay on until you turn it off</string>
+ <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing length of DND -->
+ <string name="zen_mode_settings_dnd_manual_indefinite">Do Not Disturb will stay on until you turn it off</string>
- <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing how Priority mode was triggered by an automatic DND schedule -->
- <string name="zen_mode_settings_dnd_automatic_rule" translatable="false">Priority mode was automatically turned on by a schedule (<xliff:g id="rule_name" example="Weeknights">%s</xliff:g>)</string>
+ <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer showing how DND was triggered by an automatic DND schedule -->
+ <string name="zen_mode_settings_dnd_automatic_rule">Do Not Disturb was automatically turned on by a schedule (<xliff:g id="rule_name" example="Weeknights">%s</xliff:g>)</string>
- <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer how Priority mode was triggered by an app -->
- <string name="zen_mode_settings_dnd_automatic_rule_app" translatable="false">Priority mode was automatically turned on by an app (<xliff:g id="app_name" example="Android Services">%s</xliff:g>)</string>
+ <!-- [CHAR LIMIT=110] Zen mode settings footer: Footer how DND was triggered by an app -->
+ <string name="zen_mode_settings_dnd_automatic_rule_app">Do Not Disturb was automatically turned on by an app (<xliff:g id="app_name" example="Android Services">%s</xliff:g>)</string>
- <!-- [CHAR LIMIT=120] Zen mode settings footer: Footer informing user Priority mode has custom settings. -->
- <string name="zen_mode_settings_dnd_custom_settings_footer" translatable="false">Priority mode is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
+ <!-- [CHAR LIMIT=120] Zen mode settings footer: Footer informing user DND has custom settings. -->
+ <string name="zen_mode_settings_dnd_custom_settings_footer">Do Not Disturb is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
<!-- [CHAR LIMIT=120] Zen mode settings footer: Link following zen_mode_settings_dnd_custom_settings_footer to see the currently applied custom dnd settings. -->
<string name="zen_mode_settings_dnd_custom_settings_footer_link"> <annotation id="link">View custom settings</annotation></string>
@@ -8674,11 +8684,11 @@
<!-- [CHAR LIMIT=20] Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. -->
<string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
- <!-- Sound settings screen, summary format of priority mode when on with extra info. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_sound_summary_on_with_info" translatable="false">On / <xliff:g name="dnd_summary" example="No sound except alarms and media">%1$s</xliff:g></string>
+ <!-- Sound settings screen, summary format of do not disturb when on with extra info. [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_sound_summary_on_with_info">On / <xliff:g name="dnd_summary" example="No sound except alarms and media">%1$s</xliff:g></string>
- <!-- Sound settings screen, summary format of priority mode when on with no extra information. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_sound_summary_on" translatable="false">On</string>
+ <!-- Sound settings screen, summary format of do not disturb when on with no extra information. [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_sound_summary_on">On</string>
<!-- Do not disturb: Summary for zen mode duration setting indicating user will be prompted to set dnd duration whenever dnd is manually toggled on [CHAR LIMIT=NONE]-->
<string name="zen_mode_duration_summary_always_prompt">Ask every time</string>
@@ -8711,25 +8721,25 @@
}
</string>
- <!-- Priority mode settings, main screen, category header [CHAR LIMIT=120]-->
- <string name="zen_category_behavior" translatable="false">Notifications that can reach you</string>
- <!-- Priority mode settings, main screen, field, priority mode breakthrough [CHAR LIMIT=100]-->
- <string name="zen_category_people" translatable="false">People</string>
- <!-- Priority mode settings, main screen, field, priority mode breakthrough [CHAR LIMIT=100]-->
- <string name="zen_category_apps" translatable="false">Apps</string>
- <!-- Priority mode settings, main screen, field, priority mode breakthrough [CHAR LIMIT=100]-->
- <string name="zen_category_exceptions" translatable="false">Alarms & other notifications</string>
- <!-- Priority de settings, main screen, field, schedules [CHAR LIMIT=100]-->
- <string name="zen_category_schedule" translatable="false">Schedules</string>
- <!-- Priority mode settings, main screen, field, duration setting where user can specify how
- long priority mode will last when toggling on from qs) [CHAR LIMIT=100] -->
- <string name="zen_category_duration" translatable="false">Duration for Quick Settings</string>
- <!-- Priority mode settings, main screen, category header describing settings that do not
+ <!-- Do not disturb settings, main screen, category header [CHAR LIMIT=120]-->
+ <string name="zen_category_behavior">What can interrupt Do Not Disturb</string>
+ <!-- Do not disturb settings, main screen, field, dnd breakthrough [CHAR LIMIT=100]-->
+ <string name="zen_category_people">People</string>
+ <!-- Do not disturb settings, main screen, field, dnd breakthrough [CHAR LIMIT=100]-->
+ <string name="zen_category_apps">Apps</string>
+ <!-- Do not disturb settings, main screen, field, dnd breakthrough [CHAR LIMIT=100]-->
+ <string name="zen_category_exceptions">Alarms & other interruptions</string>
+ <!-- Do not disturb settings, main screen, field, schedules [CHAR LIMIT=100]-->
+ <string name="zen_category_schedule">Schedules</string>
+ <!-- Do not disturb settings, main screen, field, duration setting where user can specify how
+ long dnd will last when toggling dnd on from qs) [CHAR LIMIT=100] -->
+ <string name="zen_category_duration">Duration for Quick Settings</string>
+ <!-- Do not disturb settings, main screen, category header describing settings that do not
fit in another group [CHAR LIMIT=100] -->
- <string name="zen_settings_general" translatable="false">Advanced</string>
+ <string name="zen_settings_general">General</string>
- <!-- Priority mode settings, sound and vibrations screen footer [CHAR LIMIT=NONE]-->
- <string name="zen_sound_footer" translatable="false">When Priority mode is on, sound and vibration will be muted, except for the items you allow above.</string>
+ <!-- Do not disturb settings, sound and vibrations screen footer [CHAR LIMIT=NONE]-->
+ <string name="zen_sound_footer">When Do Not Disturb is on, sound and vibration will be muted, except for the items you allow above.</string>
<!-- Do not disturb custom settings dialog title [CHAR LIMIT=40]-->
<string name="zen_custom_settings_dialog_title">Custom settings</string>
@@ -8744,8 +8754,8 @@
<!-- Do not disturb settings, messages, events and reminders title [CHAR LIMIT=100]-->
<string name="zen_msg_event_reminder_title">Messages, events & reminders</string>
- <!-- Priority mode settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
- <string name="zen_msg_event_reminder_footer" translatable="false">When Priority mode is on, messages, reminders, and events will be muted, except for the items you allow above. You can adjust messages settings to allow your friends, family, or other contacts to reach you.</string>
+ <!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
+ <string name="zen_msg_event_reminder_footer">When Do Not Disturb is on, messages, reminders, and events will be muted, except for the items you allow above. You can adjust messages settings to allow your friends, family, or other contacts to reach you.</string>
<!-- Do not disturb onboarding dialog, accept new settings [CHAR LIMIT=30]-->
<string name="zen_onboarding_ok">Done</string>
@@ -8761,8 +8771,8 @@
<!-- Do not disturb onboarding dialog, secondary text for radio button [CHAR LIMIT=NONE]-->
<string name="zen_onboarding_current_setting_summary">(Current setting)</string>
- <!-- Priority mode onboarding dialog, header prompt for settings [CHAR LIMIT=80]-->
- <string name="zen_onboarding_dnd_visual_disturbances_header" translatable="false">Change Priority mode notification settings?</string>
+ <!-- Do not disturb onboarding dialog, header prompt for settings [CHAR LIMIT=80]-->
+ <string name="zen_onboarding_dnd_visual_disturbances_header">Change Do Not Disturb notification settings?</string>
<!-- DO NOT TRANSLATE obsolete [CHAR LIMIT=NONE]-->
<string name="zen_onboarding_dnd_visual_disturbances_description" translatable="false">Your phone can do more to help you focus.\n\nUpdate settings to:\n\n- Hide notifications completely\n\n- Allow calls from starred contacts and repeat callers</string>
@@ -9188,7 +9198,7 @@
<string name="important_bubble">Bubble priority conversations</string>
<!-- [CHAR LIMIT=NONE] description of how notifications from important conversations behave -->
- <string name="important_conversation_behavior_summary">Priority conversations show at the top of the pull-down shade. You can also set them to bubble when Priority mode is on.</string>
+ <string name="important_conversation_behavior_summary">Priority conversations show at the top of the pull-down shade. You can also set them to bubble and interrupt Do Not Disturb.</string>
<!-- title for conversation onboarding -->
<string name="conversation_onboarding_title">Priority and modified conversations will appear here</string>
@@ -9332,12 +9342,12 @@
<xliff:g id="service" example="NotificationAssistant">%1$s</xliff:g>?</string>
<!-- Summary for a warning message about security implications of enabling a notification
assistant, displayed as a dialog message. [CHAR LIMIT=NONE] -->
- <string name="notification_assistant_security_warning_summary" translatable="false">
+ <string name="notification_assistant_security_warning_summary">
Enhanced notifications replaced Android Adaptive Notifications in Android 12.
This feature shows suggested actions and replies, and organizes your notifications.
\n\nEnhanced notifications can access notification content, including personal information
like contact names and messages. This feature can also dismiss or respond to notifications,
- such as answering phone calls, and control Priority mode.
+ such as answering phone calls, and control Do Not Disturb.
</string>
<!-- Title for a warning message about security implications of enabling a notification
@@ -9346,11 +9356,11 @@
<xliff:g id="service" example="NotificationReader">%1$s</xliff:g>?</string>
<!-- Summary for a warning message about security implications of enabling a notification
listener, displayed as a dialog message. [CHAR LIMIT=NONE] -->
- <string name="notification_listener_security_warning_summary" translatable="false">
+ <string name="notification_listener_security_warning_summary">
<xliff:g id="notification_listener_name">%1$s</xliff:g> will be able to read all notifications,
including personal information such as contact names, photos, and the text of messages you receive.
This app will also be able to snooze or dismiss notifications or take action on buttons in notifications, including answering phone calls.
- \n\nThis will also give the app the ability to turn Priority mode on or off and change related settings.
+ \n\nThis will also give the app the ability to turn Do Not Disturb on or off and change related settings.
</string>
<string name="nls_warning_prompt"><xliff:g id="notification_listener_name">%1$s</xliff:g> will be able to:</string>
<string name="nls_feature_read_title">Read your notifications</string>
@@ -9358,9 +9368,9 @@
<string name="nls_feature_reply_title">Reply to messages</string>
<string name="nls_feature_reply_summary">It can reply to messages and take action on buttons in notifications, including snoozing or dismissing notifications and answering calls.</string>
<string name="nls_feature_settings_title">Change settings</string>
- <string name="nls_feature_settings_summary" translatable="false">It can turn Priority mode on or off and change related settings.</string>
- <string name="notification_listener_disable_warning_summary" translatable="false">
- If you turn off notification access for <xliff:g id="notification_listener_name">%1$s</xliff:g>, Priority mode access may also be turned off.
+ <string name="nls_feature_settings_summary">It can turn Do Not Disturb on or off and change related settings.</string>
+ <string name="notification_listener_disable_warning_summary">
+ If you turn off notification access for <xliff:g id="notification_listener_name">%1$s</xliff:g>, Do Not Disturb access may also be turned off.
</string>
<string name="notification_listener_disable_warning_confirm">Turn off</string>
<string name="notification_listener_disable_warning_cancel">Cancel</string>
@@ -9523,14 +9533,14 @@
The placeholder would be the app name (e.g. Calendar). [CHAR LIMIT=NONE]-->
<string name="interact_across_profiles_install_app_summary">Tap to get the app</string>
- <!-- Sound & notification > Advanced section: Title for managing Priority mode access option. [CHAR LIMIT=40] -->
- <string name="manage_zen_access_title" translatable="false">Priority mode access</string>
+ <!-- Sound & notification > Advanced section: Title for managing Do Not Disturb access option. [CHAR LIMIT=40] -->
+ <string name="manage_zen_access_title">Do Not Disturb access</string>
- <!-- Button title that grants 'Priority mode' permission to an app [CHAR_LIMIT=60]-->
- <string name="zen_access_detail_switch" translatable="false">Allow Priority mode</string>
+ <!-- Button title that grants 'Do Not Disturb' permission to an app [CHAR_LIMIT=60]-->
+ <string name="zen_access_detail_switch">Allow Do Not Disturb</string>
- <!-- Sound & notification > Priority mode access > Text to display when the list is empty. [CHAR LIMIT=NONE] -->
- <string name="zen_access_empty_text" translatable="false">No installed apps have requested Priority mode access</string>
+ <!-- Sound & notification > Do Not Disturb access > Text to display when the list is empty. [CHAR LIMIT=NONE] -->
+ <string name="zen_access_empty_text">No installed apps have requested Do Not Disturb access</string>
<!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings -->
<string name="loading_notification_apps">Loading apps\u2026</string>
@@ -9603,11 +9613,11 @@
<!-- [CHAR LIMIT=NONE BACKUP_MESSAGE_ID:7166470350070693657] Channel notification settings: Badging option title -->
<string name="notification_channel_badge_title">Show notification dot</string>
- <!-- [CHAR LIMIT=NONE] App notification settings: Override Priority mode option title -->
- <string name="app_notification_override_dnd_title" translatable="false">Override Priority mode</string>
+ <!-- [CHAR LIMIT=NONE] App notification settings: Override DND option title -->
+ <string name="app_notification_override_dnd_title">Override Do Not Disturb</string>
- <!-- [CHAR LIMIT=NONE] App notification settings: Override Priority mode option description-->
- <string name="app_notification_override_dnd_summary" translatable="false">Let these notifications continue to notify you when Priority mode is on</string>
+ <!-- [CHAR LIMIT=NONE] App notification settings: Override DND option description-->
+ <string name="app_notification_override_dnd_summary">Let these notifications continue to interrupt when Do Not Disturb is on</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Visibility override option title -->
<string name="app_notification_visibility_override_title">Lock screen</string>
@@ -9658,7 +9668,7 @@
<string name="zen_mode_rule_name_warning">Schedule name already in use</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Add another automatic zen rule option name-->
- <string name="zen_mode_add_rule" translatable="false">Add a schedule</string>
+ <string name="zen_mode_add_rule">Add more</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Add event-based rule, set rule name title -->
<string name="zen_mode_add_event_rule">Add event schedule</string>
@@ -9681,26 +9691,26 @@
<!-- [CHAR LIMIT=40] Zen mode settings: External rule type name if unknown -->
<string name="zen_mode_rule_type_unknown">Unknown</string>
- <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current priority mode behavior settings -->
- <string name="zen_mode_app_set_behavior" translatable="false">These settings can\'t be changed right now. An app (<xliff:g id="app_name" example="Android Services">%1$s</xliff:g>) has automatically turned on Priority mode with custom behavior."</string>
+ <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current do not disturb behavior settings -->
+ <string name="zen_mode_app_set_behavior">These settings can\'t be changed right now. An app (<xliff:g id="app_name" example="Android Services">%1$s</xliff:g>) has automatically turned on Do Not Disturb with custom behavior."</string>
- <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current priority mode behavior settings -->
- <string name="zen_mode_unknown_app_set_behavior" translatable="false">These settings can\'t be changed right now. An app has automatically turned on Priority mode with custom behavior."</string>
+ <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current do not disturb behavior settings -->
+ <string name="zen_mode_unknown_app_set_behavior">These settings can\'t be changed right now. An app has automatically turned on Do Not Disturb with custom behavior."</string>
- <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current priority mode behavior settings -->
- <string name="zen_mode_qs_set_behavior" translatable="false">These settings can\'t be changed right now. Priority mode was manually turned on with custom behavior."</string>
+ <!-- [CHAR LIMIT=NONE] Zen mode behavior settings footer: footer describing why the user cannot change the current do not disturb behavior settings -->
+ <string name="zen_mode_qs_set_behavior">These settings can\'t be changed right now. Do Not Disturb was manually turned on with custom behavior."</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Schedule rule type name -->
<string name="zen_schedule_rule_type_name">Time</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Schedule rule toast hint when enabled -->
- <string name="zen_schedule_rule_enabled_toast" translatable="false">Automatic rule set to turn on Priority mode during specified times</string>
+ <string name="zen_schedule_rule_enabled_toast">Automatic rule set to turn on Do Not Disturb during specified times</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Event rule type name -->
<string name="zen_event_rule_type_name">Event</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Event rule toast hint when enabled -->
- <string name="zen_event_rule_enabled_toast" translatable="false">Automatic rule set to turn on Priority mode during specified events</string>
+ <string name="zen_event_rule_enabled_toast">Automatic rule set to turn on Do Not Disturb during specified events</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule calendar option title -->
<string name="zen_mode_event_rule_calendar">During events for</string>
@@ -9748,13 +9758,13 @@
<string name="zen_mode_schedule_rule_days_all">Every day</string>
<!-- [CHAR LIMIT=60] Zen mode settings: Downtime rule setting -->
- <string name="zen_mode_schedule_alarm_title" translatable="false">Use alarm as the end time</string>
+ <string name="zen_mode_schedule_alarm_title">Alarm can override end time</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Downtime rule setting -->
- <string name="zen_mode_schedule_alarm_summary" translatable="false">Schedule turns off when next alarm rings</string>
+ <string name="zen_mode_schedule_alarm_summary">Schedule turns off when an alarm rings</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Title for preference to allow custom behavior for the dnd schedule -->
- <string name="zen_mode_custom_behavior_title" translatable="false">Customized Priority mode behavior</string>
+ <string name="zen_mode_custom_behavior_title">Do Not Disturb behavior</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Summay text indicating the currenty dnd schedule is using the default dnd settings -->
<string name="zen_mode_custom_behavior_summary_default">Use default settings</string>
@@ -9793,7 +9803,7 @@
</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Header for calls and messages section of conversations
setting page -->
- <string name="zen_mode_people_calls_messages_section_title" translatable="false">Who can reach you</string>
+ <string name="zen_mode_people_calls_messages_section_title">Who can interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: people screen footer -->
<string name="zen_mode_people_footer" translatable="false">Even if messaging or calling apps can\u0027t notify you, people you choose here can still reach you through those apps</string>
@@ -9805,7 +9815,7 @@
<!-- [CHAR LIMIT=20] Zen mode settings: Calls option -->
<string name="zen_mode_calls_list">calls</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Calls settings header -->
- <string name="zen_mode_calls_header" translatable="false">Who can call you</string>
+ <string name="zen_mode_calls_header">Calls that can interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Calls screen footer -->
<string name="zen_mode_calls_footer">To make sure allowed calls make sound, check that device is set to ring</string>
<!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Calls screen footer -->
@@ -9834,7 +9844,7 @@
<!-- [CHAR LIMIT=40] Zen mode settings: Allow messages to bypass DND title -->
<string name="zen_mode_messages_title">Messages</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Messages settings header -->
- <string name="zen_mode_messages_header" translatable="false">Who can message you</string>
+ <string name="zen_mode_messages_header">Messages that can interrupt</string>
<!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
<string name="zen_mode_messages_footer">To make sure allowed messages make sound, check that device is set to ring</string>
<!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Messages screen footer -->
@@ -9861,12 +9871,12 @@
<!-- [CHAR LIMIT=40] Zen mode settings: Messages option values: From some people (but not all or none), may be contacts or conversations -->
<string name="zen_mode_from_some">Some people or conversations</string>
- <!-- Priority mode settings, calls summary [CHAR LIMIT=100]-->
- <string name="zen_calls_summary_starred_repeat" translatable="false">From starred contacts and repeat callers</string>
- <!-- Priority mode settings, calls summary [CHAR LIMIT=100]-->
- <string name="zen_calls_summary_contacts_repeat" translatable="false">From contacts and repeat callers</string>
- <!-- Priority mode settings, calls summary [CHAR LIMIT=100]-->
- <string name="zen_calls_summary_repeat_only" translatable="false">From repeat callers only</string>
+ <!-- Do not disturb settings, calls summary [CHAR LIMIT=100]-->
+ <string name="zen_calls_summary_starred_repeat">From starred contacts and repeat callers</string>
+ <!-- Do not disturb settings, calls summary [CHAR LIMIT=100]-->
+ <string name="zen_calls_summary_contacts_repeat">From contacts and repeat callers</string>
+ <!-- Do not disturb settings, calls summary [CHAR LIMIT=100]-->
+ <string name="zen_calls_summary_repeat_only">From repeat callers only</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls option value: No calls allowed -->
<string name="zen_mode_none_calls">None</string>
@@ -9920,14 +9930,14 @@
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND -->
<string name="zen_mode_bypassing_apps">Allow apps to override</string>
- <!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to notify during Priority mode header -->
- <string name="zen_mode_bypassing_apps_header" translatable="false">Apps that can notify you</string>
- <!-- [CHAR LIMIT=100] Zen mode settings: Add apps to notify during Priority mode header -->
- <string name="zen_mode_bypassing_apps_add_header" translatable="false">Choose more apps</string>
- <!-- [CHAR LIMIT=120] Zen mode settings: No apps can notify in Priority mode -->
- <string name="zen_mode_bypassing_apps_none" translatable="false">None</string>
- <!-- [CHAR LIMIT=120] Zen mode settings: No apps can notify in Priority mode -->
- <string name="zen_mode_bypassing_apps_subtext_none" translate="false">No apps can notify you</string>
+ <!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND header -->
+ <string name="zen_mode_bypassing_apps_header">Apps that can interrupt</string>
+ <!-- [CHAR LIMIT=100] Zen mode settings: Add apps to bypass DND header -->
+ <string name="zen_mode_bypassing_apps_add_header">Select more apps</string>
+ <!-- [CHAR LIMIT=120] Zen mode settings: No apps are bypassing DND -->
+ <string name="zen_mode_bypassing_apps_none">No apps selected</string>
+ <!-- [CHAR LIMIT=120] Zen mode settings: No apps are bypassing DND -->
+ <string name="zen_mode_bypassing_apps_subtext_none">No apps can interrupt</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Preference to add apps that are allowed to bypass DND -->
<string name="zen_mode_bypassing_apps_add">Add apps</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Summary indicating all notification channels can
@@ -9936,16 +9946,16 @@
<!-- [CHAR LIMIT=120] Zen mode settings: Summary indicating all notification channels can
bypass DND for this app -->
<string name="zen_mode_bypassing_apps_summary_some">Some notifications</string>
- <!-- [CHAR LIMIT=NONE] Zen mode settings: Footer for Priority mode bypassing apps settings -->
- <string name="zen_mode_bypassing_apps_footer" translatable="false">If calling or messaging apps can\u0027t notify you, people you choose in Priority mode settings can still reach you through those apps</string>
- <!-- [CHAR LIMIT=NONE] Zen mode settings: Lists apps that can bypass Priority mode. For example, "Nest, Messages, and 2 more". -->
- <string name="zen_mode_bypassing_apps_subtext" translatable="false">
+ <!-- [CHAR LIMIT=NONE] Zen mode settings: Footer for DND bypassing apps settings -->
+ <string name="zen_mode_bypassing_apps_footer">Selected people can still reach you, even if you don\u2019t allow apps to interrupt</string>
+ <!-- [CHAR LIMIT=NONE] Zen mode settings: Lists apps that can bypass DND. For example, "Nest, Messages, and 2 more can interrupt". -->
+ <string name="zen_mode_bypassing_apps_subtext">
{count, plural, offset:2
- =0 {None}
- =1 {{app_1}}
- =2 {{app_1} and {app_2}}
- =3 {{app_1}, {app_2}, and {app_3}}
- other {{app_1}, {app_2}, and # more}
+ =0 {No apps can interrupt}
+ =1 {{app_1} can interrupt}
+ =2 {{app_1} and {app_2} can interrupt}
+ =3 {{app_1}, {app_2}, and {app_3} can interrupt}
+ other {{app_1}, {app_2}, and # more can interrupt}
}
</string>
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND title-->
@@ -9954,30 +9964,30 @@
<string name="zen_mode_bypassing_apps_all_summary">All notifications</string>
<!-- [CHAR LIMIT=100] Zen mode settings: App that can bypass DND's secondary text describing which notification channels from the app can bypass DND-->
<string name="zen_mode_bypassing_apps_some_summary">Some notifications</string>
- <!-- [CHAR LIMIT=100] Zen mode settings: Allow notifications from an app to notify during Priority mode header -->
- <string name="zen_mode_bypassing_app_channels_header" translatable="false">Notifications that can reach you</string>
+ <!-- [CHAR LIMIT=100] Zen mode settings: Allow notifications from an app to bypass DND header -->
+ <string name="zen_mode_bypassing_app_channels_header">Notifications that can interrupt</string>
<!-- [CHAR LIMIT=100] Zen mode settings: Allow all notifications from an app to bypass DND
toggle title -->
<string name="zen_mode_bypassing_app_channels_toggle_all">Allow all notifications</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Summary for sound interruption settings -->
- <string name="zen_mode_other_sounds_summary" translatable="false">
+ <string name="zen_mode_other_sounds_summary">
{count, plural, offset:2
- =0 {None}
- =1 {{sound_category_1}}
- =2 {{sound_category_1} and {sound_category_2}}
- =3 {{sound_category_1}, {sound_category_2}, and {sound_category_3}}
- other {{sound_category_1}, {sound_category_2}, and # more}
+ =0 {Nothing can interrupt}
+ =1 {{sound_category_1} can interrupt}
+ =2 {{sound_category_1} and {sound_category_2} can interrupt}
+ =3 {{sound_category_1}, {sound_category_2}, and {sound_category_3} can interrupt}
+ other {{sound_category_1}, {sound_category_2}, and # more can interrupt}
}
</string>
- <!-- [CHAR LIMIT=120] Zen mode settings: No sounds are allowed to bypass Priority mode -->
- <string name="zen_mode_sounds_none">None</string>
+ <!-- [CHAR LIMIT=120] Zen mode settings: No sounds are allowed to bypass DND -->
+ <string name="zen_mode_sounds_none">Nothing can interrupt</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Summary for people category -->
- <string name="zen_mode_people_none" translatable="false">None</string>
+ <string name="zen_mode_people_none">No one can interrupt</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Summary for people category -->
- <string name="zen_mode_people_some" translatable="false">Some people can reach you</string>
+ <string name="zen_mode_people_some">Some people can interrupt</string>
<!-- [CHAR LIMIT=120] Zen mode settings: Summary for people category -->
- <string name="zen_mode_people_all" translatable="false">Anyone can reach you</string>
+ <string name="zen_mode_people_all">All people can interrupt</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Repeat callers option -->
<string name="zen_mode_repeat_callers">Repeat callers</string>
@@ -10036,13 +10046,13 @@
<!-- [CHAR LIMIT=40] Zen mode settings: visual signals: screen is on: title -->
<string name="zen_mode_screen_on">When the screen is on</string>
<!-- [CHAR LIMIT=130] Zen mode settings: visual signals: screen is on: summary -->
- <string name="zen_mode_screen_on_summary" translatable="false">Let notifications silenced by Priority mode pop on screen and show a status bar icon</string>
+ <string name="zen_mode_screen_on_summary">Let notifications silenced by Do Not Disturb pop on screen and show a status bar icon</string>
<!-- [CHAR LIMIT=40] Zen mode settings: visual signals: screen is off: title -->
<string name="zen_mode_screen_off">When the screen is off</string>
<!-- [CHAR LIMIT=130] Zen mode settings: visual interruptions: screen is off: summary -->
- <string name="zen_mode_screen_off_summary" translatable="false">Let notifications silenced by Priority mode turn on the screen and blink the light</string>
+ <string name="zen_mode_screen_off_summary">Let notifications silenced by Do Not Disturb turn on the screen and blink the light</string>
<!-- [CHAR LIMIT=130] Zen mode settings: visual interruptions: screen is off: summary -->
- <string name="zen_mode_screen_off_summary_no_led" translatable="false">Let notifications silenced by Priority mode turn on the screen</string>
+ <string name="zen_mode_screen_off_summary_no_led">Let notifications silenced by Do Not Disturb turn on the screen</string>
<!-- [CHAR LIMIT=NONE] Content description for per-app notification
settings button -->
@@ -10295,8 +10305,8 @@
<string name="notifications_redacted">Sensitive content not on lock screen</string>
<!-- App notification summary with notifications hidden [CHAR LIMIT=40] -->
<string name="notifications_hidden">Not on lock screen</string>
- <!-- App notification summary with notifications bypassing Priority mode [CHAR LIMIT=40] -->
- <string name="notifications_priority" translatable="false">Priority mode overridden</string>
+ <!-- App notification summary with notifications bypassing DND [CHAR LIMIT=40] -->
+ <string name="notifications_priority">Do Not Disturb overridden</string>
<!-- App notification summary divider [CHAR LIMIT=40] -->
<string name="notifications_summary_divider">\u00A0/\u00A0</string>
<!-- App notification summary for advanced controls -->
@@ -10373,7 +10383,7 @@
<!-- Label for showing categories with blocked notifications in list [CHAR LIMIT=30] -->
<string name="filter_notif_blocked_channels">Categories: Turned off</string>
<!-- Label for showing categories with notifications that override dnd in list [CHAR LIMIT=30] -->
- <string name="filter_notif_dnd_channels" translatable="false">Categories: Overrides Priority mode</string>
+ <string name="filter_notif_dnd_channels">Categories: Overrides Do Not Disturb</string>
<!-- Title for advanced application management settings [CHAR LIMIT=30] -->
<string name="advanced_apps">Advanced</string>
@@ -10817,18 +10827,18 @@
<string name="no_data_usage">No data used</string>
<!-- Zen mode access settings - title for warning dialog when enabling access [CHAR LIMIT=NONE] -->
- <string name="zen_access_warning_dialog_title" translatable="false">Allow access to Priority mode for <xliff:g id="app" example="Tasker">%1$s</xliff:g>?</string>
+ <string name="zen_access_warning_dialog_title">Allow access to Do Not Disturb for <xliff:g id="app" example="Tasker">%1$s</xliff:g>?</string>
<!-- Zen mode access settings - summary for warning dialog when enabling access [CHAR LIMIT=NONE] -->
- <string name="zen_access_warning_dialog_summary" translatable="false">The app will be able to turn on/off Priority mode and make changes to related settings.</string>
+ <string name="zen_access_warning_dialog_summary">The app will be able to turn on/off Do Not Disturb and make changes to related settings.</string>
<string name="zen_access_disabled_package_warning">Must stay turned on because notification access is on</string>
<!-- Zen mode access settings - title for warning dialog when revoking access [CHAR LIMIT=NONE] -->
- <string name="zen_access_revoke_warning_dialog_title" translatable="false">Revoke access to Priority mode for <xliff:g id="app" example="Tasker">%1$s</xliff:g>?</string>
+ <string name="zen_access_revoke_warning_dialog_title">Revoke access to Do Not Disturb for <xliff:g id="app" example="Tasker">%1$s</xliff:g>?</string>
<!-- Zen mode access settings - summary for warning dialog when revoking access [CHAR LIMIT=NONE] -->
- <string name="zen_access_revoke_warning_dialog_summary" translatable="false">All Priority mode rules created by this app will be removed.</string>
+ <string name="zen_access_revoke_warning_dialog_summary">All Do Not Disturb rules created by this app will be removed.</string>
<!-- Ignore battery optimizations on label [CHAR LIMIT=30] -->
<string name="ignore_optimizations_on">Don\u2019t optimize</string>
@@ -11101,8 +11111,8 @@
<!-- Summary of condition that airplane mode is on [CHAR LIMIT=NONE] -->
<string name="condition_airplane_summary">Networks unavailable</string>
- <!-- Title of condition that Priority mode is on [CHAR LIMIT=36] -->
- <string name="condition_zen_title" translatable="false">Priority mode is on</string>
+ <!-- Title of condition that do not disturb is on [CHAR LIMIT=36] -->
+ <string name="condition_zen_title">Do Not Disturb is on</string>
<!-- Summary of condition that do not disturb is on and all exceptions set to off [CHAR LIMIT=38] -->
<string name="condition_zen_summary_phone_muted">Phone muted</string>
@@ -12336,8 +12346,8 @@
<!-- Help URI, action disabled by restricted settings [DO NOT TRANSLATE] -->
<string name="help_url_action_disabled_by_restricted_settings" translatable="false"></string>
- <!-- Title label for Priority mode suggestion, which is displayed in Settings homepage [CHAR LIMIT=100] -->
- <string name="zen_suggestion_title" translatable="false">Update Priority mode</string>
+ <!-- Title label for dnd suggestion, which is displayed in Settings homepage [CHAR LIMIT=100] -->
+ <string name="zen_suggestion_title">Update Do Not Disturb</string>
<!-- Summary label for dnd suggestion, which is displayed in Settings homepage [CHAR LIMIT=100] -->
<string name="zen_suggestion_summary">Pause notifications to stay focused</string>
@@ -13343,6 +13353,10 @@
<string name="lockscreen_privacy_controls_setting_toggle">Show device controls</string>
<!-- Device controls summary [CHAR LIMIT=NONE] -->
<string name="lockscreen_privacy_controls_summary">Access controls when locked</string>
+ <!-- Trivial Device controls toggle name [CHAR LIMIT=60] -->
+ <string name="lockscreen_trivial_controls_setting_toggle">Control from locked device</string>
+ <!-- Trivial Device controls summary [CHAR LIMIT=NONE] -->
+ <string name="lockscreen_trivial_controls_summary">Control external devices without unlocking your phone or tablet if allowed by the device controls app</string>
<!-- Lockscreen double-line clock summary [CHAR LIMIT=NONE] -->
<string name="lockscreen_double_line_clock_summary">Show double-line clock when available</string>
<!-- Lockscreen double-line clock toggle [CHAR LIMIT=60] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ebaea6b..3827767 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -734,6 +734,7 @@
parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" >
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:padding">6dp</item>
+ <item name="android:textSize">14sp</item>
</style>
<style name="Widget.PopupWindow.Settings"
diff --git a/res/xml/other_sound_settings.xml b/res/xml/other_sound_settings.xml
index d8396a4..056551f 100644
--- a/res/xml/other_sound_settings.xml
+++ b/res/xml/other_sound_settings.xml
@@ -44,6 +44,11 @@
android:key="touch_sounds"
android:title="@string/touch_sounds_title" />
+ <!-- Vibrate icon in status bar -->
+ <SwitchPreference
+ android:key="vibrate_icon"
+ android:title="@string/vibrate_icon_title" />
+
<!-- Dock speaker plays -->
<DropDownPreference
android:key="dock_audio_media"
diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml
index 7ecf200..b61f458 100644
--- a/res/xml/security_lockscreen_settings.xml
+++ b/res/xml/security_lockscreen_settings.xml
@@ -29,7 +29,7 @@
settings:keywords="@string/keywords_lock_screen_notif"/>
<SwitchPreference
- android:key="security_dispaly_lockscreen_bypass"
+ android:key="security_display_lockscreen_bypass"
android:title="@string/lockscreen_bypass_title"
android:summary="@string/lockscreen_bypass_summary"
settings:searchable="false"
@@ -64,6 +64,12 @@
settings:controller="com.android.settings.display.ControlsPrivacyPreferenceController" />
<SwitchPreference
+ android:key="lockscreen_trivial_controls_switch"
+ android:title="@string/lockscreen_trivial_controls_setting_toggle"
+ android:summary="@string/lockscreen_trivial_controls_summary"
+ settings:controller="com.android.settings.display.ControlsTrivialPrivacyPreferenceController"/>
+
+ <SwitchPreference
android:key="lockscreen_double_line_clock_switch"
android:title="@string/lockscreen_double_line_clock_setting_toggle"
android:summary="@string/lockscreen_double_line_clock_summary"
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index c1298db..d79594c 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -191,6 +191,12 @@
android:title="@string/touch_sounds_title"
android:order="-30"/>
+ <!-- Show vibrate icon in status bar -->
+ <SwitchPreference
+ android:key="vibrate_icon"
+ android:title="@string/vibrate_icon_title"
+ android:order="-27"/>
+
<!-- Dock speaker plays -->
<DropDownPreference
android:key="dock_audio_media"
diff --git a/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java b/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
index 05dc784..98fd5f2 100644
--- a/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
+++ b/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceController.java
@@ -38,12 +38,6 @@
}
@Override
- public boolean isRestrictedByRingerModeSilent() {
- // Touch feedback is disabled when the phone is in silent mode.
- return true;
- }
-
- @Override
public int readIntensity() {
final int hapticFeedbackEnabled = Settings.System.getInt(mContentResolver,
Settings.System.HAPTIC_FEEDBACK_ENABLED, ON);
diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java
index 3bcf94f..964eae4 100644
--- a/src/com/android/settings/applications/AppStateNotificationBridge.java
+++ b/src/com/android/settings/applications/AppStateNotificationBridge.java
@@ -24,11 +24,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Slog;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.CompoundButton;
-import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.Utils;
@@ -127,8 +123,7 @@
private void addBlockStatus(AppEntry entry, NotificationsSentState stats) {
if (stats != null) {
stats.blocked = mBackend.getNotificationsBanned(entry.info.packageName, entry.info.uid);
- stats.systemApp = mBackend.isSystemApp(mContext, entry.info);
- stats.blockable = !stats.systemApp || (stats.systemApp && stats.blocked);
+ stats.blockable = mBackend.enableSwitch(mContext, entry.info);
}
}
@@ -229,11 +224,13 @@
return null;
}
return (buttonView, isChecked) -> {
- mBackend.setNotificationsEnabledForPackage(
- entry.info.packageName, entry.info.uid, isChecked);
NotificationsSentState stats = getNotificationsSentState(entry);
if (stats != null) {
- stats.blocked = !isChecked;
+ if (stats.blocked == isChecked) {
+ mBackend.setNotificationsEnabledForPackage(
+ entry.info.packageName, entry.info.uid, isChecked);
+ stats.blocked = !isChecked;
+ }
}
};
}
@@ -329,7 +326,6 @@
if (stats == null) {
return false;
}
-
return !stats.blocked;
}
@@ -344,6 +340,5 @@
public int sentCount = 0;
public boolean blockable;
public boolean blocked;
- public boolean systemApp;
}
}
diff --git a/src/com/android/settings/applications/appinfo/AppLocaleDetails.java b/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
index 8f1c212..d50a67b 100644
--- a/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
+++ b/src/com/android/settings/applications/appinfo/AppLocaleDetails.java
@@ -48,6 +48,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Locale;
/**
@@ -292,7 +293,7 @@
});
// Other locales in suggested languages group.
- Collection<Locale> supportedSystemLocales = new ArrayList<>();
+ Collection<Locale> supportedSystemLocales = new HashSet<>();
getCurrentSystemLocales().forEach(systemLocale -> {
mAppSupportedLocales.forEach(supportedLocale -> {
if (compareLocale(systemLocale, supportedLocale)) {
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 5085172..e360760 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -56,6 +56,7 @@
private static final String TAG = "BiometricEnrollIntroduction";
private static final String KEY_CONFIRMING_CREDENTIALS = "confirming_credentials";
+ private static final String KEY_SCROLLED_TO_BOTTOM = "scrolled";
private UserManager mUserManager;
private boolean mHasPassword;
@@ -64,6 +65,7 @@
protected boolean mConfirmingCredentials;
protected boolean mNextClicked;
private boolean mParentalConsentRequired;
+ private boolean mHasScrolledToBottom = false;
@Nullable private PorterDuffColorFilter mIconColorFilter;
@@ -152,6 +154,7 @@
if (savedInstanceState != null) {
mConfirmingCredentials = savedInstanceState.getBoolean(KEY_CONFIRMING_CREDENTIALS);
+ mHasScrolledToBottom = savedInstanceState.getBoolean(KEY_SCROLLED_TO_BOTTOM);
}
Intent intent = getIntent();
@@ -196,14 +199,14 @@
mFooterBarMixin = layout.getMixin(FooterBarMixin.class);
mFooterBarMixin.setPrimaryButton(getPrimaryFooterButton());
mFooterBarMixin.setSecondaryButton(getSecondaryFooterButton(), true /* usePrimaryStyle */);
- mFooterBarMixin.getSecondaryButton().setVisibility(View.INVISIBLE);
+ mFooterBarMixin.getSecondaryButton().setVisibility(
+ mHasScrolledToBottom ? View.VISIBLE : View.INVISIBLE);
final RequireScrollMixin requireScrollMixin = layout.getMixin(RequireScrollMixin.class);
requireScrollMixin.requireScrollWithButton(this, getPrimaryFooterButton(),
getMoreButtonTextRes(), this::onNextButtonClick);
requireScrollMixin.setOnRequireScrollStateChangedListener(
scrollNeeded -> {
-
boolean enrollmentCompleted = checkMaxEnrolled() != 0;
if (!enrollmentCompleted) {
// Update text of primary button from "More" to "Agree".
@@ -216,6 +219,7 @@
// Show secondary button once scroll is completed.
if (!scrollNeeded) {
getSecondaryFooterButton().setVisibility(View.VISIBLE);
+ mHasScrolledToBottom = true;
}
});
}
@@ -241,6 +245,7 @@
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_CONFIRMING_CREDENTIALS, mConfirmingCredentials);
+ outState.putBoolean(KEY_SCROLLED_TO_BOTTOM, mHasScrolledToBottom);
}
@Override
diff --git a/src/com/android/settings/biometrics/BiometricNavigationUtils.java b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
index e4f2b7f..b747faf 100644
--- a/src/com/android/settings/biometrics/BiometricNavigationUtils.java
+++ b/src/com/android/settings/biometrics/BiometricNavigationUtils.java
@@ -19,14 +19,17 @@
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import com.android.settings.Utils;
+import com.android.internal.app.UnlaunchableAppActivity;
import com.android.settings.core.SettingsBaseActivity;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.transition.SettingsTransitionHelper;
/**
@@ -41,15 +44,62 @@
* for managed profile, otherwise shows a dialog to disable the Quiet Mode.
*
* @param className The class name of Settings screen to launch.
- * @param extras Extras to put into the launching {@link Intent}.
+ * @param extras Extras to put into the launching {@link Intent}.
* @return true if the Settings screen is launching.
*/
public boolean launchBiometricSettings(Context context, String className, Bundle extras) {
- final UserManager userManager = UserManager.get(context);
- if (Utils.startQuietModeDialogIfNecessary(context, userManager, mUserId)) {
+ final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
+ if (quietModeDialogIntent != null) {
+ context.startActivity(quietModeDialogIntent);
return false;
}
+ context.startActivity(getSettingsPageIntent(className, extras));
+ return true;
+ }
+ /**
+ * Returns {@link Intent} to launch an appropriate Settings screen.
+ *
+ * <p>If the Setting is disabled by admin, returns {@link Intent} to launch an explanation.
+ * If Quiet Mode is enabled for managed profile, returns {@link Intent} to launch a dialog
+ * to disable the Quiet Mode. Otherwise, returns {@link Intent} to launch the Settings screen.
+ *
+ * @param className The class name of Settings screen to launch.
+ * @param enforcedAdmin Details of admin account that disables changing the setting.
+ * @param extras Extras to put into the result {@link Intent}.
+ */
+ public Intent getBiometricSettingsIntent(Context context, String className,
+ EnforcedAdmin enforcedAdmin, Bundle extras) {
+ if (enforcedAdmin != null) {
+ return getRestrictedDialogIntent(context, enforcedAdmin);
+ }
+ final Intent quietModeDialogIntent = getQuietModeDialogIntent(context);
+ return quietModeDialogIntent != null ? quietModeDialogIntent
+ : getSettingsPageIntent(className, extras);
+ }
+
+ private Intent getQuietModeDialogIntent(Context context) {
+ final UserManager userManager = UserManager.get(context);
+ if (userManager.isQuietModeEnabled(UserHandle.of(mUserId))) {
+ return UnlaunchableAppActivity.createInQuietModeDialogIntent(mUserId);
+ }
+ return null;
+ }
+
+ private Intent getRestrictedDialogIntent(Context context, EnforcedAdmin enforcedAdmin) {
+ final Intent intent = RestrictedLockUtils
+ .getShowAdminSupportDetailsIntent(context, enforcedAdmin);
+ int targetUserId = mUserId;
+ if (enforcedAdmin.user != null && RestrictedLockUtils
+ .isCurrentUserOrProfile(context, enforcedAdmin.user.getIdentifier())) {
+ targetUserId = enforcedAdmin.user.getIdentifier();
+ }
+ intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, enforcedAdmin.enforcedRestriction);
+ intent.putExtra(Intent.EXTRA_USER_ID, targetUserId);
+ return intent;
+ }
+
+ private Intent getSettingsPageIntent(String className, Bundle extras) {
final Intent intent = new Intent();
intent.setClassName(SETTINGS_PACKAGE_NAME, className);
if (!extras.isEmpty()) {
@@ -59,7 +109,7 @@
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);
- context.startActivity(intent);
- return true;
+
+ return intent;
}
}
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
index 6d2c301..de713dd 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
@@ -19,9 +19,7 @@
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.hardware.face.FaceManager;
-import android.os.UserHandle;
-import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollSidecar;
import java.util.Arrays;
@@ -33,7 +31,7 @@
private final int[] mDisabledFeatures;
- private FaceManager mFaceManager;
+ private FaceUpdater mFaceUpdater;
public FaceEnrollSidecar(int[] disabledFeatures) {
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
@@ -42,13 +40,13 @@
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- mFaceManager = Utils.getFaceManagerOrNull(activity);
+ mFaceUpdater = new FaceUpdater(activity);
}
@Override
public void startEnrollment() {
super.startEnrollment();
- mFaceManager.enroll(mUserId, mToken, mEnrollmentCancel,
+ mFaceUpdater.enroll(mUserId, mToken, mEnrollmentCancel,
mEnrollmentCallback, mDisabledFeatures);
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
index 616b736..7db5958 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
@@ -103,6 +103,7 @@
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final Context mContext;
private final FaceManager mFaceManager;
+ private final FaceUpdater mFaceUpdater;
private final FaceManager.RemovalCallback mRemovalCallback = new FaceManager.RemovalCallback() {
@Override
public void onRemovalError(Face face, int errMsgId, CharSequence errString) {
@@ -144,7 +145,7 @@
}
// Remove the first/only face
- mFaceManager.remove(faces.get(0), mUserId, mRemovalCallback);
+ mFaceUpdater.remove(faces.get(0), mUserId, mRemovalCallback);
} else {
mButton.setEnabled(true);
mRemoving = false;
@@ -157,6 +158,7 @@
mContext = context;
mFaceManager = context.getSystemService(FaceManager.class);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ mFaceUpdater = new FaceUpdater(context, mFaceManager);
}
public FaceSettingsRemoveButtonPreferenceController(Context context) {
diff --git a/src/com/android/settings/biometrics/face/FaceUpdater.java b/src/com/android/settings/biometrics/face/FaceUpdater.java
new file mode 100644
index 0000000..bb77cae
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceUpdater.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 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.biometrics.face;
+
+import android.content.Context;
+import android.hardware.face.Face;
+import android.hardware.face.FaceEnrollCell;
+import android.hardware.face.FaceManager;
+import android.os.CancellationSignal;
+import android.view.Surface;
+
+import androidx.annotation.Nullable;
+
+import com.android.settings.Utils;
+import com.android.settings.safetycenter.BiometricsSafetySource;
+
+/**
+ * Responsible for making {@link FaceManager#enroll} and {@link FaceManager#remove} calls and thus
+ * updating the face setting.
+ */
+public class FaceUpdater {
+
+ private final Context mContext;
+ private final FaceManager mFaceManager;
+
+ public FaceUpdater(Context context) {
+ mContext = context;
+ mFaceManager = Utils.getFaceManagerOrNull(context);
+ }
+
+ public FaceUpdater(Context context, FaceManager faceManager) {
+ mContext = context;
+ mFaceManager = faceManager;
+ }
+
+ /** Wrapper around the {@link FaceManager#enroll} method. */
+ public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
+ FaceManager.EnrollmentCallback callback, int[] disabledFeatures) {
+ mFaceManager.enroll(userId, hardwareAuthToken, cancel,
+ new NotifyingEnrollmentCallback(mContext, callback), disabledFeatures);
+ }
+
+ /** Wrapper around the {@link FaceManager#enroll} method. */
+ public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
+ FaceManager.EnrollmentCallback callback, int[] disabledFeatures,
+ @Nullable Surface previewSurface, boolean debugConsent) {
+ mFaceManager.enroll(userId, hardwareAuthToken, cancel,
+ new NotifyingEnrollmentCallback(mContext, callback), disabledFeatures,
+ previewSurface, debugConsent);
+ }
+
+ /** Wrapper around the {@link FaceManager#remove} method. */
+ public void remove(Face face, int userId, FaceManager.RemovalCallback callback) {
+ mFaceManager.remove(face, userId, new NotifyingRemovalCallback(mContext, callback));
+ }
+
+ /**
+ * Decorator of the {@link FaceManager.EnrollmentCallback} class that notifies other
+ * interested parties that a face setting has changed.
+ */
+ private static class NotifyingEnrollmentCallback
+ extends FaceManager.EnrollmentCallback {
+
+ private final Context mContext;
+ private final FaceManager.EnrollmentCallback mCallback;
+
+ NotifyingEnrollmentCallback(Context context,
+ FaceManager.EnrollmentCallback callback) {
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {
+ mCallback.onEnrollmentError(errMsgId, errString);
+ }
+
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+ mCallback.onEnrollmentHelp(helpMsgId, helpString);
+ }
+
+ @Override
+ public void onEnrollmentFrame(int helpCode, @Nullable CharSequence helpMessage,
+ @Nullable FaceEnrollCell cell, int stage, float pan, float tilt, float distance) {
+ mCallback.onEnrollmentFrame(helpCode, helpMessage, cell, stage, pan, tilt, distance);
+ }
+
+ @Override
+ public void onEnrollmentProgress(int remaining) {
+ mCallback.onEnrollmentProgress(remaining);
+ if (remaining == 0) {
+ BiometricsSafetySource.sendSafetyData(mContext); // biometrics data changed
+ }
+ }
+ }
+
+ /**
+ * Decorator of the {@link FaceManager.RemovalCallback} class that notifies other
+ * interested parties that a face setting has changed.
+ */
+ private static class NotifyingRemovalCallback extends FaceManager.RemovalCallback {
+
+ private final Context mContext;
+ private final FaceManager.RemovalCallback mCallback;
+
+ NotifyingRemovalCallback(Context context, FaceManager.RemovalCallback callback) {
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onRemovalError(Face fp, int errMsgId, CharSequence errString) {
+ mCallback.onRemovalError(fp, errMsgId, errString);
+ }
+
+ @Override
+ public void onRemovalSucceeded(@Nullable Face fp, int remaining) {
+ mCallback.onRemovalSucceeded(fp, remaining);
+ BiometricsSafetySource.sendSafetyData(mContext); // biometrics data changed
+ }
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
index 40348d4..d8ecd20 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollSidecar.java
@@ -22,7 +22,6 @@
import android.util.Log;
import com.android.settings.R;
-import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollSidecar;
/**
@@ -31,13 +30,13 @@
public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {
private static final String TAG = "FingerprintEnrollSidecar";
- private FingerprintManager mFingerprintManager;
+ private FingerprintUpdater mFingerprintUpdater;
private @FingerprintManager.EnrollReason int mEnrollReason;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
+ mFingerprintUpdater = new FingerprintUpdater(activity);
}
@Override
@@ -51,7 +50,7 @@
return;
}
- mFingerprintManager.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
+ mFingerprintUpdater.enroll(mToken, mEnrollmentCancel, mUserId, mEnrollmentCallback,
mEnrollReason);
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java b/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
index b356103..134462d 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintRemoveSidecar.java
@@ -21,7 +21,6 @@
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
-import android.os.UserHandle;
import android.util.Log;
import com.android.settings.core.InstrumentedFragment;
@@ -38,7 +37,7 @@
private Listener mListener;
private Fingerprint mFingerprintRemoving;
private Queue<Object> mFingerprintsRemoved;
- FingerprintManager mFingerprintManager;
+ private FingerprintUpdater mFingerprintUpdater;
private class RemovalError {
Fingerprint fingerprint;
@@ -80,15 +79,15 @@
return;
}
mFingerprintRemoving = fingerprint;
- mFingerprintManager.remove(fingerprint, userId, mRemoveCallback);;
+ mFingerprintUpdater.remove(fingerprint, userId, mRemoveCallback);
}
public FingerprintRemoveSidecar() {
mFingerprintsRemoved = new LinkedList<>();
}
- public void setFingerprintManager(FingerprintManager fingerprintManager) {
- mFingerprintManager = fingerprintManager;
+ public void setFingerprintUpdater(FingerprintUpdater fingerprintUpdater) {
+ mFingerprintUpdater = fingerprintUpdater;
}
@Override
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 50e1780..abc6d53 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -17,9 +17,9 @@
package com.android.settings.biometrics.fingerprint;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_UNLOCK_DISABLED_EXPLANATION;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_FINGERPRINT_LAST_DELETE_MESSAGE;
+import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
@@ -137,6 +137,7 @@
protected static final boolean DEBUG = false;
private FingerprintManager mFingerprintManager;
+ private FingerprintUpdater mFingerprintUpdater;
private List<FingerprintSensorPropertiesInternal> mSensorProperties;
private boolean mInFingerprintLockout;
private byte[] mToken;
@@ -299,6 +300,7 @@
Activity activity = getActivity();
mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
+ mFingerprintUpdater = new FingerprintUpdater(activity, mFingerprintManager);
mSensorProperties = mFingerprintManager.getSensorPropertiesInternal();
mToken = getIntent().getByteArrayExtra(
@@ -322,7 +324,7 @@
getFragmentManager().beginTransaction()
.add(mRemovalSidecar, TAG_REMOVAL_SIDECAR).commit();
}
- mRemovalSidecar.setFingerprintManager(mFingerprintManager);
+ mRemovalSidecar.setFingerprintUpdater(mFingerprintUpdater);
mRemovalSidecar.setListener(mRemovalListener);
RenameDialog renameDialog = (RenameDialog) getFragmentManager().
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java b/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java
new file mode 100644
index 0000000..75d8f7b
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 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.biometrics.fingerprint;
+
+import android.content.Context;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.CancellationSignal;
+
+import androidx.annotation.Nullable;
+
+import com.android.settings.Utils;
+import com.android.settings.safetycenter.BiometricsSafetySource;
+
+/**
+ * Responsible for making {@link FingerprintManager#enroll} and {@link FingerprintManager#remove}
+ * calls and thus updating the fingerprint setting.
+ */
+public class FingerprintUpdater {
+
+ private final Context mContext;
+ private final FingerprintManager mFingerprintManager;
+
+ public FingerprintUpdater(Context context) {
+ mContext = context;
+ mFingerprintManager = Utils.getFingerprintManagerOrNull(context);
+ }
+
+ public FingerprintUpdater(Context context, FingerprintManager fingerprintManager) {
+ mContext = context;
+ mFingerprintManager = fingerprintManager;
+ }
+
+ /** Wrapper around the {@link FingerprintManager#enroll} method. */
+ public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
+ FingerprintManager.EnrollmentCallback callback,
+ @FingerprintManager.EnrollReason int enrollReason) {
+ mFingerprintManager.enroll(hardwareAuthToken, cancel, userId,
+ new NotifyingEnrollmentCallback(mContext, callback), enrollReason);
+ }
+
+ /** Wrapper around the {@link FingerprintManager#remove} method. */
+ public void remove(Fingerprint fp, int userId, FingerprintManager.RemovalCallback callback) {
+ mFingerprintManager.remove(fp, userId, new NotifyingRemovalCallback(mContext, callback));
+ }
+
+ /**
+ * Decorator of the {@link FingerprintManager.EnrollmentCallback} class that notifies other
+ * interested parties that a fingerprint setting has changed.
+ */
+ private static class NotifyingEnrollmentCallback
+ extends FingerprintManager.EnrollmentCallback {
+
+ private final Context mContext;
+ private final FingerprintManager.EnrollmentCallback mCallback;
+
+ NotifyingEnrollmentCallback(Context context,
+ FingerprintManager.EnrollmentCallback callback) {
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {
+ mCallback.onEnrollmentError(errMsgId, errString);
+ }
+
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+ mCallback.onEnrollmentHelp(helpMsgId, helpString);
+ }
+
+ @Override
+ public void onEnrollmentProgress(int remaining) {
+ mCallback.onEnrollmentProgress(remaining);
+ if (remaining == 0) {
+ BiometricsSafetySource.sendSafetyData(mContext); // biometrics data changed
+ }
+ }
+ }
+
+ /**
+ * Decorator of the {@link FingerprintManager.RemovalCallback} class that notifies other
+ * interested parties that a fingerprint setting has changed.
+ */
+ private static class NotifyingRemovalCallback extends FingerprintManager.RemovalCallback {
+
+ private final Context mContext;
+ private final FingerprintManager.RemovalCallback mCallback;
+
+ NotifyingRemovalCallback(Context context, FingerprintManager.RemovalCallback callback) {
+ mContext = context;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
+ mCallback.onRemovalError(fp, errMsgId, errString);
+ }
+
+ @Override
+ public void onRemovalSucceeded(@Nullable Fingerprint fp, int remaining) {
+ mCallback.onRemovalSucceeded(fp, remaining);
+ BiometricsSafetySource.sendSafetyData(mContext); // biometrics data changed
+ }
+ }
+}
diff --git a/src/com/android/settings/display/ControlsPrivacyPreferenceController.java b/src/com/android/settings/display/ControlsPrivacyPreferenceController.java
index 00573a7..6f146d5 100644
--- a/src/com/android/settings/display/ControlsPrivacyPreferenceController.java
+++ b/src/com/android/settings/display/ControlsPrivacyPreferenceController.java
@@ -30,6 +30,9 @@
/**
* Preference for showing/hiding sensitive device controls content while the device is locked.
+ *
+ * Note that ControlsTrivialPrivacyPreferenceController depends on the preferenceKey
+ * of this controller.
*/
public class ControlsPrivacyPreferenceController extends TogglePreferenceController {
diff --git a/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java b/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java
new file mode 100644
index 0000000..a6c8e03
--- /dev/null
+++ b/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.display;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * Preference for requiring authorization to use home controls for certain devices.
+ */
+public class ControlsTrivialPrivacyPreferenceController extends TogglePreferenceController {
+
+ private static final String SETTING_KEY = Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS;
+ private static final String DEPENDENCY_SETTING_KEY = Settings.Secure.LOCKSCREEN_SHOW_CONTROLS;
+
+ public ControlsTrivialPrivacyPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Secure.getInt(mContext.getContentResolver(), SETTING_KEY, 0) != 0;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return Settings.Secure.putInt(mContext.getContentResolver(), SETTING_KEY,
+ isChecked ? 1 : 0);
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getText(R.string.lockscreen_trivial_controls_summary);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ preference.setEnabled(getAvailabilityStatus() != DISABLED_DEPENDENT_SETTING);
+ refreshSummary(preference);
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_display;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return showDeviceControlsSettingsEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
+ }
+
+ private boolean showDeviceControlsSettingsEnabled() {
+ return Settings.Secure.getInt(mContext.getContentResolver(), DEPENDENCY_SETTING_KEY, 0)
+ != 0;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference currentPreference = screen.findPreference(getPreferenceKey());
+ currentPreference.setDependency("lockscreen_privacy_controls_switch");
+ }
+}
diff --git a/src/com/android/settings/dream/DreamAdapter.java b/src/com/android/settings/dream/DreamAdapter.java
index 8e487d4..44f77e3 100644
--- a/src/com/android/settings/dream/DreamAdapter.java
+++ b/src/com/android/settings/dream/DreamAdapter.java
@@ -16,6 +16,7 @@
package com.android.settings.dream;
+import android.annotation.LayoutRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
@@ -31,7 +32,6 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
-import com.android.settingslib.Utils;
import java.util.List;
@@ -40,6 +40,8 @@
*/
public class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<IDreamItem> mItemList;
+ @LayoutRes
+ private final int mLayoutRes;
private int mLastSelectedPos = -1;
/**
@@ -88,8 +90,8 @@
? mContext.getDrawable(R.drawable.ic_dream_check_circle)
: item.getIcon();
if (icon instanceof VectorDrawable) {
- icon.setTint(Utils.getColorAttrDefaultColor(mContext,
- com.android.internal.R.attr.colorAccentPrimaryVariant));
+ icon.setTintList(
+ mContext.getColorStateList(R.color.dream_card_text_color_state_list));
}
final int iconSize = mContext.getResources().getDimensionPixelSize(
R.dimen.dream_item_icon_size);
@@ -116,15 +118,16 @@
}
}
- public DreamAdapter(List<IDreamItem> itemList) {
+ public DreamAdapter(@LayoutRes int layoutRes, List<IDreamItem> itemList) {
mItemList = itemList;
+ mLayoutRes = layoutRes;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
- .inflate(R.layout.dream_preference_layout, viewGroup, false);
+ .inflate(mLayoutRes, viewGroup, false);
return new DreamViewHolder(view, viewGroup.getContext());
}
diff --git a/src/com/android/settings/dream/DreamPickerController.java b/src/com/android/settings/dream/DreamPickerController.java
index af8c364..201d6de 100644
--- a/src/com/android/settings/dream/DreamPickerController.java
+++ b/src/com/android/settings/dream/DreamPickerController.java
@@ -74,9 +74,10 @@
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mAdapter = new DreamAdapter(mDreamInfos.stream()
- .map(DreamItem::new)
- .collect(Collectors.toList()));
+ mAdapter = new DreamAdapter(R.layout.dream_preference_layout,
+ mDreamInfos.stream()
+ .map(DreamItem::new)
+ .collect(Collectors.toList()));
final LayoutPreference pref = screen.findPreference(getPreferenceKey());
if (pref == null) {
diff --git a/src/com/android/settings/homepage/contextualcards/FaceReEnrollDialog.java b/src/com/android/settings/homepage/contextualcards/FaceReEnrollDialog.java
index e778e8c..a823924 100644
--- a/src/com/android/settings/homepage/contextualcards/FaceReEnrollDialog.java
+++ b/src/com/android/settings/homepage/contextualcards/FaceReEnrollDialog.java
@@ -30,6 +30,7 @@
import com.android.internal.app.AlertController;
import com.android.settings.R;
import com.android.settings.Utils;
+import com.android.settings.biometrics.face.FaceUpdater;
import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice;
/**
@@ -43,6 +44,7 @@
private static final String BIOMETRIC_ENROLL_ACTION = "android.settings.BIOMETRIC_ENROLL";
private FaceManager mFaceManager;
+ private FaceUpdater mFaceUpdater;
/**
* The type of re-enrollment that has been requested,
* see {@link Settings.Secure#FACE_UNLOCK_RE_ENROLL} for more details.
@@ -67,6 +69,7 @@
alertParams.mPositiveButtonListener = this;
mFaceManager = Utils.getFaceManagerOrNull(getApplicationContext());
+ mFaceUpdater = new FaceUpdater(getApplicationContext(), mFaceManager);
final Context context = getApplicationContext();
mReEnrollType = FaceSetupSlice.getReEnrollSetting(context, getUserId());
@@ -96,7 +99,7 @@
if (mFaceManager == null || !mFaceManager.hasEnrolledTemplates(userId)) {
finish();
}
- mFaceManager.remove(new Face("", 0, 0), userId, new FaceManager.RemovalCallback() {
+ mFaceUpdater.remove(new Face("", 0, 0), userId, new FaceManager.RemovalCallback() {
@Override
public void onRemovalError(Face face, int errMsgId, CharSequence errString) {
super.onRemovalError(face, errMsgId, errString);
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index dbc36d0..2ae91e2 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -22,15 +22,20 @@
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
import static android.os.UserHandle.USER_SYSTEM;
+import android.Manifest;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationHistory;
import android.app.NotificationManager;
+import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.companion.ICompanionDeviceManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -42,6 +47,7 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -100,12 +106,6 @@
return row;
}
- public boolean isBlockable(Context context, ApplicationInfo info) {
- final boolean blocked = getNotificationsBanned(info.packageName, info.uid);
- final boolean systemApp = isSystemApp(context, info);
- return !systemApp || (systemApp && blocked);
- }
-
public AppRow loadAppRow(Context context, PackageManager pm,
RoleManager roleManager, PackageInfo app) {
final AppRow row = loadAppRow(context, pm, app.applicationInfo);
@@ -130,6 +130,15 @@
|| roles.contains(RoleManager.ROLE_EMERGENCY)) {
row.systemApp = row.lockedImportance = true;
}
+ // if the app targets T but has not requested the permission, we cannot change the
+ // permission state
+ if (app.applicationInfo.targetSdkVersion > Build.VERSION_CODES.S_V2) {
+ if (app.requestedPermissions == null || Arrays.stream(app.requestedPermissions)
+ .noneMatch(p -> p.equals(android.Manifest.permission.POST_NOTIFICATIONS))) {
+ row.lockedImportance = true;
+ }
+ }
+
} else {
row.systemApp = Utils.isSystemPackage(context.getResources(), pm, app);
List<String> roles = rm.getHeldRolesFromController(app.packageName);
@@ -192,14 +201,15 @@
return sb.toString();
}
- public boolean isSystemApp(Context context, ApplicationInfo app) {
+ public boolean enableSwitch(Context context, ApplicationInfo app) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(
app.packageName, PackageManager.GET_SIGNATURES);
RoleManager rm = context.getSystemService(RoleManager.class);
final AppRow row = new AppRow();
recordCanBeBlocked(context, context.getPackageManager(), rm, info, row);
- return row.systemApp;
+ boolean systemBlockable = !row.systemApp || (row.systemApp && row.banned);
+ return systemBlockable && !row.lockedImportance;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index 971937c..2d6f377 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -267,12 +267,15 @@
new BootSoundPreferenceController(context);
final EmergencyTonePreferenceController emergencyTonePreferenceController =
new EmergencyTonePreferenceController(context, fragment, lifecycle);
+ final VibrateIconPreferenceController vibrateIconPreferenceController =
+ new VibrateIconPreferenceController(context, fragment, lifecycle);
controllers.add(dialPadTonePreferenceController);
controllers.add(screenLockSoundPreferenceController);
controllers.add(chargingSoundPreferenceController);
controllers.add(dockingSoundPreferenceController);
controllers.add(touchSoundPreferenceController);
+ controllers.add(vibrateIconPreferenceController);
controllers.add(dockAudioMediaPreferenceController);
controllers.add(bootSoundPreferenceController);
controllers.add(emergencyTonePreferenceController);
@@ -283,6 +286,7 @@
chargingSoundPreferenceController,
dockingSoundPreferenceController,
touchSoundPreferenceController,
+ vibrateIconPreferenceController,
dockAudioMediaPreferenceController,
bootSoundPreferenceController,
emergencyTonePreferenceController)));
diff --git a/src/com/android/settings/notification/VibrateIconPreferenceController.java b/src/com/android/settings/notification/VibrateIconPreferenceController.java
new file mode 100644
index 0000000..25d2326
--- /dev/null
+++ b/src/com/android/settings/notification/VibrateIconPreferenceController.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 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 com.android.settings.notification.SettingPref.TYPE_SECURE;
+
+import android.content.Context;
+import android.provider.Settings.Secure;
+
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class VibrateIconPreferenceController extends SettingPrefController {
+
+ private static final String KEY_VIBRATE_ICON = "vibrate_icon";
+
+ public VibrateIconPreferenceController(Context context, SettingsPreferenceFragment parent,
+ Lifecycle lifecycle) {
+ super(context, parent, lifecycle);
+ mPreference = new SettingPref(
+ TYPE_SECURE, KEY_VIBRATE_ICON, Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0 /*default off*/);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+}
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index f31abb9..a28f237 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -75,6 +75,7 @@
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.safetycenter.LockScreenSafetySource;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settingslib.RestrictedPreference;
@@ -856,6 +857,7 @@
}
mLockPatternUtils.setLockScreenDisabled(disabled, mUserId);
getActivity().setResult(Activity.RESULT_OK);
+ LockScreenSafetySource.onLockScreenChange(getContext());
finish();
}
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 50a0bae..9f307cb 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -18,13 +18,13 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PASSWORD_RECENTLY_USED;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PIN_RECENTLY_USED;
import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PASSWORD_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.REENTER_WORK_PROFILE_PIN_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PASSWORD_HEADER;
import static android.app.admin.DevicePolicyResources.Strings.Settings.SET_WORK_PROFILE_PIN_HEADER;
+import static android.app.admin.DevicePolicyResources.Strings.UNDEFINED;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
diff --git a/src/com/android/settings/password/SaveChosenLockWorkerBase.java b/src/com/android/settings/password/SaveChosenLockWorkerBase.java
index cea908b..980b022 100644
--- a/src/com/android/settings/password/SaveChosenLockWorkerBase.java
+++ b/src/com/android/settings/password/SaveChosenLockWorkerBase.java
@@ -30,6 +30,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.settings.R;
+import com.android.settings.safetycenter.LockScreenSafetySource;
/**
* An invisible retained worker fragment to track the AsyncWork that saves (and optionally
@@ -110,6 +111,7 @@
if (mUnificationProfileCredential != null) {
mUnificationProfileCredential.zeroize();
}
+ LockScreenSafetySource.onLockScreenChange(getContext());
}
public void setBlocking(boolean blocking) {
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index bfe2fb0..6a93bda 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -16,14 +16,30 @@
package com.android.settings.safetycenter;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricNavigationUtils;
+import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils;
+import com.android.settings.biometrics.face.FaceStatusUtils;
+import com.android.settings.biometrics.fingerprint.FingerprintStatusUtils;
+import com.android.settingslib.RestrictedLockUtils;
/** Combined Biometrics Safety Source for Safety Center. */
public final class BiometricsSafetySource {
public static final String SAFETY_SOURCE_ID = "Biometrics";
- private BiometricsSafetySource() {}
+ private BiometricsSafetySource() {
+ }
/** Sends biometric safety data to Safety Center. */
public static void sendSafetyData(Context context) {
@@ -31,7 +47,75 @@
return;
}
- // TODO(b/215517420): Send biometric data to Safety Center if there are biometrics available
- // on this device.
+ final BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils();
+ final CombinedBiometricStatusUtils combinedBiometricStatusUtils =
+ new CombinedBiometricStatusUtils(context);
+
+ if (combinedBiometricStatusUtils.isAvailable()) {
+ final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ combinedBiometricStatusUtils.getDisablingAdmin();
+ sendBiometricSafetySourceData(context,
+ context.getString(R.string.security_settings_biometric_preference_title),
+ combinedBiometricStatusUtils.getSummary(),
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ combinedBiometricStatusUtils.getSettingsClassName(), disablingAdmin,
+ Bundle.EMPTY),
+ disablingAdmin == null /* enabled */);
+ return;
+ }
+
+ final FaceManager faceManager = Utils.getFaceManagerOrNull(context);
+ final FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager);
+
+ if (faceStatusUtils.isAvailable()) {
+ final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ faceStatusUtils.getDisablingAdmin();
+ sendBiometricSafetySourceData(context,
+ context.getString(R.string.security_settings_face_preference_title),
+ faceStatusUtils.getSummary(),
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ faceStatusUtils.getSettingsClassName(), disablingAdmin,
+ Bundle.EMPTY),
+ disablingAdmin == null /* enabled */);
+ return;
+ }
+
+ final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
+ final FingerprintStatusUtils fingerprintStatusUtils = new FingerprintStatusUtils(context,
+ fingerprintManager);
+
+ if (fingerprintStatusUtils.isAvailable()) {
+ final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ fingerprintStatusUtils.getDisablingAdmin();
+ sendBiometricSafetySourceData(context,
+ context.getString(R.string.security_settings_fingerprint_preference_title),
+ fingerprintStatusUtils.getSummary(),
+ biometricNavigationUtils.getBiometricSettingsIntent(context,
+ fingerprintStatusUtils.getSettingsClassName(), disablingAdmin,
+ Bundle.EMPTY),
+ disablingAdmin == null /* enabled */);
+ }
+ }
+
+ private static void sendBiometricSafetySourceData(Context context, String title, String summary,
+ Intent clickIntent, boolean enabled) {
+ final PendingIntent pendingIntent = createPendingIntent(context, clickIntent);
+
+ final SafetySourceStatus status = new SafetySourceStatus.Builder(title, summary,
+ SafetySourceStatus.STATUS_LEVEL_NONE, pendingIntent)
+ .setEnabled(enabled).build();
+ final SafetySourceData safetySourceData = new SafetySourceData.Builder(SAFETY_SOURCE_ID)
+ .setStatus(status).build();
+
+ SafetyCenterManagerWrapper.get().sendSafetyCenterUpdate(context, safetySourceData);
+ }
+
+ private static PendingIntent createPendingIntent(Context context, Intent intent) {
+ return PendingIntent
+ .getActivity(
+ context,
+ 0 /* requestCode */,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE);
}
}
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index 5adaa79..d010821 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -17,10 +17,12 @@
package com.android.settings.safetycenter;
import android.app.PendingIntent;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
import android.safetycenter.SafetySourceStatus;
import android.safetycenter.SafetySourceStatus.IconAction;
@@ -33,6 +35,9 @@
public final class LockScreenSafetySource {
public static final String SAFETY_SOURCE_ID = "LockScreen";
+ public static final String NO_SCREEN_LOCK_ISSUE_ID = "NoScreenLockIssue";
+ public static final String NO_SCREEN_LOCK_ISSUE_TYPE_ID = "NoScreenLockIssueType";
+ public static final String SET_SCREEN_LOCK_ACTION_ID = "SetScreenLockAction";
private LockScreenSafetySource() {
}
@@ -66,12 +71,23 @@
.setEnabled(
!screenLockPreferenceDetailsUtils.isPasswordQualityManaged(userId, admin))
.setIconAction(gearMenuIconAction).build();
- final SafetySourceData safetySourceData = new SafetySourceData.Builder(
- SAFETY_SOURCE_ID).setStatus(status).build();
+ final SafetySourceData.Builder safetySourceDataBuilder = new SafetySourceData.Builder(
+ SAFETY_SOURCE_ID).setStatus(status);
+ if (!screenLockPreferenceDetailsUtils.isLockPatternSecure()) {
+ safetySourceDataBuilder.addIssue(createNoScreenLockIssue(context, pendingIntent));
+ }
+ final SafetySourceData safetySourceData = safetySourceDataBuilder.build();
SafetyCenterManagerWrapper.get().sendSafetyCenterUpdate(context, safetySourceData);
}
+ /** Notifies Safety Center of a change in lock screen settings. */
+ public static void onLockScreenChange(Context context) {
+ sendSafetyData(
+ context,
+ new ScreenLockPreferenceDetailsUtils(context, SettingsEnums.SAFETY_CENTER));
+ }
+
private static IconAction createGearMenuIconAction(Context context,
ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) {
return screenLockPreferenceDetailsUtils.shouldShowGearMenu() ? new IconAction(
@@ -89,4 +105,20 @@
intent,
PendingIntent.FLAG_IMMUTABLE);
}
+
+ private static SafetySourceIssue createNoScreenLockIssue(Context context,
+ PendingIntent pendingIntent) {
+ final SafetySourceIssue.Action action = new SafetySourceIssue.Action.Builder(
+ SET_SCREEN_LOCK_ACTION_ID,
+ context.getString(R.string.no_screen_lock_issue_action_label),
+ pendingIntent).build();
+ return new SafetySourceIssue.Builder(
+ NO_SCREEN_LOCK_ISSUE_ID,
+ context.getString(R.string.no_screen_lock_issue_title),
+ context.getString(R.string.no_screen_lock_issue_summary),
+ SafetySourceStatus.STATUS_LEVEL_RECOMMENDATION,
+ NO_SCREEN_LOCK_ISSUE_TYPE_ID)
+ .setIssueCategory(SafetySourceIssue.ISSUE_CATEGORY_DEVICE)
+ .addAction(action).build();
+ }
}
diff --git a/src/com/android/settings/security/LockscreenDashboardFragment.java b/src/com/android/settings/security/LockscreenDashboardFragment.java
index b3351ac..2e4a1f2 100644
--- a/src/com/android/settings/security/LockscreenDashboardFragment.java
+++ b/src/com/android/settings/security/LockscreenDashboardFragment.java
@@ -21,8 +21,13 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
@@ -68,6 +73,8 @@
private AmbientDisplayConfiguration mConfig;
private OwnerInfoPreferenceController mOwnerInfoPreferenceController;
+ @VisibleForTesting
+ ContentObserver mControlsContentObserver;
@Override
public int getMetricsCategory() {
@@ -106,6 +113,27 @@
use(AmbientDisplayNotificationsPreferenceController.class).setConfig(getConfig(context));
use(DoubleTapScreenPreferenceController.class).setConfig(getConfig(context));
use(PickupGesturePreferenceController.class).setConfig(getConfig(context));
+
+ mControlsContentObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updatePreferenceStates();
+ }
+ };
+ context.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS),
+ false /* notifyForDescendants */, mControlsContentObserver);
+ }
+
+ @Override
+ public void onDetach() {
+ if (mControlsContentObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mControlsContentObserver);
+ mControlsContentObserver = null;
+ }
+ super.onDetach();
}
@Override
diff --git a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java
index 22e2b8a..44d2e86 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationIntensityPreferenceControllerTest.java
@@ -18,9 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
@@ -45,6 +47,7 @@
private static final String PREFERENCE_KEY = "preference_key";
@Mock private PreferenceScreen mScreen;
+ @Mock private AudioManager mAudioManager;
private Lifecycle mLifecycle;
private Context mContext;
@@ -56,7 +59,9 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle(() -> mLifecycle);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mVibrator = mContext.getSystemService(Vibrator.class);
mController = new AlarmVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY,
Vibrator.VIBRATION_INTENSITY_HIGH);
@@ -88,6 +93,26 @@
}
@Test
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
+ updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
public void updateState_shouldDisplayIntensityInSliderPosition() {
updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationTogglePreferenceControllerTest.java
index 82d65f7..48599ac 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationTogglePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AlarmVibrationTogglePreferenceControllerTest.java
@@ -18,9 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
@@ -45,6 +47,7 @@
private static final String PREFERENCE_KEY = "preference_key";
@Mock private PreferenceScreen mScreen;
+ @Mock AudioManager mAudioManager;
private Lifecycle mLifecycle;
private Context mContext;
@@ -56,7 +59,9 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle(() -> mLifecycle);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mVibrator = mContext.getSystemService(Vibrator.class);
mController = new AlarmVibrationTogglePreferenceController(mContext, PREFERENCE_KEY);
mLifecycle.addObserver(mController);
@@ -84,6 +89,26 @@
}
@Test
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
+ updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
public void updateState_shouldDisplayOnOffState() {
updateSetting(Settings.System.ALARM_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java
index 9d87c93..344a25f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackIntensityPreferenceControllerTest.java
@@ -94,28 +94,22 @@
}
@Test
- public void updateState_ringerModeUpdates_shouldPreserveSettingAndDisplaySummary() {
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mController.updateState(mPreference);
assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
- assertThat(mPreference.getSummary()).isNull();
assertThat(mPreference.isEnabled()).isTrue();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
mController.updateState(mPreference);
- assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_OFF);
- // TODO(b/136805769): summary is broken in SeekBarPreference, enable this once fixed
-// assertThat(mPreference.getSummary()).isNotNull();
-// assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString(
-// R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary));
- assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mController.updateState(mPreference);
assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
- assertThat(mPreference.getSummary()).isNull();
assertThat(mPreference.isEnabled()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackTogglePreferenceControllerTest.java
index 3e8aeac..77aede2 100644
--- a/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackTogglePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HapticFeedbackTogglePreferenceControllerTest.java
@@ -31,7 +31,6 @@
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
-import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -90,29 +89,23 @@
assertThat(mPreference.isChecked()).isTrue();
}
-
@Test
- public void updateState_ringerModeUpdates_shouldPreserveSettingAndDisplaySummary() {
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
updateSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
- assertThat(mPreference.getSummary()).isNull();
assertThat(mPreference.isEnabled()).isTrue();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isFalse();
- assertThat(mPreference.getSummary()).isNotNull();
- assertThat(mPreference.getSummary().toString()).isEqualTo(mContext.getString(
- R.string.accessibility_vibration_setting_disabled_for_silent_mode_summary));
- assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
- assertThat(mPreference.getSummary()).isNull();
assertThat(mPreference.isEnabled()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java
index 0a9f242..3a4b43a 100644
--- a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationIntensityPreferenceControllerTest.java
@@ -18,9 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
@@ -46,6 +48,7 @@
private static final String PREFERENCE_KEY = "preference_key";
@Mock private PreferenceScreen mScreen;
+ @Mock private AudioManager mAudioManager;
private Lifecycle mLifecycle;
private Context mContext;
@@ -57,7 +60,9 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle(() -> mLifecycle);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mVibrator = mContext.getSystemService(Vibrator.class);
mController = new MediaVibrationIntensityPreferenceController(mContext, PREFERENCE_KEY,
Vibrator.VIBRATION_INTENSITY_HIGH);
@@ -89,6 +94,26 @@
}
@Test
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
+ updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getProgress()).isEqualTo(Vibrator.VIBRATION_INTENSITY_LOW);
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
public void updateState_shouldDisplayIntensityInSliderPosition() {
updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationTogglePreferenceControllerTest.java
index 7923cca..49a7b7b 100644
--- a/tests/robotests/src/com/android/settings/accessibility/MediaVibrationTogglePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/MediaVibrationTogglePreferenceControllerTest.java
@@ -18,9 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.media.AudioManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.provider.Settings;
@@ -46,6 +48,7 @@
private static final String PREFERENCE_KEY = "preference_key";
@Mock private PreferenceScreen mScreen;
+ @Mock AudioManager mAudioManager;
private Lifecycle mLifecycle;
private Context mContext;
@@ -57,7 +60,9 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle(() -> mLifecycle);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
mVibrator = mContext.getSystemService(Vibrator.class);
mController = new MediaVibrationTogglePreferenceController(mContext, PREFERENCE_KEY);
mLifecycle.addObserver(mController);
@@ -85,6 +90,26 @@
}
@Test
+ public void updateState_ringerModeUpdates_shouldNotAffectSettings() {
+ updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
public void updateState_shouldDisplayOnOffState() {
updateSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java
index 21a2947..b725fc3 100644
--- a/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppStateNotificationBridgeTest.java
@@ -99,7 +99,7 @@
when(mState.newSession(any())).thenReturn(mSession);
when(mState.getBackgroundLooper()).thenReturn(mock(Looper.class));
when(mBackend.getNotificationsBanned(anyString(), anyInt())).thenReturn(true);
- when(mBackend.isSystemApp(any(), any())).thenReturn(true);
+ when(mBackend.enableSwitch(any(), any())).thenReturn(true);
// most tests assume no work profile
when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
mContext = RuntimeEnvironment.application.getApplicationContext();
@@ -245,7 +245,6 @@
assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentDaily).isEqualTo(1);
assertThat(((NotificationsSentState) apps.get(0).extraInfo).avgSentWeekly).isEqualTo(0);
assertThat(((NotificationsSentState) apps.get(0).extraInfo).blocked).isTrue();
- assertThat(((NotificationsSentState) apps.get(0).extraInfo).systemApp).isTrue();
assertThat(((NotificationsSentState) apps.get(0).extraInfo).blockable).isTrue();
}
@@ -376,7 +375,6 @@
assertThat(((NotificationsSentState) entry.extraInfo).avgSentDaily).isEqualTo(2);
assertThat(((NotificationsSentState) entry.extraInfo).avgSentWeekly).isEqualTo(0);
assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue();
- assertThat(((NotificationsSentState) entry.extraInfo).systemApp).isTrue();
assertThat(((NotificationsSentState) entry.extraInfo).blockable).isTrue();
}
@@ -563,11 +561,11 @@
entry.extraInfo = new NotificationsSentState();
CompoundButton.OnCheckedChangeListener listener = mBridge.getSwitchOnCheckedListener(entry);
- listener.onCheckedChanged(toggle, true);
+ listener.onCheckedChanged(toggle, false);
verify(mBackend).setNotificationsEnabledForPackage(
- entry.info.packageName, entry.info.uid, true);
- assertThat(((NotificationsSentState) entry.extraInfo).blocked).isFalse();
+ entry.info.packageName, entry.info.uid, false);
+ assertThat(((NotificationsSentState) entry.extraInfo).blocked).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
new file mode 100644
index 0000000..2c53d4e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ControlsTrivialPrivacyPreferenceControllerTest {
+
+ private static final String TEST_KEY = "test_key";
+ private static final String SETTING_KEY = Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS;
+ private static final String DEPENDENCY_SETTING_KEY = Settings.Secure.LOCKSCREEN_SHOW_CONTROLS;
+
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ private ControlsTrivialPrivacyPreferenceController mController;
+
+ @Mock
+ private Preference mPreference;
+
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+
+ mContentResolver = mContext.getContentResolver();
+
+ mController = new ControlsTrivialPrivacyPreferenceController(mContext, TEST_KEY);
+ }
+
+ @Test
+ public void isCheckedWhenSettingIsTrue() {
+ Settings.Secure.putInt(mContentResolver, SETTING_KEY, 1);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isCheckedWhenSettingIsFalse() {
+ Settings.Secure.putInt(mContentResolver, SETTING_KEY, 0);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isCheckedWhenSettingIsNull() {
+ Settings.Secure.putString(mContentResolver, SETTING_KEY, null);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void checkedMeansSettingIsTrue() {
+ mController.setChecked(true);
+
+ assertThat(Settings.Secure.getInt(mContentResolver, SETTING_KEY, 0)).isNotEqualTo(0);
+ }
+
+ @Test
+ public void uncheckedMeansSettingIsFalse() {
+ mController.setChecked(false);
+
+ assertThat(Settings.Secure.getInt(mContentResolver, SETTING_KEY, 0)).isEqualTo(0);
+ }
+
+ @Test
+ public void getSummaryRequireDeviceControls() {
+ Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 0);
+
+ assertThat(mController.getSummary().toString()).isEqualTo(
+ mContext.getText(R.string.lockscreen_trivial_controls_summary));
+ }
+
+ @Test
+ public void getSummaryDefault() {
+ Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 1);
+
+ assertThat(mController.getSummary().toString()).isEqualTo(
+ mContext.getText(R.string.lockscreen_trivial_controls_summary));
+ }
+
+ @Test
+ public void updateState() {
+ Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 1);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setEnabled(anyBoolean());
+ verify(mPreference, atLeastOnce()).setSummary(mController.getSummary());
+ }
+
+ @Test
+ public void getAvailabilityStatusWithoutDeviceControls() {
+ Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 0);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ public void getAvailabilityStatusWithDeviceControls() {
+ Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 1);
+
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void setDependency() {
+ Mockito.when(mPreferenceScreen
+ .findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ mController.displayPreference(mPreferenceScreen);
+ verify(mPreference).setDependency(anyString());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java b/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java
index 64cde5a..a7ddec3 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationBackendTest.java
@@ -37,7 +37,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
import android.net.MacAddress;
+import android.os.Build;
import android.os.Parcel;
import android.provider.Settings;
@@ -178,6 +180,51 @@
}
@Test
+ public void testMarkAppRow_targetsT_noPermissionRequest() throws Exception {
+ Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
+
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = "test";
+ pi.applicationInfo = new ApplicationInfo();
+ pi.applicationInfo.packageName = "test";
+ pi.applicationInfo.uid = 123;
+ pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU;
+ pi.requestedPermissions = new String[] {"something"};
+
+ when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false);
+
+ AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application,
+ mock(PackageManager.class), mock(RoleManager.class), pi);
+
+ assertFalse(appRow.systemApp);
+ assertTrue(appRow.lockedImportance);
+ }
+
+ @Test
+ public void testMarkAppRow_targetsT_permissionRequest() throws Exception {
+ Secure.putIntForUser(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
+
+ PackageInfo pi = new PackageInfo();
+ pi.packageName = "test";
+ pi.applicationInfo = new ApplicationInfo();
+ pi.applicationInfo.packageName = "test";
+ pi.applicationInfo.uid = 123;
+ pi.applicationInfo.targetSdkVersion= Build.VERSION_CODES.TIRAMISU;
+ pi.requestedPermissions = new String[] {"something",
+ android.Manifest.permission.POST_NOTIFICATIONS};
+
+ when(mInm.isPermissionFixed(pi.packageName, 0)).thenReturn(false);
+
+ AppRow appRow = new NotificationBackend().loadAppRow(RuntimeEnvironment.application,
+ mock(PackageManager.class), mock(RoleManager.class), pi);
+
+ assertFalse(appRow.systemApp);
+ assertFalse(appRow.lockedImportance);
+ }
+
+ @Test
public void testMarkAppRow_notDefaultPackage() {
PackageInfo pi = new PackageInfo();
pi.packageName = "test";
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBypassingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBypassingAppsPreferenceControllerTest.java
index 8f31b0a..460ae2d 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBypassingAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBypassingAppsPreferenceControllerTest.java
@@ -185,7 +185,7 @@
// only channel bypassing DND is a conversation (which will be showed on the
// conversations page instead of the apps page)
assertThat(mController.mPreference.isEnabled()).isTrue();
- assertThat(mController.getSummary().contains("None")).isTrue();
+ assertThat(mController.getSummary().contains("No apps")).isTrue();
}
@Test
@@ -246,7 +246,7 @@
// THEN the preference is enabled and summary is updated
assertThat(mController.mPreference.isEnabled()).isTrue();
- assertThat(mController.getSummary().contains("None")).isTrue();
+ assertThat(mController.getSummary().contains("No apps")).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java
index 5c60001..bf5e957 100644
--- a/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/security/LockscreenDashboardFragmentTest.java
@@ -67,6 +67,7 @@
.thenReturn(mLockPatternUtils);
mContext = RuntimeEnvironment.application;
mTestFragment = spy(new TestFragment());
+ doReturn(mContext).when(mTestFragment).getContext();
}
@Test
@@ -131,6 +132,14 @@
.doesNotContain("security_lockscreen_settings_screen");
}
+ @Test
+ public void controlsSettings() {
+ mTestFragment.onAttach(mContext);
+ assertThat(mTestFragment.mControlsContentObserver).isNotNull();
+ mTestFragment.onDetach();
+ assertThat(mTestFragment.mControlsContentObserver).isNull();
+ }
+
public static class TestFragment extends LockscreenDashboardFragment {
@Override
protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java b/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java
index 0f9d54b..aa0daad 100644
--- a/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java
+++ b/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java
@@ -43,7 +43,9 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Set;
/**
* Unittest for ApplocaleDetails
@@ -151,8 +153,9 @@
@Test
@UiThreadTest
public void
- handleAllLocalesData_noAppAndNoSupportedSimLocale_1stSuggestedLocaleIsAssetLocale() {
- Locale firstAssetLocale = new Locale("en", "GB");
+ handleAllLocalesData_noAppAndNoSupportedSimLocale_suggestedLocaleIsSupported() {
+ Locale testEnAssetLocale = new Locale("en", "GB");
+ Locale testJaAssetLocale = new Locale("ja", "JP");
setupInitialLocales(
/* appLocale= */ "",
/* simCountry= */ "tw",
@@ -166,8 +169,8 @@
helper.handleAllLocalesData();
Collection<Locale> suggestedLocales = helper.getSuggestedLocales();
- Locale locale = suggestedLocales.iterator().next();
- assertTrue(locale.equals(firstAssetLocale));
+ assertTrue(suggestedLocales.contains(testEnAssetLocale));
+ assertTrue(suggestedLocales.contains(testJaAssetLocale));
}
@Test
@@ -297,6 +300,35 @@
@Test
@UiThreadTest
+ public void handleAllLocalesData_sameLocaleButDifferentRegion_notShowDuplicatedLocale() {
+ setupInitialLocales(
+ /* appLocale= */ "",
+ /* simCountry= */ "",
+ /* networkCountry= */ "",
+ /* systemLocales= */ "en-us, en-gb, jp, ne",
+ /* packageLocales= */ "pa, cn, tw, en-us, en-gb",
+ /* assetLocales= */ new String[]{});
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ Collection<Locale> suggestedLocales = helper.getSuggestedLocales();
+ assertFalse(hasDuplicatedResult(suggestedLocales));
+ }
+
+ private boolean hasDuplicatedResult(Collection<Locale> locales) {
+ Set<Locale> tempSet = new HashSet<>();
+ for (Locale locale : locales) {
+ if (!tempSet.add(locale)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Test
+ @UiThreadTest
public void handleAllLocalesData_supportLocaleListIsNotEmpty() {
DummyAppLocaleDetailsHelper helper =
new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
diff --git a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
index 3e6ac09..c767c32 100644
--- a/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/BiometricNavigationUtilsTest.java
@@ -24,14 +24,20 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,6 +50,8 @@
private static final String SETTINGS_CLASS_NAME = "SettingsClassName";
private static final String EXTRA_KEY = "EXTRA_KEY";
+ private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
+ private static final int ADMIN_USER_ID = 2;
@Mock
private UserManager mUserManager;
@@ -60,7 +68,7 @@
}
@Test
- public void openBiometricSettings_quietMode_launchesQuiteModeDialog() {
+ public void launchBiometricSettings_quietMode_launchesQuiteModeDialog() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
mBiometricNavigationUtils.launchBiometricSettings(mContext, SETTINGS_CLASS_NAME,
@@ -70,7 +78,7 @@
}
@Test
- public void openBiometricSettings_quietMode_returnsFalse() {
+ public void launchBiometricSettings_quietMode_returnsFalse() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
@@ -78,7 +86,7 @@
}
@Test
- public void openBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() {
+ public void launchBiometricSettings_noQuietMode_emptyExtras_launchesFragmentWithoutExtras() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
mBiometricNavigationUtils.launchBiometricSettings(
@@ -88,7 +96,7 @@
}
@Test
- public void openBiometricSettings_noQuietMode_emptyExtras_returnsTrue() {
+ public void launchBiometricSettings_noQuietMode_emptyExtras_returnsTrue() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
@@ -96,7 +104,7 @@
}
@Test
- public void openBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() {
+ public void launchBiometricSettings_noQuietMode_withExtras_launchesFragmentWithExtras() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
final Bundle extras = createNotEmptyExtras();
@@ -106,13 +114,79 @@
}
@Test
- public void openBiometricSettings_noQuietMode_withExtras_returnsTrue() {
+ public void launchBiometricSettings_noQuietMode_withExtras_returnsTrue() {
when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
assertThat(mBiometricNavigationUtils.launchBiometricSettings(
mContext, SETTINGS_CLASS_NAME, createNotEmptyExtras())).isTrue();
}
+ @Test
+ public void getBiometricSettingsIntent_quietMode_returnsQuiteModeDialogIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY);
+
+ assertQuietModeDialogIntent(intent);
+ }
+
+ @Test
+ public void getBiometricSettingsIntent_noQuietMode_emptyExtras_returnsSettingsIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, Bundle.EMPTY);
+
+ assertSettingsPageIntent(intent, false /* shouldContainExtras */);
+ }
+
+ @Test
+ public void getBiometricSettingsIntent_noQuietMode_withExtras_returnsSettingsIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, null /* enforcedAdmin */, createNotEmptyExtras());
+
+ assertSettingsPageIntent(intent, true /* shouldContainExtras */);
+ }
+
+ @Test
+ public void getBiometricSettingsIntent_whenDisabledByAdmin_quietMode_returnsBlockedIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(true);
+ final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+ COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+ assertBlockedByAdminDialogIntent(intent);
+ }
+
+ @Test
+ public void getBiometricSettingsIntent_whenDisabledByAdmin_emptyExtras_returnsBlockedIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+ final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+ COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+ assertBlockedByAdminDialogIntent(intent);
+ }
+
+ @Test
+ public void getBiometricSettingsIntent_whenDisabledByAdmin_withExtras_returnsBlockedIntent() {
+ when(mUserManager.isQuietModeEnabled(any())).thenReturn(false);
+ final EnforcedAdmin enforcedAdmin = new EnforcedAdmin(
+ COMPONENT_NAME, UserHandle.of(ADMIN_USER_ID));
+
+ final Intent intent = mBiometricNavigationUtils.getBiometricSettingsIntent(
+ mContext, SETTINGS_CLASS_NAME, enforcedAdmin, Bundle.EMPTY);
+
+ assertBlockedByAdminDialogIntent(intent);
+ }
+
private Bundle createNotEmptyExtras() {
final Bundle bundle = new Bundle();
bundle.putInt(EXTRA_KEY, 0);
@@ -124,17 +198,32 @@
verify(mContext).startActivity(intentCaptor.capture());
Intent intent = intentCaptor.getValue();
+ assertQuietModeDialogIntent(intent);
+ }
+
+ private void assertQuietModeDialogIntent(Intent intent) {
assertThat(intent.getComponent().getPackageName())
.isEqualTo("android");
assertThat(intent.getComponent().getClassName())
.isEqualTo("com.android.internal.app.UnlaunchableAppActivity");
}
+ private void assertBlockedByAdminDialogIntent(Intent intent) {
+ assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ assertThat(
+ (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN))
+ .isEqualTo(COMPONENT_NAME);
+ }
+
private void assertSettingsPageLaunchRequested(boolean shouldContainExtras) {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).startActivity(intentCaptor.capture());
Intent intent = intentCaptor.getValue();
+ assertSettingsPageIntent(intent, shouldContainExtras);
+ }
+
+ private void assertSettingsPageIntent(Intent intent, boolean shouldContainExtras) {
assertThat(intent.getComponent().getPackageName())
.isEqualTo("com.android.settings");
assertThat(intent.getComponent().getClassName())
diff --git a/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java b/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java
new file mode 100644
index 0000000..a49b4a6
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/face/FaceUpdaterTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2022 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.biometrics.face;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.hardware.face.Face;
+import android.hardware.face.FaceEnrollCell;
+import android.hardware.face.FaceEnrollStages;
+import android.hardware.face.FaceManager;
+import android.os.CancellationSignal;
+import android.view.Surface;
+
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FaceUpdaterTest {
+
+ private static final byte[] HARDWARE_AUTH_TOKEN = new byte[] {0};
+ private static final CancellationSignal CANCELLATION_SIGNAL = new CancellationSignal();
+ private static final int USER_ID = 0;
+ private static final int ERR_MSG_ID = 0;
+ private static final int HELP_MSG_ID = 0;
+ private static final String HELP_STRING = "";
+ private static final String ERR_STRING = "";
+ private static final Face FACE =
+ new Face(/* name= */"", /* faceId */ 0, /* deviceId= */ 0L);
+ private static final int[] DISABLED_FEATURES = new int[] {0};
+ private static final boolean DEBUG_CONSENT = false;
+ private static final Surface PREVIEW_SURFACE = new Surface();
+ private static final int HELP_CODE = 0;
+ private static final CharSequence HELP_MESSAGE = "";
+ private static final FaceEnrollCell CELL =
+ new FaceEnrollCell(/* x= */ 0, /* y= */ 0, /* z= */ 0);
+ private static final int STAGE = FaceEnrollStages.UNKNOWN;
+ private static final float PAN = 0;
+ private static final float TILT = 0;
+ private static final float DISTANCE = 0;
+
+
+ @Mock private FaceManager mFaceManager;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
+ private FaceUpdater mFaceUpdater;
+ private Context mContext;
+ private FaceManager.EnrollmentCallback mEnrollmentCallback;
+ private FaceManager.RemovalCallback mRemovalCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+ mFaceUpdater = new FaceUpdater(mContext, mFaceManager);
+ mEnrollmentCallback = spy(new TestEnrollmentCallback());
+ mRemovalCallback = spy(new TestRemovalCallback());
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ }
+
+ @Test
+ public void enroll_firstVersion_onEnrollmentCallbacks_triggerGivenCallback() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ callback.onEnrollmentProgress(/* remaining= */ 2);
+ callback.onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+ callback.onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
+
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentProgress(/* remaining= */ 2);
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+ verify(mEnrollmentCallback, atLeast(1))
+ .onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
+ }
+
+ @Test
+ public void enroll_firstVersion_onEnrollmentSuccess_invokedInteractionWithSafetyCenter() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 0);
+
+ verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
+ }
+
+ @Test
+ public void enroll_firstVersion_onEnrollmentNotYetFinished_didntInvokeInteractionWithSafetyCenter() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 1);
+
+ verify(mSafetyCenterManagerWrapper, never()).isEnabled(any());
+ }
+
+ @Test
+ public void enroll_secondVersion_onEnrollmentCallbacks_triggerGivenCallback() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES, PREVIEW_SURFACE, DEBUG_CONSENT);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES),
+ same(PREVIEW_SURFACE),
+ eq(DEBUG_CONSENT));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ callback.onEnrollmentProgress(/* remaining= */ 2);
+ callback.onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+ callback.onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
+
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentProgress(/* remaining= */ 2);
+ verify(mEnrollmentCallback, atLeast(1)).onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+ verify(mEnrollmentCallback, atLeast(1))
+ .onEnrollmentFrame(HELP_CODE, HELP_MESSAGE, CELL, STAGE, PAN, TILT, DISTANCE);
+ }
+
+ @Test
+ public void enroll_secondVersion_onEnrollmentSuccess_invokedInteractionWithSafetyCenter() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES, PREVIEW_SURFACE, DEBUG_CONSENT);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES),
+ same(PREVIEW_SURFACE),
+ eq(DEBUG_CONSENT));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 0);
+
+ verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
+ }
+
+ @Test
+ public void enroll_secondVersion_onEnrollmentNotYetFinished_didntInvokeInteractionWithSafetyCenter() {
+ ArgumentCaptor<FaceManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.EnrollmentCallback.class);
+ mFaceUpdater.enroll(USER_ID, HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, mEnrollmentCallback,
+ DISABLED_FEATURES, PREVIEW_SURFACE, DEBUG_CONSENT);
+ verify(mFaceManager).enroll(
+ eq(USER_ID),
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ callbackCaptor.capture(),
+ same(DISABLED_FEATURES),
+ same(PREVIEW_SURFACE),
+ eq(DEBUG_CONSENT));
+ FaceManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 1);
+
+ verify(mSafetyCenterManagerWrapper, never()).isEnabled(any());
+ }
+
+ @Test
+ public void remove_onRemovalCallbacks_triggerGivenCallback() {
+ ArgumentCaptor<FaceManager.RemovalCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.RemovalCallback.class);
+ mFaceUpdater.remove(FACE, USER_ID, mRemovalCallback);
+ verify(mFaceManager)
+ .remove(same(FACE), eq(USER_ID), callbackCaptor.capture());
+ FaceManager.RemovalCallback callback = callbackCaptor.getValue();
+
+ callback.onRemovalSucceeded(FACE, /* remaining= */ 1);
+ callback.onRemovalError(FACE, ERR_MSG_ID, ERR_STRING);
+
+ verify(mRemovalCallback).onRemovalSucceeded(any(), eq(1));
+ verify(mRemovalCallback).onRemovalError(FACE, ERR_MSG_ID, ERR_STRING);
+ }
+
+ @Test
+ public void remove_onRemovalSuccess_invokedInteractionWithSafetyCenter() {
+ ArgumentCaptor<FaceManager.RemovalCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FaceManager.RemovalCallback.class);
+ mFaceUpdater.remove(FACE, USER_ID, mRemovalCallback);
+ verify(mFaceManager)
+ .remove(same(FACE), eq(USER_ID), callbackCaptor.capture());
+ FaceManager.RemovalCallback callback = callbackCaptor.getValue();
+
+ callback.onRemovalSucceeded(FACE, /* remaining= */ 0);
+
+ verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
+ }
+
+ public static class TestEnrollmentCallback extends FaceManager.EnrollmentCallback {
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {}
+
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {}
+
+ @Override
+ public void onEnrollmentProgress(int remaining) {}
+
+ @Override
+ public void onEnrollmentFrame(int helpCode, @Nullable CharSequence helpMessage,
+ @Nullable FaceEnrollCell cell, int stage, float pan, float tilt, float distance) {}
+ }
+
+ public static class TestRemovalCallback extends FaceManager.RemovalCallback {
+ @Override
+ public void onRemovalError(Face fp, int errMsgId, CharSequence errString) {}
+
+ @Override
+ public void onRemovalSucceeded(@Nullable Face fp, int remaining) {}
+ }
+}
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintUpdaterTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintUpdaterTest.java
new file mode 100644
index 0000000..62435b4
--- /dev/null
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintUpdaterTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 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.biometrics.fingerprint;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.CancellationSignal;
+
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FingerprintUpdaterTest {
+
+ private static final byte[] HARDWARE_AUTH_TOKEN = new byte[] {0};
+ private static final CancellationSignal CANCELLATION_SIGNAL = new CancellationSignal();
+ private static final int USER_ID = 0;
+ private static final int ENROLL_REASON = 0;
+ private static final int ERR_MSG_ID = 0;
+ private static final int HELP_MSG_ID = 0;
+ private static final String HELP_STRING = "";
+ private static final String ERR_STRING = "";
+ private static final Fingerprint FINGERPRINT =
+ new Fingerprint(/* name= */"", /* fingerId */ 0, /* deviceId= */ 0L);
+
+ @Mock private FingerprintManager mFingerprintManager;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
+ private FingerprintUpdater mFingerprintUpdater;
+ private Context mContext;
+ private FingerprintManager.EnrollmentCallback mEnrollmentCallback;
+ private FingerprintManager.RemovalCallback mRemovalCallback;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+ mFingerprintUpdater = new FingerprintUpdater(mContext, mFingerprintManager);
+ mEnrollmentCallback = spy(new TestEntrollmentCallback());
+ mRemovalCallback = spy(new TestRemovalCallback());
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ }
+
+ @Test
+ public void enroll_onEnrollmentCallbacks_triggerGivenCallback() {
+ ArgumentCaptor<FingerprintManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.EnrollmentCallback.class);
+ mFingerprintUpdater.enroll(HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, USER_ID,
+ mEnrollmentCallback, ENROLL_REASON);
+ verify(mFingerprintManager).enroll(
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ eq(USER_ID),
+ callbackCaptor.capture(),
+ eq(ENROLL_REASON));
+ FingerprintManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ callback.onEnrollmentProgress(/* remaining= */ 2);
+ callback.onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+
+ verify(mEnrollmentCallback).onEnrollmentError(ERR_MSG_ID, ERR_STRING);
+ verify(mEnrollmentCallback).onEnrollmentProgress(/* remaining= */ 2);
+ verify(mEnrollmentCallback).onEnrollmentHelp(HELP_MSG_ID, HELP_STRING);
+ }
+
+ @Test
+ public void enroll_onEnrollmentSuccess_invokedInteractionWithSafetyCenter() {
+ ArgumentCaptor<FingerprintManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.EnrollmentCallback.class);
+ mFingerprintUpdater.enroll(HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, USER_ID,
+ mEnrollmentCallback, ENROLL_REASON);
+ verify(mFingerprintManager).enroll(
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ eq(USER_ID),
+ callbackCaptor.capture(),
+ eq(ENROLL_REASON));
+ FingerprintManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 0);
+
+ verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
+ }
+
+ @Test
+ public void enroll_onEnrollmentNotYetFinished_didntInvokeInteractionWithSafetyCenter() {
+ ArgumentCaptor<FingerprintManager.EnrollmentCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.EnrollmentCallback.class);
+ mFingerprintUpdater.enroll(HARDWARE_AUTH_TOKEN, CANCELLATION_SIGNAL, USER_ID,
+ mEnrollmentCallback, ENROLL_REASON);
+ verify(mFingerprintManager).enroll(
+ same(HARDWARE_AUTH_TOKEN),
+ same(CANCELLATION_SIGNAL),
+ eq(USER_ID),
+ callbackCaptor.capture(),
+ eq(ENROLL_REASON));
+ FingerprintManager.EnrollmentCallback callback = callbackCaptor.getValue();
+
+ callback.onEnrollmentProgress(/* remaining= */ 1);
+
+ verify(mSafetyCenterManagerWrapper, never()).isEnabled(any());
+ }
+
+ @Test
+ public void remove_onRemovalCallbacks_triggerGivenCallback() {
+ ArgumentCaptor<FingerprintManager.RemovalCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.RemovalCallback.class);
+ mFingerprintUpdater.remove(FINGERPRINT, USER_ID, mRemovalCallback);
+ verify(mFingerprintManager)
+ .remove(same(FINGERPRINT), eq(USER_ID), callbackCaptor.capture());
+ FingerprintManager.RemovalCallback callback = callbackCaptor.getValue();
+
+ callback.onRemovalSucceeded(FINGERPRINT, /* remaining= */ 1);
+ callback.onRemovalError(FINGERPRINT, ERR_MSG_ID, ERR_STRING);
+
+ verify(mRemovalCallback).onRemovalSucceeded(any(), eq(1));
+ verify(mRemovalCallback).onRemovalError(FINGERPRINT, ERR_MSG_ID, ERR_STRING);
+ }
+
+ @Test
+ public void remove_onRemovalSuccess_invokedInteractionWithSafetyCenter() {
+ ArgumentCaptor<FingerprintManager.RemovalCallback> callbackCaptor =
+ ArgumentCaptor.forClass(FingerprintManager.RemovalCallback.class);
+ mFingerprintUpdater.remove(FINGERPRINT, USER_ID, mRemovalCallback);
+ verify(mFingerprintManager)
+ .remove(same(FINGERPRINT), eq(USER_ID), callbackCaptor.capture());
+ FingerprintManager.RemovalCallback callback = callbackCaptor.getValue();
+
+ callback.onRemovalSucceeded(FINGERPRINT, /* remaining= */ 0);
+
+ verify(mSafetyCenterManagerWrapper).isEnabled(mContext);
+ }
+
+ public static class TestEntrollmentCallback extends FingerprintManager.EnrollmentCallback {
+ @Override
+ public void onEnrollmentError(int errMsgId, CharSequence errString) {}
+
+ @Override
+ public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {}
+
+ @Override
+ public void onEnrollmentProgress(int remaining) {}
+ }
+
+ public static class TestRemovalCallback extends FingerprintManager.RemovalCallback {
+ @Override
+ public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {}
+
+ @Override
+ public void onRemovalSucceeded(@Nullable Fingerprint fp, int remaining) {}
+ }
+}
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index 2627d24..4a91e8f 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -16,35 +16,84 @@
package com.android.settings.safetycenter;
+import static android.provider.Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS;
+
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.Settings;
+import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintSettings;
+import com.android.settings.testutils.ResourcesUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class BiometricsSafetySourceTest {
+ private static final ComponentName COMPONENT_NAME =
+ new ComponentName("package", "class");
+ private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+
private Context mApplicationContext;
@Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ private FingerprintManager mFingerprintManager;
+ @Mock
+ private FaceManager mFaceManager;
+ @Mock
private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mApplicationContext = ApplicationProvider.getApplicationContext();
+ mApplicationContext = spy(ApplicationProvider.getApplicationContext());
+ when(mApplicationContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
+ when(mDevicePolicyManager.getProfileOwnerOrDeviceOwnerSupervisionComponent(USER_HANDLE))
+ .thenReturn(COMPONENT_NAME);
+ when(mApplicationContext.getSystemService(Context.FINGERPRINT_SERVICE))
+ .thenReturn(mFingerprintManager);
+ when(mApplicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
+ .thenReturn(mDevicePolicyManager);
+ when(mApplicationContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
}
@@ -63,12 +112,371 @@
}
@Test
- // TODO(b/215517420): Adapt this test when method is implemented.
- public void sendSafetyData_whenSafetyCenterIsEnabled_sendsNoData() {
- when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ public void sendSafetyData_whenSafetyCenterIsEnabled_withoutBiometrics_sendsNoData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
BiometricsSafetySource.sendSafetyData(mApplicationContext);
verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any());
}
+
+ @Test
+ public void sendSafetyData_withFingerprintNotEnrolled_whenDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceDisabledDataSentWithSingularSummary(
+ "security_settings_fingerprint_preference_title",
+ "security_settings_fingerprint_preference_summary_none");
+ }
+
+ @Test
+ public void sendSafetyData_withFingerprintNotEnrolled_whenNotDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_fingerprint_preference_title",
+ "security_settings_fingerprint_preference_summary_none",
+ FingerprintEnrollIntroduction.class.getName());
+ }
+
+ @Test
+ public void sendSafetyData_withFingerprintsEnrolled_whenDisabledByAdmin_sendsData() {
+ final int enrolledFingerprintsCount = 2;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceDisabledDataSentWithPluralSummary(
+ "security_settings_fingerprint_preference_title",
+ "security_settings_fingerprint_preference_summary",
+ enrolledFingerprintsCount);
+ }
+
+ @Test
+ public void sendSafetyData_withFingerprintsEnrolled_whenNotDisabledByAdmin_sendsData() {
+ final int enrolledFingerprintsCount = 2;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithPluralSummary(
+ "security_settings_fingerprint_preference_title",
+ "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+ FingerprintSettings.class.getName());
+ }
+
+ @Test
+ public void sendSafetyData_withFaceNotEnrolled_whenDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceDisabledDataSentWithSingularSummary(
+ "security_settings_face_preference_title",
+ "security_settings_face_preference_summary_none");
+ }
+
+ @Test
+ public void sendSafetyData_withFaceNotEnrolled_whenNotDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_face_preference_title",
+ "security_settings_face_preference_summary_none",
+ FaceEnrollIntroduction.class.getName());
+ }
+
+ @Test
+ public void sendSafetyData_withFaceEnrolled_whenDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceDisabledDataSentWithSingularSummary(
+ "security_settings_face_preference_title",
+ "security_settings_face_preference_summary");
+ }
+
+ @Test
+ public void sendSafetyData_withFaceEnrolled_whenNotDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_face_preference_title",
+ "security_settings_face_preference_summary",
+ Settings.FaceSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenBothNotDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_none_enrolled",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenFaceDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_none_enrolled",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenFingerprintDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_none_enrolled",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenBothDisabledByAdmin_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE
+ | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceDisabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_none_enrolled");
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withMpFingers_sendsData() {
+ final int enrolledFingerprintsCount = 2;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+ createFingerprintList(enrolledFingerprintsCount));
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_both_fp_multiple",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withOneFinger_sendsData() {
+ final int enrolledFingerprintsCount = 1;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+ createFingerprintList(enrolledFingerprintsCount));
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_biometric_preference_summary_both_fp_single",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenFaceEnrolled_withNoFingers_sendsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+ Collections.emptyList());
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithSingularSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_face_preference_summary",
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ @Test
+ public void sandSafetyData_withFaceAndFingerprint_whenNoFaceEnrolled_withFingers_sendsData() {
+ final int enrolledFingerprintsCount = 1;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt())).thenReturn(
+ createFingerprintList(enrolledFingerprintsCount));
+
+ BiometricsSafetySource.sendSafetyData(mApplicationContext);
+
+ assertSafetySourceEnabledDataSentWithPluralSummary(
+ "security_settings_biometric_preference_title",
+ "security_settings_fingerprint_preference_summary", enrolledFingerprintsCount,
+ Settings.CombinedBiometricSettingsActivity.class.getName());
+ }
+
+ private void assertSafetySourceDisabledDataSentWithSingularSummary(String expectedTitleResName,
+ String expectedSummaryResName) {
+ assertSafetySourceDisabledDataSent(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName)
+ );
+ }
+
+ private void assertSafetySourceEnabledDataSentWithSingularSummary(String expectedTitleResName,
+ String expectedSummaryResName,
+ String expectedSettingsClassName) {
+ assertSafetySourceEnabledDataSent(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName),
+ expectedSettingsClassName
+ );
+ }
+
+ private void assertSafetySourceDisabledDataSentWithPluralSummary(String expectedTitleResName,
+ String expectedSummaryResName, int expectedSummaryQuantity) {
+ final int stringResId = ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(), "plurals",
+ expectedSummaryResName);
+ assertSafetySourceDisabledDataSent(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ mApplicationContext.getResources().getQuantityString(stringResId,
+ expectedSummaryQuantity /* quantity */,
+ expectedSummaryQuantity /* formatArgs */)
+ );
+ }
+
+ private void assertSafetySourceEnabledDataSentWithPluralSummary(String expectedTitleResName,
+ String expectedSummaryResName, int expectedSummaryQuantity,
+ String expectedSettingsClassName) {
+ final int stringResId = ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(), "plurals",
+ expectedSummaryResName);
+ assertSafetySourceEnabledDataSent(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ mApplicationContext.getResources().getQuantityString(stringResId,
+ expectedSummaryQuantity /* quantity */,
+ expectedSummaryQuantity /* formatArgs */),
+ expectedSettingsClassName
+ );
+ }
+
+ private void assertSafetySourceDisabledDataSent(String expectedTitle, String expectedSummary) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isFalse();
+ final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ assertThat(clickIntent).isNotNull();
+ assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ }
+
+ private void assertSafetySourceEnabledDataSent(String expectedTitle, String expectedSummary,
+ String expectedSettingsClassName) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isTrue();
+ final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ assertThat(clickIntent).isNotNull();
+ assertThat(clickIntent.getComponent().getPackageName())
+ .isEqualTo("com.android.settings");
+ assertThat(clickIntent.getComponent().getClassName())
+ .isEqualTo(expectedSettingsClassName);
+ }
+
+
+ private List<Fingerprint> createFingerprintList(int size) {
+ final List<Fingerprint> fingerprintList = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ fingerprintList.add(new Fingerprint("fingerprint" + i, 0, 0));
+ }
+ return fingerprintList;
+ }
}
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index 64b9692..90a24aa 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -27,13 +27,16 @@
import android.content.Context;
import android.content.Intent;
import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceIssue;
import android.safetycenter.SafetySourceStatus;
import android.safetycenter.SafetySourceStatus.IconAction;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.widget.LockPatternUtils;
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.After;
@@ -59,11 +62,17 @@
@Mock
private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mApplicationContext = ApplicationProvider.getApplicationContext();
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+ when(featureFactory.securityFeatureProvider.getLockPatternUtils(mApplicationContext))
+ .thenReturn(mLockPatternUtils);
}
@After
@@ -72,8 +81,10 @@
}
@Test
- public void sendSafetyData_whenSafetyCenterIsDisabled_sendsNoData() {
+ public void sendSafetyData_whenScreenLockIsEnabled_whenSafetyCenterIsDisabled_sendsNoData() {
+ whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+ when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(true);
LockScreenSafetySource.sendSafetyData(mApplicationContext,
mScreenLockPreferenceDetailsUtils);
@@ -95,6 +106,7 @@
@Test
public void sendSafetyData_whenScreenLockIsEnabled_sendsData() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
LockScreenSafetySource.sendSafetyData(mApplicationContext,
mScreenLockPreferenceDetailsUtils);
@@ -119,6 +131,7 @@
@Test
public void sendSafetyData_whenLockPatternIsSecure_sendsStatusLevelOk() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(true);
LockScreenSafetySource.sendSafetyData(mApplicationContext,
@@ -136,6 +149,7 @@
@Test
public void sendSafetyData_whenLockPatternIsNotSecure_sendsStatusLevelRecommendation() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(false);
LockScreenSafetySource.sendSafetyData(mApplicationContext,
@@ -151,8 +165,62 @@
}
@Test
+ public void sendSafetyData_whenLockPatternIsSecure_sendsNoIssues() {
+ whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(true);
+
+ LockScreenSafetySource.sendSafetyData(mApplicationContext,
+ mScreenLockPreferenceDetailsUtils);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+ SafetySourceData safetySourceData = captor.getValue();
+
+ assertThat(safetySourceData.getIssues()).isEmpty();
+ }
+
+ @Test
+ public void sendSafetyData_whenLockPatternIsNotSecure_sendsIssue() {
+ whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(false);
+
+ LockScreenSafetySource.sendSafetyData(mApplicationContext,
+ mScreenLockPreferenceDetailsUtils);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), captor.capture());
+ SafetySourceData safetySourceData = captor.getValue();
+
+ assertThat(safetySourceData.getIssues()).hasSize(1);
+ SafetySourceIssue issue = safetySourceData.getIssues().get(0);
+ assertThat(issue.getId()).isEqualTo(LockScreenSafetySource.NO_SCREEN_LOCK_ISSUE_ID);
+ assertThat(issue.getTitle().toString()).isEqualTo(
+ ResourcesUtils.getResourcesString(mApplicationContext,
+ "no_screen_lock_issue_title"));
+ assertThat(issue.getSummary().toString()).isEqualTo(
+ ResourcesUtils.getResourcesString(mApplicationContext,
+ "no_screen_lock_issue_summary"));
+ assertThat(issue.getSeverityLevel()).isEqualTo(
+ SafetySourceStatus.STATUS_LEVEL_RECOMMENDATION);
+ assertThat(issue.getIssueTypeId()).isEqualTo(
+ LockScreenSafetySource.NO_SCREEN_LOCK_ISSUE_TYPE_ID);
+ assertThat(issue.getIssueCategory()).isEqualTo(SafetySourceIssue.ISSUE_CATEGORY_DEVICE);
+ assertThat(issue.getActions()).hasSize(1);
+ SafetySourceIssue.Action action = issue.getActions().get(0);
+ assertThat(action.getId()).isEqualTo(LockScreenSafetySource.SET_SCREEN_LOCK_ACTION_ID);
+ assertThat(action.getLabel().toString()).isEqualTo(
+ ResourcesUtils.getResourcesString(mApplicationContext,
+ "no_screen_lock_issue_action_label"));
+ assertThat(action.getPendingIntent().getIntent().getAction())
+ .isEqualTo(FAKE_ACTION_CHOOSE_LOCK_GENERIC_FRAGMENT);
+ }
+
+ @Test
public void sendSafetyData_whenPasswordQualityIsManaged_sendsDisabled() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(true);
@@ -170,6 +238,7 @@
@Test
public void sendSafetyData_whenPasswordQualityIsNotManaged_sendsEnabled() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
@@ -187,6 +256,7 @@
@Test
public void sendSafetyData_whenShouldShowGearMenu_sendsGearMenuActionIcon() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
final Intent launchScreenLockSettings = new Intent(FAKE_ACTION_SCREEN_LOCK_SETTINGS);
when(mScreenLockPreferenceDetailsUtils.getLaunchScreenLockSettingsIntent())
.thenReturn(launchScreenLockSettings);
@@ -208,6 +278,7 @@
@Test
public void sendSafetyData_whenShouldNotShowGearMenu_sendsNoGearMenuActionIcon() {
whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(false);
LockScreenSafetySource.sendSafetyData(mApplicationContext,
@@ -221,8 +292,27 @@
assertThat(safetySourceStatus.getIconAction()).isNull();
}
- private void whenScreenLockIsEnabled() {
+ @Test
+ public void onLockScreenChange_whenSafetyCenterEnabled_sendsData() {
+ whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+
+ LockScreenSafetySource.onLockScreenChange(mApplicationContext);
+
+ verify(mSafetyCenterManagerWrapper).sendSafetyCenterUpdate(any(), any());
+ }
+
+ @Test
+ public void onLockScreenChange_whenSafetyCenterDisabled_sendsNoData() {
+ whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+
+ LockScreenSafetySource.onLockScreenChange(mApplicationContext);
+
+ verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any());
+ }
+
+ private void whenScreenLockIsEnabled() {
when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.getSummary(anyInt())).thenReturn(SUMMARY);
diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
index f2a28ff..f042c22 100644
--- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
@@ -45,6 +45,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class SafetySourceBroadcastReceiverTest {
@@ -149,9 +151,12 @@
new String[]{ BiometricsSafetySource.SAFETY_SOURCE_ID });
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper, times(1))
+ .sendSafetyCenterUpdate(any(), captor.capture());
+ SafetySourceData safetySourceData = captor.getValue();
- // TODO(b/215517420): Update this test when BiometricSafetySource is implemented.
- verify(mSafetyCenterManagerWrapper, never()).sendSafetyCenterUpdate(any(), any());
+ assertThat(safetySourceData.getId()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
}
@Test
@@ -159,14 +164,15 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED);
- // TODO(b/215517420): Update this test when BiometricSafetySource is implemented to test
- // that biometrics data is also sent.
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
- verify(mSafetyCenterManagerWrapper, times(1))
+ verify(mSafetyCenterManagerWrapper, times(2))
.sendSafetyCenterUpdate(any(), captor.capture());
- SafetySourceData safetySourceData = captor.getValue();
+ List<SafetySourceData> safetySourceDataList = captor.getAllValues();
- assertThat(safetySourceData.getId()).isEqualTo(LockScreenSafetySource.SAFETY_SOURCE_ID);
+ assertThat(safetySourceDataList.stream().anyMatch(
+ data -> data.getId().equals(LockScreenSafetySource.SAFETY_SOURCE_ID))).isTrue();
+ assertThat(safetySourceDataList.stream().anyMatch(
+ data -> data.getId().equals(BiometricsSafetySource.SAFETY_SOURCE_ID))).isTrue();
}
}