Merge "Show ambient volume contrl only for hearing devices" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bce30dc..b178f0a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2830,6 +2830,12 @@
android:screenOrientation="portrait"/>
<activity android:name=".biometrics.face.FaceEnrollIntroduction"
+ android:exported="false"
+ android:theme="@style/GlifV4Theme.DayNight"
+ android:screenOrientation="nosensor">
+ </activity>
+
+ <activity android:name=".biometrics.face.FaceEnroll"
android:exported="true"
android:theme="@style/GlifV4Theme.DayNight"
android:screenOrientation="nosensor">
diff --git a/aconfig/accessibility/accessibility_flags.aconfig b/aconfig/accessibility/accessibility_flags.aconfig
index 4a741a1..268ae6a 100644
--- a/aconfig/accessibility/accessibility_flags.aconfig
+++ b/aconfig/accessibility/accessibility_flags.aconfig
@@ -59,6 +59,13 @@
}
flag {
+ name: "enable_magnification_focus_following_dialog"
+ namespace: "accessibility"
+ description: "Decides whether to show the magnification focus following dialog in Settings app."
+ bug: "388336111"
+}
+
+flag {
name: "fix_a11y_settings_search"
namespace: "accessibility"
description: "Fix the a11y related search items in Settings app"
diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig
index 835a637..bdd317e 100644
--- a/aconfig/settings_bluetooth_declarations.aconfig
+++ b/aconfig/settings_bluetooth_declarations.aconfig
@@ -26,16 +26,6 @@
}
flag {
- name: "disable_bonding_cancellation_for_orientation_change"
- namespace: "cross_device_experiences"
- description: "Stop cancelling bonding process when there is an orientation change"
- bug: "349542301"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "enable_bluetooth_key_missing_dialog"
namespace: "cross_device_experiences"
description: "Show a dialog if the bluetooth key is missing when reconnecting"
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index 6eb1e02..b57a69d 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -70,3 +70,13 @@
description: "Flag for catalyst service"
bug: "323791114"
}
+
+flag {
+ name: "utils_return_user_handle_for_current_user_id"
+ namespace: "profile_experiences"
+ description: "Don't ignore the current user id when checking for existing profiles."
+ bug: "378471943"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/res/drawable/ic_settings_trackpad.xml b/res/drawable/ic_settings_touchpad.xml
similarity index 100%
rename from res/drawable/ic_settings_trackpad.xml
rename to res/drawable/ic_settings_touchpad.xml
diff --git a/res/drawable/trackpad_bordered.xml b/res/drawable/touchpad_bordered.xml
similarity index 100%
rename from res/drawable/trackpad_bordered.xml
rename to res/drawable/touchpad_bordered.xml
diff --git a/res/drawable/trackpad_button_done_colored.xml b/res/drawable/touchpad_button_done_colored.xml
similarity index 100%
rename from res/drawable/trackpad_button_done_colored.xml
rename to res/drawable/touchpad_button_done_colored.xml
diff --git a/res/drawable/trackpad_gesture_dialog_bg.xml b/res/drawable/touchpad_gesture_dialog_bg.xml
similarity index 100%
rename from res/drawable/trackpad_gesture_dialog_bg.xml
rename to res/drawable/touchpad_gesture_dialog_bg.xml
diff --git a/res/layout/dialog_keyboard_a11y_input_setting_keys.xml b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
index dfa3c46..d826fee 100644
--- a/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
+++ b/res/layout/dialog_keyboard_a11y_input_setting_keys.xml
@@ -55,7 +55,7 @@
android:text="@string/input_setting_keys_dialog_option_200"
android:paddingStart="12dp"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="start|center_vertical"
android:background="@null"/>
<RadioButton
@@ -63,30 +63,30 @@
android:text="@string/input_setting_keys_dialog_option_400"
android:paddingStart="12dp"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="start|center_vertical"
- android:layout_marginTop="12dp"
+ android:layout_marginTop="6dp"
android:background="@null"/>
<RadioButton
android:id="@+id/input_setting_keys_value_600"
android:text="@string/input_setting_keys_dialog_option_600"
android:paddingStart="12dp"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="start|center_vertical"
- android:layout_marginTop="12dp"
+ android:layout_marginTop="6dp"
android:background="@null"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginVertical="12dp">
+ android:layout_marginVertical="6dp">
<RadioButton
android:id="@+id/input_setting_keys_value_custom"
android:paddingStart="12dp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:background="@null"/>
<LinearLayout
@@ -94,6 +94,7 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="48dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:paddingEnd="16dp">
@@ -123,8 +124,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
- android:visibility="gone"
- android:background="@null"/>
+ android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</RadioGroup>
diff --git a/res/layout/notif_importance_preference.xml b/res/layout/notif_importance_preference.xml
index b2a02d1..614856c 100644
--- a/res/layout/notif_importance_preference.xml
+++ b/res/layout/notif_importance_preference.xml
@@ -21,8 +21,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="16dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="@dimen/notification_importance_toggle_marginTop"
android:paddingBottom="@dimen/notification_importance_toggle_marginTop"
android:orientation="vertical">
diff --git a/res/layout/notif_priority_conversation_preference.xml b/res/layout/notif_priority_conversation_preference.xml
index 4601c00..326c52a 100644
--- a/res/layout/notif_priority_conversation_preference.xml
+++ b/res/layout/notif_priority_conversation_preference.xml
@@ -21,8 +21,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="16dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="@dimen/notification_importance_toggle_marginTop"
android:paddingBottom="@dimen/notification_importance_toggle_marginTop"
android:orientation="vertical">
diff --git a/res/layout/trackpad_gesture_preview.xml b/res/layout/touchpad_gesture_preview.xml
similarity index 93%
rename from res/layout/trackpad_gesture_preview.xml
rename to res/layout/touchpad_gesture_preview.xml
index 978da06..2fdd418 100644
--- a/res/layout/trackpad_gesture_preview.xml
+++ b/res/layout/touchpad_gesture_preview.xml
@@ -17,7 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:background="@drawable/trackpad_gesture_dialog_bg"
+ android:background="@drawable/touchpad_gesture_dialog_bg"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@@ -46,7 +46,7 @@
android:layout_alignParentStart="true"
android:paddingVertical="14dp"
android:drawablePadding="9dp"
- style="@style/TrackpadButtonCancel"
+ style="@style/TouchpadButtonCancel"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/gesture_button_skip"/>
@@ -60,7 +60,7 @@
android:layout_alignParentStart="true"
android:paddingVertical="14dp"
android:drawablePadding="9dp"
- style="@style/TrackpadButtonCancel"
+ style="@style/TouchpadButtonCancel"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/gesture_button_restart"/>
@@ -81,7 +81,7 @@
android:layout_alignParentEnd="true"
android:paddingVertical="14dp"
android:drawablePadding="9dp"
- style="@style/TrackpadButtonDone"
+ style="@style/TouchpadButtonDone"
android:textColor="@androidprv:color/materialColorOnPrimary"
android:text="@string/gesture_button_next"/>
@@ -95,7 +95,7 @@
android:layout_alignParentEnd="true"
android:paddingVertical="14dp"
android:drawablePadding="9dp"
- style="@style/TrackpadButtonDone"
+ style="@style/TouchpadButtonDone"
android:textColor="@androidprv:color/materialColorOnPrimary"
android:text="@string/gesture_button_done"/>
</RelativeLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2393982..9842843 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -809,6 +809,12 @@
<!-- Message shown in summary field when Face Unlock is not set up. [CHAR LIMIT=54] -->
<string name="security_settings_face_preference_summary_none">Setup needed</string>
<!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
+ <string name="security_settings_face_preference_title_new">Face</string>
+ <!-- Title shown for menu item that launches face settings or enrollment, for work profile. [CHAR LIMIT=50] -->
+ <string name="security_settings_face_profile_preference_title_new">Face for work</string>
+ <!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
+ <string name="private_space_face_unlock_title_new">Face for private space</string>
+ <!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
<string name="security_settings_face_preference_title">Face Unlock</string>
<!-- Title shown for menu item that launches face settings or enrollment, for work profile [CHAR LIMIT=50] -->
<string name="security_settings_face_profile_preference_title">Face Unlock for work</string>
@@ -938,6 +944,8 @@
<string name="security_settings_fingerprint_settings_preferences_category">When using Fingerprint Unlock</string>
<!-- Title shown for work menu item that launches fingerprint settings or enrollment [CHAR LIMIT=22] -->
<string name="security_settings_work_fingerprint_preference_title">Fingerprint for work</string>
+ <!-- Title shown for work menu item that launches fingerprint settings or enrollment [CHAR LIMIT=22] -->
+ <string name="security_settings_work_fingerprint_preference_title_new">Fingerprint for work</string>
<!-- Preference to check enrolled fingerprints -->
<string name="fingerprint_check_enrolled_title">Check enrolled fingerprints</string>
<!-- Preference to add another fingerprint -->
@@ -1381,6 +1389,8 @@
<string name="private_space_biometric_summary">Tap to set up</string>
<!-- Title for the Fingerprint unlock for private space preference. [CHAR LIMIT=60] -->
<string name="private_space_fingerprint_unlock_title">Fingerprint Unlock for private space</string>
+ <!-- Title for the Fingerprint unlock for private space preference. [CHAR LIMIT=60] -->
+ <string name="private_space_fingerprint_unlock_title_new">Fingerprint for private space</string>
<!-- Title for the Face unlock for private space preference. [CHAR LIMIT=60] -->
<string name="private_space_face_unlock_title">Face Unlock for private space</string>
<!-- Title for the Face and Fingerprint preference for private space. [CHAR LIMIT=60] -->
@@ -3170,6 +3180,10 @@
<string name="screensaver_settings_summary_dock">While docked</string>
<!-- Display settings screen, summary fragment for screen saver options, activated never [CHAR LIMIT=35] -->
<string name="screensaver_settings_summary_never">Never</string>
+ <!-- Summary for when screensaver is enabled, only while stationary and upright [CHAR LIMIT=35] -->
+ <string name="screensaver_settings_summary_postured">While postured</string>
+ <!-- Summary for when screensaver is enabled, only while stationary and upright and charging [CHAR LIMIT=35] -->
+ <string name="screensaver_settings_summary_postured_and_charging">While postured and charging</string>
<!-- Display settings screen, summary for screen saver options, screen saver is turned on [CHAR LIMIT=50] -->
<string name="screensaver_settings_summary_on">
On / <xliff:g id="screen_saver" example="Art gallery">%1$s</xliff:g>
@@ -3943,6 +3957,16 @@
<string name="location_time_zone_detection_not_allowed">Location time zone detection changes are not allowed</string>
<!-- [CHAR LIMIT=NONE] Location settings screen, summary when location time zone detection is enabled. -->
<string name="location_time_zone_detection_auto_is_on">If your device location is available, it may be used to set your time zone</string>
+
+ <!-- Date&Time settings screen, title of the notification category [CHAR LIMIT=60] -->
+ <string name="time_notifications_title">Notifications</string>
+ <!-- Date&Time settings screen, title of the time zone change notification toggle [CHAR LIMIT=60] -->
+ <string name="time_zone_change_notifications_toggle_title">Time zone change</string>
+ <!-- Date&Time settings screen, summary of the time zone change notification toggle [CHAR_LIMIT=NONE] -->
+ <string name="time_zone_change_notifications_toggle_summary">Receive a notification when your time zone is automatically updated</string>
+ <!-- Search keywords for the time zone notification category / section in Date & Time settings. [CHAR_LIMIT=NONE] -->
+ <string name="keywords_time_notification_category">notification, time, zone, timezone</string>
+
<!-- Main settings screen, setting summary for the user to go into the About phone screen-->
<string name="about_settings_summary">View legal info, status, software version</string>
<!-- About phone settings screen, setting option name to go to dialog that shows legal info -->
@@ -4678,6 +4702,8 @@
<!-- TODO(b/383555305): finalize these strings and mark them translatable. -->
<!-- Title for the 'Mouse controlled scrolling' preference switch, which disables the mouse scrolling acceleration so that the scrolling speed becomes directly proportional to the speed at which the wheel is turned. [CHAR LIMIT=60]-->
<string name="mouse_scrolling_acceleration" translatable="false">Controlled scrolling</string>
+ <!-- Title for the 'Scrolling speed' slider seekbar, which controls how fast content scrolls when the user moves the scroll wheel. [CHAR LIMIT=60]-->
+ <string name="mouse_scrolling_speed" translatable="false">Scrolling speed</string>
<!-- Title for the 'Swap buttons' preference switch, which swaps the left and right buttons of connected mice so that right click will be the primary action button and left clicking will be the secondary action, for example showing the context menu. [CHAR LIMIT=60] -->
<string name="mouse_swap_primary_button">Swap primary mouse button</string>
<!-- Summary text for the 'Swap buttons' preference switch indicating to users that when this switch is enabled, their left click will behave as though it is the right click (secondary action) and that the right click will be the primary action. [CHAR LIMIT=NONE] -->
@@ -4702,7 +4728,7 @@
<string name="mouse_keys_release2_summary">Use the \“<xliff:g id="release_2_label" example="/">%s</xliff:g>\” key to click the secondary mouse button</string>
<!-- Title for the button to trigger the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=35] -->
- <string name="keyboard_shortcuts_helper">Keyboard shortcuts</string>
+ <string name="keyboard_shortcuts_helper">View keyboard shortcuts</string>
<!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
<string name="keyboard_shortcuts_helper_summary">Show list of shortcuts</string>
<!-- Title for the 'Work profile keyboards & tools' preference category inside Languages and inputs'. [CHAR LIMIT=50] -->
@@ -5078,6 +5104,12 @@
<string name="accessibility_tap_assistance_title">Timing controls</string>
<!-- Title for the accessibility system controls page. [CHAR LIMIT=50] -->
<string name="accessibility_system_controls_title">System controls</string>
+ <!-- Title for the accessibility feedback preference. [CHAR LIMIT=50] -->
+ <string name="accessibility_feedback_title">Feedback</string>
+ <!-- Summary for the accessibility feedback preference. [CHAR LIMIT=100] -->
+ <string name="accessibility_feedback_summary">Help improve by taking a survey</string>
+ <!-- Summary for the accessibility feedback preference is disabled. [CHAR LIMIT=100] -->
+ <string name="accessibility_feedback_disabled_summary">No surveys available</string>
<!-- Title for the accessibility preference category of services downloaded by the user. [CHAR LIMIT=50] -->
<string name="user_installed_services_category_title">Downloaded apps</string>
<!-- Title for the accessibility preference category of settings considered to be experimental, meaning they might be changed or removed in the future. [CHAR LIMIT=50] -->
@@ -5574,6 +5606,9 @@
<!-- Summary for the seekbar that adjust auto click cursor area size. [CHAR_LIMIT=NONE] -->
<!-- TODO(b/383901288): Update string to translatable once approved by UXW. -->
<string name="autoclick_cursor_area_size_summary" translatable="false">Adjust the autoclick ring indicator area size</string>
+ <!-- Title for the toggle button that turns on/off the autoclick setting of ignoring minor cursor movement. [CHAR_LIMIT=NONE] -->
+ <!-- TODO(b/388845718): Update string to translatable once approved by UXW. -->
+ <string name="autoclick_ignore_minor_cursor_movement_title" translatable="false">Ignore minor cursor movement</string>
<!-- Title for preference screen for configuring vibrations. [CHAR LIMIT=NONE] -->
<string name="accessibility_vibration_settings_title">Vibration & haptics</string>
<!-- Summary for preference screen for configuring vibrations. [CHAR LIMIT=NONE] -->
@@ -8983,9 +9018,12 @@
<!-- [CHAR LIMIT=100] Title for switch that says whether this app can appear in the conversation notification section-->
<string name="conversation_section_switch_title">Conversation section</string>
- <!-- [CHAR LIMIT=100] Summary for switch that says whether this app can appear in the conversation notification section-->
+ <!-- [CHAR LIMIT=100] Summary for switch that says whether this app can appear in the conversation notification section (old)-->
<string name="conversation_section_switch_summary">Allow app to use conversation section</string>
+ <!-- [CHAR LIMIT=100] Summary for switch that says whether this app can appear in the conversation notification section-->
+ <string name="conversation_section_switch_complete_summary">Allow app to use conversation section, although conversation features like prioritization and bubbles are not supported by this app.</string>
+
<!-- [CHAR LIMIT=NONE] Conversation preference summary, the parent channel this conversation was spawned from (separator) the parent channel group (e.g. an account name)-->
<string name="notification_conversation_summary" translatable="false">"<xliff:g id="parent_category_name">%1$s</xliff:g> • <xliff:g id="parent_category_group_name">%2$s</xliff:g>"</string>
@@ -9378,8 +9416,11 @@
<!-- [CHAR LIMIT=NONE] Text appearing when app does not send notifications -->
<string name="app_notifications_not_send_desc">This app does not send notifications</string>
+ <!-- [CHAR LIMIT=NONE] App notification settings: section header for app wide notif settings -->
+ <string name="app_notification_settings">App settings</string>
+
<!-- [CHAR LIMIT=NONE] App notification settings: channels title -->
- <string name="notification_channels">Categories</string>
+ <string name="notification_channels">Notification categories</string>
<!-- [CHAR LIMIT=NONE] App notification settings: non-grouped-channels title -->
<string name="notification_channels_other">Other</string>
@@ -11275,19 +11316,19 @@
<string name="double_tap_power_for_camera_summary">To quickly open camera, press the power button twice. Works from any screen.</string>
<!-- Title text for double tap power gesture [CHAR LIMIT=80]-->
- <string name="double_tap_power_title">Double tap power button</string>
+ <string name="double_tap_power_title">Double press power button</string>
<!-- Summary for double tap power settings [DO NOT TRANSLATE] -->
<string name="double_tap_power_summary" translatable="false"><xliff:g id="double_tap_power_on_off" example="On">%1$s</xliff:g> / <xliff:g id="double_tap_power_actions" example="Access Wallet">%2$s</xliff:g></string>
<!-- Switch label to enable/disable double tap power button gesture [CHAR LIMIT=60] -->
- <string name="double_tap_power_enabled">Use double tap</string>
+ <string name="double_tap_power_enabled">Use double press</string>
<!-- Category title for double tap power gesture [CHAR_LIMIT=80] -->
- <string name="double_tap_power_target_action_category">Double Tap Power Button</string>
+ <string name="double_tap_power_target_action_category">Double press power button to open</string>
<!-- Double Tap Power Gesture camera launch action title [CHAR_LIMIT=60] -->
- <string name="double_tap_power_camera_action_title">Open Camera</string>
+ <string name="double_tap_power_camera_action_title">Camera</string>
<!-- Setting summary to describe double tap power button will open camera. [CHAR LIMIT=NONE] -->
<string name="double_tap_power_camera_action_summary">Access Camera</string>
<!-- Double Tap Power Gesture wallet launch action title [CHAR_LIMIT=60] -->
- <string name="double_tap_power_wallet_action_title">Open Wallet</string>
+ <string name="double_tap_power_wallet_action_title">Wallet</string>
<!-- Setting summary to describe double tap power button will open wallet. [CHAR LIMIT=NONE] -->
<string name="double_tap_power_wallet_action_summary">Access Wallet</string>
@@ -12421,9 +12462,9 @@
<!-- Category name "About satellite messaging" [CHAR_LIMIT=NONE] -->
<string name="category_name_about_satellite_messaging">About <xliff:g id="subject" example="satellite messaging">%1$s</xliff:g></string>
<!-- Summary for category "About satellite messaging" [CHAR_LIMIT=NONE] -->
- <string name="title_about_satellite_setting">You can send and receive text messages by satellite as part of an eligible <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> account</string>
+ <string name="title_about_satellite_setting">You can send and receive text messages by satellite with an eligible <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> account</string>
<!-- Category title "Your mobile plan" [CHAR_LIMIT=NONE] -->
- <string name="category_title_your_satellite_plan">Your <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> plan</string>
+ <string name="category_title_your_satellite_plan">Your <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> account</string>
<!-- Title for category "Your mobile plan when satellite is included in plan" [CHAR_LIMIT=NONE] -->
<string name="title_have_satellite_plan">Messaging is included with your account</string>
<!-- Title for category "Your mobile plan when satellite is not included in plan" [CHAR_LIMIT=NONE] -->
@@ -12441,7 +12482,7 @@
<!-- Summary for satellite supported service [CHAR_LIMIT=NONE] -->
<string name="summary_supported_service">You can text anyone, including emergency services. Your phone will reconnect to a mobile network when available.</string>
<!-- learn more text - more about satellite messaging [CHAR_LIMIT=NONE] -->
- <string name="satellite_setting_summary_more_information"><xliff:g id="subject" example="satellite messaging">%1$s</xliff:g> may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> for details.</string>
+ <string name="satellite_setting_summary_more_information"><xliff:g id="subject" example="satellite messaging">%1$s</xliff:g> may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact <xliff:g id="carrier_name" example="T-Mobile">%2$s</xliff:g> for details.</string>
<!-- more about satellite messaging [CHAR_LIMIT=NONE] -->
<string name="more_about_satellite_messaging">More about <xliff:g id="subject" example="satellite messaging">%1$s</xliff:g></string>
<!-- Title for satellite warning dialog to avoid user using wifi/bluetooth/airplane mode [CHAR_LIMIT=NONE] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 2f4c1ef..29b4aa6 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -372,15 +372,15 @@
<item name="android:padding">4dp</item>
</style>
- <style name="TrackpadButtonDone" parent="@android:style/Widget.Material.Button">
- <item name="android:background">@drawable/trackpad_button_done_colored</item>
+ <style name="TouchpadButtonDone" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/touchpad_button_done_colored</item>
<item name="android:stateListAnimator">@null</item>
<item name="android:textSize">16sp</item>
<item name="android:padding">4dp</item>
</style>
- <style name="TrackpadButtonCancel" parent="@android:style/Widget.Material.Button">
- <item name="android:background">@drawable/trackpad_bordered</item>
+ <style name="TouchpadButtonCancel" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/touchpad_bordered</item>
<item name="android:stateListAnimator">@null</item>
<item name="android:textSize">16sp</item>
<item name="android:padding">4dp</item>
diff --git a/res/xml/accessibility_autoclick_settings.xml b/res/xml/accessibility_autoclick_settings.xml
index 72371f3..edcc29b 100644
--- a/res/xml/accessibility_autoclick_settings.xml
+++ b/res/xml/accessibility_autoclick_settings.xml
@@ -80,11 +80,15 @@
android:key="accessibility_control_autoclick_cursor_area_size"
android:title="@string/autoclick_cursor_area_size_title"
android:summary="@string/autoclick_cursor_area_size_summary"
- settings:seekBarIncrement="20"
android:selectable="false"
settings:searchable="false"
settings:controller="com.android.settings.accessibility.ToggleAutoclickCursorAreaSizeController"/>
+ <SwitchPreferenceCompat
+ android:key="accessibility_control_autoclick_ignore_minor_cursor_movement"
+ android:title="@string/autoclick_ignore_minor_cursor_movement_title"
+ settings:controller="com.android.settings.accessibility.ToggleAutoclickIgnoreMinorCursorMovementController"/>
+
<com.android.settings.accessibility.AccessibilityFooterPreference
android:key="accessibility_autoclick_footer"
android:title="@string/accessibility_autoclick_description"
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index 06d74f6..b91aea9 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -30,49 +30,21 @@
<Preference
android:key="block_desc" />
- <!-- Whether the app can show promoted notifications -->
- <PreferenceCategory
- android:title="@string/live_notifications"
- android:key="promoted_category"
- android:visibility="gone">
-
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="promoted_switch"
- android:title="@string/live_notifications_switch" />
-
- <Preference
- android:key="promoted_desc"
- android:summary="@string/live_notifications_desc"
- android:selectable="false"/>
-
- </PreferenceCategory>
-
<!-- Conversations added here -->
<PreferenceCategory
android:title="@string/conversations_category_title"
android:key="conversations"
- android:visibility="gone">
+ android:visibility="gone"
+ android:layout="@layout/empty_view" >
</PreferenceCategory>
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="invalid_conversation_switch"
- android:title="@string/conversation_section_switch_title" />
- <Preference
- android:key="invalid_conversation_info"/>
-
- <!--Bubbles -->
- <Preference
- android:key="bubble_pref_link"
- android:title="@string/notification_bubbles_title"
- android:icon="@drawable/ic_create_bubble"
- settings:controller="com.android.settings.notification.app.BubbleSummaryPreferenceController">
- </Preference>
<!-- Bundles added here -->
<PreferenceCategory
android:key="bundles"
android:title="@string/notification_bundles"
- android:visibility="gone" />
+ android:visibility="gone"
+ android:layout="@layout/empty_view" />
<!-- Channels/Channel groups added here -->
<PreferenceCategory
@@ -84,61 +56,78 @@
android:title="@string/no_recent_channels"
android:icon="@drawable/ic_expand"/>
+ <PreferenceCategory
+ android:key="pre_channels_fields"
+ android:layout="@layout/empty_view"
+ android:visibility="gone" >
<!-- Importance toggle -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="allow_sound"
- android:title="@string/allow_interruption"
- android:summary="@string/allow_interruption_summary"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="allow_sound"
+ android:title="@string/allow_interruption"
+ android:summary="@string/allow_interruption_summary" />
- <!-- Visibility Override -->
- <com.android.settings.RestrictedListPreference
- android:key="visibility_override"
- android:title="@string/app_notification_visibility_override_title"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <!-- Visibility Override -->
+ <com.android.settings.RestrictedListPreference
+ android:key="visibility_override"
+ android:title="@string/app_notification_visibility_override_title" />
- <!-- Bypass DND -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="bypass_dnd"
- android:title="@string/app_notification_override_dnd_title"
- android:summary="@string/app_notification_override_dnd_summary"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <!-- Bypass DND -->
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="bypass_dnd"
+ android:title="@string/app_notification_override_dnd_title"
+ android:summary="@string/app_notification_override_dnd_summary"/>
+ </PreferenceCategory>
- <!-- Allow full-screen intents -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="fsi_permission"
- android:title="@string/app_notification_fsi_permission_title"
- android:summary="@string/app_notification_fsi_permission_summary"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <PreferenceCategory
+ android:key="app_wide"
+ android:title="@string/app_notification_settings"
+ settings:isPreferenceVisible="false">
- <!-- Show badge -->
- <com.android.settingslib.RestrictedSwitchPreference
- android:key="badge"
- android:title="@string/notification_badge_title"
- android:icon="@drawable/ic_notification_dot"
- settings:useAdditionalSummary="true"
- settings:restrictedSwitchSummary="@string/enabled_by_admin"
- android:order="1001"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <!-- Whether the app can show promoted notifications -->
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="promoted_switch"
+ android:title="@string/live_notifications_switch"
+ android:summary="@string/live_notifications_desc" />
- <Preference
- android:key="app_link"
- android:icon="@drawable/ic_settings_24dp"
- android:title="@string/app_settings_link"
- android:order="1003"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="invalid_conversation_switch"
+ android:title="@string/conversation_section_switch_title" />
+ <Preference
+ android:key="invalid_conversation_info"/>
- <com.android.settingslib.widget.FooterPreference
- android:key="deleted"
- android:icon="@drawable/ic_trash_can"
- android:order="8000"
- settings:allowDividerAbove="true"
- settings:allowDividerBelow="false" />
+ <!--Bubbles -->
+ <Preference
+ android:key="bubble_pref_link"
+ android:title="@string/notification_bubbles_title"
+ android:icon="@drawable/ic_create_bubble"
+ settings:controller="com.android.settings.notification.app.BubbleSummaryPreferenceController">
+ </Preference>
+
+ <!-- Allow full-screen intents -->
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="fsi_permission"
+ android:title="@string/app_notification_fsi_permission_title"
+ android:summary="@string/app_notification_fsi_permission_summary"/>
+
+ <!-- Show badge -->
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="badge"
+ android:title="@string/notification_badge_title"
+ android:icon="@drawable/ic_notification_dot"
+ settings:useAdditionalSummary="true"
+ settings:restrictedSwitchSummary="@string/enabled_by_admin"
+ android:order="1001"/>
+
+ <Preference
+ android:key="app_link"
+ android:icon="@drawable/ic_settings_24dp"
+ android:title="@string/app_settings_link"
+ android:order="1003"/>
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="deleted"
+ android:icon="@drawable/ic_trash_can"
+ android:order="8000"/>
+ </PreferenceCategory>
</PreferenceScreen>
diff --git a/res/xml/channel_notification_settings.xml b/res/xml/channel_notification_settings.xml
index a3895e3..a8b536b 100644
--- a/res/xml/channel_notification_settings.xml
+++ b/res/xml/channel_notification_settings.xml
@@ -111,16 +111,18 @@
android:title="@string/app_notification_override_dnd_title"
android:summary="@string/app_notification_override_dnd_summary" />
- <Preference
- android:key="app_link"
- android:order="18"
- android:title="@string/app_settings_link"
- android:icon="@drawable/ic_settings_24dp"
- settings:allowDividerAbove="true"/>
-
<com.android.settingslib.widget.FooterPreference
android:key="block_desc"
- android:order="110"
- settings:allowDividerAbove="false"/>
+ android:order="110"/>
+
+ <PreferenceCategory
+ android:key="external"
+ android:order="18"
+ android:layout="@layout/settingslib_preference_category_no_title">
+ <Preference
+ android:key="app_link"
+ android:title="@string/app_settings_link"
+ android:icon="@drawable/ic_settings_24dp"/>
+ </PreferenceCategory>
</PreferenceScreen>
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index fe0fd7e..678b1e2 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -75,18 +75,33 @@
</PreferenceCategory>
+ <!-- An optional preference category for notifications. Only displayed up if enabled via flags and config. -->
+ <PreferenceCategory
+ android:key="time_notifications_category"
+ android:title="@string/time_notifications_title"
+ settings:controller="com.android.settings.datetime.NotificationsPreferenceCategoryController">
+
+ <SwitchPreferenceCompat
+ android:key="time_zone_change_notifications"
+ android:summary="@string/summary_placeholder"
+ android:title="@string/time_zone_change_notifications_toggle_title"
+ settings:keywords="@string/keywords_time_notification_category"
+ settings:controller="com.android.settings.datetime.TimeZoneNotificationsPreferenceController" />
+
+ </PreferenceCategory>
+
<!-- An optional preference category for feedback. Only displayed up if enabled via flags and config. -->
<PreferenceCategory
- android:key="time_feedback_preference_category"
- android:title="@string/time_feedback_category_title"
- settings:keywords="@string/keywords_time_feedback_category"
- settings:controller="com.android.settings.datetime.TimeFeedbackPreferenceCategoryController">
+ android:key="time_feedback_preference_category"
+ android:title="@string/time_feedback_category_title"
+ settings:controller="com.android.settings.datetime.TimeFeedbackPreferenceCategoryController"
+ settings:keywords="@string/keywords_time_feedback_category">
<Preference
- android:key="time_feedback"
- android:title="@string/time_feedback_title"
- settings:keywords="@string/keywords_time_feedback"
- settings:controller="com.android.settings.datetime.TimeFeedbackPreferenceController" />
+ android:key="time_feedback"
+ android:title="@string/time_feedback_title"
+ settings:controller="com.android.settings.datetime.TimeFeedbackPreferenceController"
+ settings:keywords="@string/keywords_time_feedback" />
</PreferenceCategory>
diff --git a/res/xml/modes_calls_settings.xml b/res/xml/modes_calls_settings.xml
index b564020..e3a6fca 100644
--- a/res/xml/modes_calls_settings.xml
+++ b/res/xml/modes_calls_settings.xml
@@ -32,9 +32,11 @@
android:layout_height="16dp"/>
<!-- Repeat callers -->
- <SwitchPreferenceCompat
- android:key="zen_mode_repeat_callers"
- android:title="@string/zen_mode_repeat_callers_title" />
+ <PreferenceCategory>
+ <SwitchPreferenceCompat
+ android:key="zen_mode_repeat_callers"
+ android:title="@string/zen_mode_repeat_callers_title" />
+ </PreferenceCategory>
<com.android.settingslib.widget.FooterPreference
android:key="info_footer"
diff --git a/res/xml/mouse_settings.xml b/res/xml/mouse_settings.xml
index a25d516..98a429f 100644
--- a/res/xml/mouse_settings.xml
+++ b/res/xml/mouse_settings.xml
@@ -44,11 +44,6 @@
android:summary="@string/mouse_pointer_acceleration_summary"
settings:controller="com.android.settings.inputmethod.MousePointerAccelerationPreferenceController" />
- <SwitchPreferenceCompat
- android:key="mouse_scrolling_acceleration"
- android:title="@string/mouse_scrolling_acceleration"
- settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
-
<com.android.settings.widget.SeekBarPreference
android:key="trackpad_pointer_speed"
android:title="@string/trackpad_pointer_speed"
@@ -64,4 +59,18 @@
android:title="@string/accessibility_pointer_and_touchpad_title"
android:summary="@string/accessibility_pointer_and_touchpad_summary"
settings:searchable="true"/>
+
+ <SwitchPreferenceCompat
+ android:key="mouse_scrolling_acceleration"
+ android:title="@string/mouse_scrolling_acceleration"
+ android:order="55"
+ settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
+
+ <com.android.settings.widget.SeekBarPreference
+ android:key="mouse_scrolling_speed"
+ android:title="@string/mouse_scrolling_speed"
+ android:order="60"
+ android:selectable="false"
+ settings:controller="com.android.settings.inputmethod.MouseScrollingSpeedPreferenceController"/>
+
</PreferenceScreen>
diff --git a/res/xml/physical_keyboard_settings.xml b/res/xml/physical_keyboard_settings.xml
index 5691405..b7538c8 100644
--- a/res/xml/physical_keyboard_settings.xml
+++ b/res/xml/physical_keyboard_settings.xml
@@ -24,8 +24,7 @@
android:title="@string/keyboard_options_category">
<Preference
android:key="keyboard_shortcuts_helper"
- android:title="@string/keyboard_shortcuts_helper"
- android:summary="@string/keyboard_shortcuts_helper_summary" />
+ android:title="@string/keyboard_shortcuts_helper"/>
<Preference
android:key="modifier_keys_settings"
diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml
index 32f0924..331549c 100644
--- a/res/xml/security_settings_fingerprint.xml
+++ b/res/xml/security_settings_fingerprint.xml
@@ -29,6 +29,14 @@
android:title="@string/fingerprint_add_title"
android:icon="@drawable/ic_add_24dp"/>
+ <com.android.settingslib.widget.ButtonPreference
+ android:key="key_fingerprint_add_expressive"
+ android:title="@string/add"
+ settings:buttonPreferenceSize="large"
+ settings:buttonPreferenceType="tonal"
+ android:visibility="gone"
+ android:icon="@drawable/ic_add_24dp"/>
+
<PreferenceCategory
android:key="security_settings_fingerprint_unlock_category"
android:title="@string/security_settings_fingerprint_settings_preferences_category"
diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml
index a9d7444..68752d9 100644
--- a/res/xml/system_dashboard_fragment.xml
+++ b/res/xml/system_dashboard_fragment.xml
@@ -50,7 +50,7 @@
android:key="trackpad_settings"
android:title="@string/trackpad_mouse_settings"
android:summary="@string/trackpad_settings_summary"
- android:icon="@drawable/ic_settings_trackpad"
+ android:icon="@drawable/ic_settings_touchpad"
android:order="-254"
android:fragment="com.android.settings.inputmethod.TouchpadAndMouseSettings"
settings:controller="com.android.settings.inputmethod.TouchpadAndMouseSettingsController"/>
@@ -59,7 +59,7 @@
android:key="touchpad_settings"
android:title="@string/trackpad_settings"
android:summary="@string/trackpad_settings_summary"
- android:icon="@drawable/ic_settings_trackpad"
+ android:icon="@drawable/ic_settings_touchpad"
android:order="-253"
android:fragment="com.android.settings.inputmethod.TouchpadSettingFragment"
settings:controller="com.android.settings.inputmethod.TouchpadSettingsController"/>
diff --git a/res/xml/touchpad_and_mouse_settings.xml b/res/xml/touchpad_and_mouse_settings.xml
index bc9f842..2fd48a9 100644
--- a/res/xml/touchpad_and_mouse_settings.xml
+++ b/res/xml/touchpad_and_mouse_settings.xml
@@ -20,31 +20,31 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/trackpad_mouse_settings">
<SwitchPreferenceCompat
- android:key="trackpad_tap_to_click"
+ android:key="touchpad_tap_to_click"
android:title="@string/trackpad_tap_to_click"
- settings:controller="com.android.settings.inputmethod.TrackpadTapToClickPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadTapToClickPreferenceController"
android:order="10"/>
<SwitchPreferenceCompat
- android:key="trackpad_reverse_scrolling"
+ android:key="touchpad_reverse_scrolling"
android:title="@string/trackpad_reverse_scrolling_title"
android:summary="@string/trackpad_reverse_scrolling_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadReverseScrollingPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadReverseScrollingPreferenceController"
android:order="20"/>
<SwitchPreferenceCompat
- android:key="trackpad_bottom_right_tap"
+ android:key="touchpad_bottom_right_tap"
android:title="@string/trackpad_bottom_right_tap_title"
android:summary="@string/trackpad_bottom_right_tap_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadBottomPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadRightClickZonePreferenceController"
android:order="30"
settings:keywords="@string/keywords_trackpad_bottom_right_tap"/>
<SwitchPreferenceCompat
- android:key="trackpad_tap_dragging"
+ android:key="touchpad_tap_dragging"
android:title="@string/trackpad_tap_dragging_title"
android:summary="@string/trackpad_tap_dragging_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadTapDraggingPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadTapDraggingPreferenceController"
android:order="35"/>
<Preference
@@ -55,11 +55,11 @@
android:order="37"/>
<com.android.settings.widget.SeekBarPreference
- android:key="trackpad_pointer_speed"
+ android:key="touchpad_pointer_speed"
android:title="@string/trackpad_pointer_speed"
android:order="40"
android:selectable="false"
- settings:controller="com.android.settings.inputmethod.TrackpadPointerSpeedPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadPointerSpeedPreferenceController"/>
<SwitchPreferenceCompat
android:key="mouse_reverse_vertical_scrolling"
@@ -75,12 +75,6 @@
settings:controller="com.android.settings.inputmethod.MouseSwapPrimaryButtonPreferenceController"
android:order="47"/>
- <SwitchPreferenceCompat
- android:key="mouse_scrolling_acceleration"
- android:title="@string/mouse_scrolling_acceleration"
- settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController"
- android:order="48"/>
-
<Preference
android:fragment="com.android.settings.inputmethod.PointerTouchpadFragment"
android:key="pointer_and_touchpad"
@@ -90,14 +84,27 @@
android:summary="@string/accessibility_pointer_and_touchpad_summary"
settings:searchable="true"/>
+ <SwitchPreferenceCompat
+ android:key="mouse_scrolling_acceleration"
+ android:title="@string/mouse_scrolling_acceleration"
+ settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController"
+ android:order="51"/>
+
+ <com.android.settings.widget.SeekBarPreference
+ android:key="mouse_scrolling_speed"
+ android:title="@string/mouse_scrolling_speed"
+ android:order="52"
+ android:selectable="false"
+ settings:controller="com.android.settings.inputmethod.MouseScrollingSpeedPreferenceController"/>
+
<com.android.settingslib.widget.ButtonPreference
- android:key="trackpad_touch_gesture"
+ android:key="touchpad_touch_gesture"
android:title="@string/trackpad_touch_gesture"
- settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadGesturesTutorialButtonPreferenceController"/>
<com.android.settingslib.widget.FooterPreference
- android:key="trackpad_gestures_disabled_footer"
+ android:key="touchpad_gestures_disabled_footer"
android:title="@string/trackpad_gestures_disabled_footer_text"
settings:searchable="false"
- settings:controller="com.android.settings.inputmethod.TrackpadGesturesDisabledFooterPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadGesturesDisabledFooterPreferenceController"/>
</PreferenceScreen>
diff --git a/res/xml/touchpad_settings.xml b/res/xml/touchpad_settings.xml
index d3b8157..7d4b4bf 100644
--- a/res/xml/touchpad_settings.xml
+++ b/res/xml/touchpad_settings.xml
@@ -20,31 +20,31 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/trackpad_settings">
<SwitchPreferenceCompat
- android:key="trackpad_tap_to_click"
+ android:key="touchpad_tap_to_click"
android:title="@string/trackpad_tap_to_click"
- settings:controller="com.android.settings.inputmethod.TrackpadTapToClickPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadTapToClickPreferenceController"
android:order="10"/>
<SwitchPreferenceCompat
- android:key="trackpad_reverse_scrolling"
+ android:key="touchpad_reverse_scrolling"
android:title="@string/trackpad_reverse_scrolling_title"
android:summary="@string/trackpad_reverse_scrolling_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadReverseScrollingPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadReverseScrollingPreferenceController"
android:order="20"/>
<SwitchPreferenceCompat
- android:key="trackpad_bottom_right_tap"
+ android:key="touchpad_bottom_right_tap"
android:title="@string/trackpad_bottom_right_tap_title"
android:summary="@string/trackpad_bottom_right_tap_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadBottomPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadRightClickZonePreferenceController"
android:order="30"
settings:keywords="@string/keywords_trackpad_bottom_right_tap"/>
<SwitchPreferenceCompat
- android:key="trackpad_tap_dragging"
+ android:key="touchpad_tap_dragging"
android:title="@string/trackpad_tap_dragging_title"
android:summary="@string/trackpad_tap_dragging_summary"
- settings:controller="com.android.settings.inputmethod.TrackpadTapDraggingPreferenceController"
+ settings:controller="com.android.settings.inputmethod.TouchpadTapDraggingPreferenceController"
android:order="35"/>
<Preference
@@ -55,11 +55,11 @@
android:order="37"/>
<com.android.settings.widget.SeekBarPreference
- android:key="trackpad_pointer_speed"
+ android:key="touchpad_pointer_speed"
android:title="@string/trackpad_pointer_speed"
android:order="40"
android:selectable="false"
- settings:controller="com.android.settings.inputmethod.TrackpadPointerSpeedPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadPointerSpeedPreferenceController"/>
<Preference
android:fragment="com.android.settings.inputmethod.PointerTouchpadFragment"
@@ -71,13 +71,13 @@
settings:searchable="true"/>
<com.android.settingslib.widget.ButtonPreference
- android:key="trackpad_touch_gesture"
+ android:key="touchpad_touch_gesture"
android:title="@string/trackpad_touch_gesture"
- settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadGesturesTutorialButtonPreferenceController"/>
<com.android.settingslib.widget.FooterPreference
android:key="trackpad_gestures_disabled_footer"
android:title="@string/trackpad_gestures_disabled_footer_text"
settings:searchable="false"
- settings:controller="com.android.settings.inputmethod.TrackpadGesturesDisabledFooterPreferenceController"/>
+ settings:controller="com.android.settings.inputmethod.TouchpadGesturesDisabledFooterPreferenceController"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index c8011ee..636ef1c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -424,7 +424,8 @@
final List<UserHandle> userProfiles = userManager.getUserProfiles();
String umUserType = getUmUserType(userType);
for (UserHandle profile : userProfiles) {
- if (profile.getIdentifier() == UserHandle.myUserId()) {
+ if (!com.android.settings.flags.Flags.utilsReturnUserHandleForCurrentUserId()
+ && profile.getIdentifier() == UserHandle.myUserId()) {
continue;
}
final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 6f0ef9e..c0341cc 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -148,9 +148,7 @@
private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
new ArrayMap<>();
- @VisibleForTesting
- final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
- new ArrayMap<>();
+ private final List<Preference> mServicePreferences = new ArrayList<>();
private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap =
new ArrayMap<>();
@@ -372,13 +370,10 @@
// Since services category is auto generated we have to do a pass
// to generate it since services can come and go and then based on
// the global accessibility state to decided whether it is enabled.
- final ArrayList<Preference> servicePreferences =
- new ArrayList<>(mServicePreferenceToPreferenceCategoryMap.keySet());
- for (int i = 0; i < servicePreferences.size(); i++) {
- Preference service = servicePreferences.get(i);
- PreferenceCategory category = mServicePreferenceToPreferenceCategoryMap.get(service);
- category.removePreference(service);
+ for (Preference service : mServicePreferences) {
+ service.getParent().removePreference(service);
}
+ mServicePreferences.clear();
initializePreBundledServicesMapFromArray(CATEGORY_SCREEN_READER,
R.array.config_preinstalled_screen_reader_services);
@@ -423,7 +418,7 @@
prefCategory = mPreBundledServiceComponentToCategoryMap.get(componentName);
}
prefCategory.addPreference(preference);
- mServicePreferenceToPreferenceCategoryMap.put(preference, prefCategory);
+ mServicePreferences.add(preference);
}
// Update the order of all the category according to the order defined in xml file.
diff --git a/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceController.java b/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceController.java
new file mode 100644
index 0000000..bfcd293
--- /dev/null
+++ b/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceController.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SurveyFeatureProvider;
+
+/**
+ * PreferenceController for magnification feedback preference. This controller manages the
+ * visibility and click behavior of the preference based on the availability of a user survey
+ * related to magnification.
+ */
+public class MagnificationFeedbackPreferenceController extends BasePreferenceController
+ implements DefaultLifecycleObserver {
+ private static final String TAG = "MagnificationFeedbackPreferenceController";
+ public static final String PREF_KEY = "magnification_feedback";
+ public static final String FEEDBACK_KEY = "A11yMagnificationUser";
+ private final DashboardFragment mParent;
+ private final @Nullable SurveyFeatureProvider mSurveyFeatureProvider;
+
+ public MagnificationFeedbackPreferenceController(@NonNull Context context,
+ @NonNull DashboardFragment parent, @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ mParent = parent;
+ mSurveyFeatureProvider =
+ FeatureFactory.getFeatureFactory().getSurveyFeatureProvider(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void updateState(@NonNull Preference preference) {
+ super.updateState(preference);
+ if (mSurveyFeatureProvider != null) {
+ mSurveyFeatureProvider.checkSurveyAvailable(
+ mParent.getViewLifecycleOwner(),
+ FEEDBACK_KEY,
+ enabled -> {
+ final String summary = mContext.getString(enabled
+ ? R.string.accessibility_feedback_summary
+ : R.string.accessibility_feedback_disabled_summary);
+ preference.setSummary(summary);
+ preference.setEnabled(enabled);
+ });
+ } else {
+ Log.w(TAG, "SurveyFeatureProvider is not ready");
+ }
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(@NonNull Preference preference) {
+ if (mSurveyFeatureProvider != null) {
+ mSurveyFeatureProvider.sendActivityIfAvailable(FEEDBACK_KEY);
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeController.java b/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeController.java
index 95016b5..835bd5a 100644
--- a/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeController.java
+++ b/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeController.java
@@ -17,6 +17,7 @@
package com.android.settings.accessibility;
import static android.content.Context.MODE_PRIVATE;
+import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_INCREMENT_SIZE;
import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_MAX;
import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_MIN;
@@ -35,6 +36,7 @@
import com.android.server.accessibility.Flags;
import com.android.settings.core.SliderPreferenceController;
+import com.android.settingslib.widget.SliderPreference;
/** Controller class that controls accessibility autoclick cursor area size settings. */
public class ToggleAutoclickCursorAreaSizeController extends SliderPreferenceController
@@ -44,6 +46,7 @@
private final ContentResolver mContentResolver;
private final SharedPreferences mSharedPreferences;
+ private SliderPreference mPreference;
public ToggleAutoclickCursorAreaSizeController(@NonNull Context context,
@NonNull String preferenceKey) {
@@ -70,6 +73,13 @@
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ if (mPreference != null) {
+ mPreference.setMin(getMin());
+ mPreference.setMax(getMax());
+ mPreference.setSliderIncrement(AUTOCLICK_CURSOR_AREA_INCREMENT_SIZE);
+ mPreference.setValue(getSliderPosition());
+ }
}
@Override
@@ -85,8 +95,9 @@
@Override
public boolean setSliderPosition(int position) {
- Settings.Secure.putInt(mContentResolver,
- Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, position);
+ int size = validateSize(position);
+ Settings.Secure.putInt(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE, size);
return true;
}
@@ -95,10 +106,7 @@
int size = Settings.Secure.getInt(mContentResolver,
Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT);
- // Make sure the size is between min and max allowed value.
- size = Math.min(size, AUTOCLICK_CURSOR_AREA_SIZE_MAX);
- size = Math.max(size, AUTOCLICK_CURSOR_AREA_SIZE_MIN);
- return size;
+ return validateSize(size);
}
@Override
@@ -110,4 +118,10 @@
public int getMin() {
return AUTOCLICK_CURSOR_AREA_SIZE_MIN;
}
+
+ private int validateSize(int size) {
+ size = Math.min(size, AUTOCLICK_CURSOR_AREA_SIZE_MAX);
+ size = Math.max(size, AUTOCLICK_CURSOR_AREA_SIZE_MIN);
+ return size;
+ }
}
diff --git a/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementController.java b/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementController.java
new file mode 100644
index 0000000..302e42a
--- /dev/null
+++ b/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.accessibility.Flags;
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class ToggleAutoclickIgnoreMinorCursorMovementController extends TogglePreferenceController {
+
+ private static final String TAG =
+ ToggleAutoclickIgnoreMinorCursorMovementController.class.getSimpleName();
+
+ public ToggleAutoclickIgnoreMinorCursorMovementController(
+ @NonNull Context context, @NonNull String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return Flags.enableAutoclickIndicator() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ // TODO(b/388845718): retrieve check status from settings.
+ return false;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ // TODO(b/388845718): Update settings.
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 73b31c3..fef83ae 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -196,20 +196,17 @@
@Override
protected void initSettingsPreference() {
- // If the device doesn't support window magnification feature, it should hide the
- // settings preference.
- if (!isWindowMagnificationSupported(getContext())) {
- return;
- }
-
final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY);
- // LINT.IfChange(preference_list)
- addMagnificationModeSetting(generalCategory);
- addFollowTypingSetting(generalCategory);
- addOneFingerPanningSetting(generalCategory);
- addAlwaysOnSetting(generalCategory);
- addJoystickSetting(generalCategory);
- // LINT.ThenChange(search_data)
+ if (isWindowMagnificationSupported(getContext())) {
+ // LINT.IfChange(preference_list)
+ addMagnificationModeSetting(generalCategory);
+ addFollowTypingSetting(generalCategory);
+ addOneFingerPanningSetting(generalCategory);
+ addAlwaysOnSetting(generalCategory);
+ addJoystickSetting(generalCategory);
+ // LINT.ThenChange(:search_data)
+ }
+ addFeedbackSetting(generalCategory);
}
@Override
@@ -346,6 +343,14 @@
return pref;
}
+ private static Preference createFeedbackPreference(Context context) {
+ final Preference pref = new Preference(context);
+ pref.setTitle(R.string.accessibility_feedback_title);
+ pref.setSummary(R.string.accessibility_feedback_summary);
+ pref.setKey(MagnificationFeedbackPreferenceController.PREF_KEY);
+ return pref;
+ }
+
private static boolean isJoystickSupported() {
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
@@ -371,6 +376,21 @@
addPreferenceController(joystickPreferenceController);
}
+ private void addFeedbackSetting(PreferenceCategory generalCategory) {
+ if (!Flags.enableLowVisionHats()) {
+ return;
+ }
+
+ final Preference feedbackPreference = createFeedbackPreference(getPrefContext());
+ generalCategory.addPreference(feedbackPreference);
+
+ final MagnificationFeedbackPreferenceController magnificationFeedbackPreferenceController =
+ new MagnificationFeedbackPreferenceController(getContext(), this,
+ MagnificationFeedbackPreferenceController.PREF_KEY);
+ magnificationFeedbackPreferenceController.displayPreference(getPreferenceScreen());
+ addPreferenceController(magnificationFeedbackPreferenceController);
+ }
+
@Override
public void showDialog(int dialogId) {
super.showDialog(dialogId);
@@ -773,7 +793,8 @@
createFollowTypingPreference(context),
createOneFingerPanningPreference(context),
createAlwaysOnPreference(context),
- createJoystickPreference(context)
+ createJoystickPreference(context),
+ createFeedbackPreference(context)
)
.forEach(pref ->
rawData.add(createPreferenceSearchData(context, pref)));
@@ -810,9 +831,14 @@
niks.add(MagnificationJoystickPreferenceController.PREF_KEY);
}
}
+
+ if (!Flags.enableLowVisionHats()) {
+ niks.add(MagnificationFeedbackPreferenceController.PREF_KEY);
+ }
+
return niks;
}
- // LINT.ThenChange(preference_list)
+ // LINT.ThenChange(:preference_list)
private SearchIndexableRaw createPreferenceSearchData(
Context context, Preference pref) {
diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
index 4f1eec2..a9a0516 100644
--- a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
+++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
/** Accessibility settings for vibration. */
// LINT.IfChange
@@ -62,6 +63,9 @@
callingUid: Int,
) = ReadWritePermit.ALLOW
+ override val sensitivityLevel: Int
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun onResume(context: PreferenceLifecycleContext) {
vibrator = context.getSystemService(Vibrator::class.java)
context
diff --git a/src/com/android/settings/accounts/OWNERS b/src/com/android/settings/accounts/OWNERS
new file mode 100644
index 0000000..8ddd950
--- /dev/null
+++ b/src/com/android/settings/accounts/OWNERS
@@ -0,0 +1,11 @@
+# Default reviewers for account settings.
+jcivelli@google.com
+aseemk@google.com
+dementyev@google.com
+
+# For CredMan related reviews.
+reemabajwa@google.com
+helenqin@google.com
+sgjerry@google.com
+jbabs@google.com
+leecam@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
index 809b32d..1ab86f9 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
@@ -38,7 +38,7 @@
import com.android.settings.Settings;
import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
-import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.face.FaceEnrollActivityClassProvider;
import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollActivityClassProvider;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
@@ -254,6 +254,11 @@
.buildSearchIntent(mContext, SettingsEnums.SETTINGS_HOMEPAGE);
addActivityFilter(activityFilters, searchIntent);
}
+ final FaceEnrollActivityClassProvider faceClassProvider = FeatureFactory
+ .getFeatureFactory()
+ .getFaceFeatureProvider()
+ .getEnrollActivityClassProvider();
+ addActivityFilter(activityFilters, faceClassProvider.getNext());
final FingerprintEnrollActivityClassProvider fpClassProvider = FeatureFactory
.getFeatureFactory()
.getFingerprintFeatureProvider()
@@ -263,7 +268,6 @@
addActivityFilter(activityFilters, fpClassProvider.getAddAnother());
addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
- addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
addActivityFilter(activityFilters, RemoteAuthActivity.class);
addActivityFilter(activityFilters, RemoteAuthActivityInternal.class);
addActivityFilter(activityFilters, ChooseLockPattern.class);
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index b91e0e5..594cf60 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -28,6 +28,7 @@
import androidx.window.embedding.SplitController;
import com.android.settings.R;
+import com.android.window.flags.Flags;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -48,7 +49,10 @@
* @see androidx.window.embedding.SplitController.SplitSupportStatus#SPLIT_UNAVAILABLE
*/
private static final boolean SHOULD_ENABLE_LARGE_SCREEN_OPTIMIZATION =
- SystemProperties.getBoolean("persist.settings.large_screen_opt.enabled", false);
+ SystemProperties.getBoolean("persist.settings.large_screen_opt.enabled", false)
+ || (Flags.activityEmbeddingSupportForConnectedDisplays()
+ && SystemProperties.getBoolean(
+ "persist.settings.large_screen_opt_for_dp.enabled", false));
private static final String TAG = "ActivityEmbeddingUtils";
diff --git a/src/com/android/settings/applications/AppStorageSizesController.java b/src/com/android/settings/applications/AppStorageSizesController.java
index 43734b2..7cf86f8 100644
--- a/src/com/android/settings/applications/AppStorageSizesController.java
+++ b/src/com/android/settings/applications/AppStorageSizesController.java
@@ -17,7 +17,6 @@
package com.android.settings.applications;
import android.content.Context;
-import android.text.format.Formatter;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -25,6 +24,7 @@
import com.android.internal.util.Preconditions;
import com.android.settingslib.applications.StorageStatsSource;
+import com.android.settingslib.spaprivileged.model.app.AppStorageRepositoryImpl;
/**
* Handles setting the sizes for the app info screen.
@@ -70,27 +70,28 @@
mCacheSize.setSummary(errorRes);
mTotalSize.setSummary(errorRes);
} else {
+ var appStorageRepository = new AppStorageRepositoryImpl(context);
long codeSize = mLastResult.getCodeBytes();
long dataSize =
mDataCleared ? 0 : mLastResult.getDataBytes() - mLastResult.getCacheBytes();
if (mLastCodeSize != codeSize) {
mLastCodeSize = codeSize;
- mAppSize.setSummary(getSizeStr(context, codeSize));
+ mAppSize.setSummary(appStorageRepository.formatSizeBytes(codeSize));
}
if (mLastDataSize != dataSize) {
mLastDataSize = dataSize;
- mDataSize.setSummary(getSizeStr(context, dataSize));
+ mDataSize.setSummary(appStorageRepository.formatSizeBytes(dataSize));
}
long cacheSize = (mDataCleared || mCachedCleared) ? 0 : mLastResult.getCacheBytes();
if (mLastCacheSize != cacheSize) {
mLastCacheSize = cacheSize;
- mCacheSize.setSummary(getSizeStr(context, cacheSize));
+ mCacheSize.setSummary(appStorageRepository.formatSizeBytes(cacheSize));
}
long totalSize = codeSize + dataSize + cacheSize;
if (mLastTotalSize != totalSize) {
mLastTotalSize = totalSize;
- mTotalSize.setSummary(getSizeStr(context, totalSize));
+ mTotalSize.setSummary(appStorageRepository.formatSizeBytes(totalSize));
}
}
}
@@ -129,10 +130,6 @@
return mLastResult;
}
- private String getSizeStr(Context context, long size) {
- return Formatter.formatFileSize(context, size);
- }
-
public static class Builder {
private Preference mTotalSize;
private Preference mAppSize;
diff --git a/src/com/android/settings/applications/RecentAppStatsMixin.java b/src/com/android/settings/applications/RecentAppStatsMixin.java
index 4e8f795..2a79a61 100644
--- a/src/com/android/settings/applications/RecentAppStatsMixin.java
+++ b/src/com/android/settings/applications/RecentAppStatsMixin.java
@@ -186,7 +186,8 @@
return false;
}
- if (AppUtils.isHiddenSystemModule(mContext, pkgName)) {
+ if (!android.content.pm.Flags.removeHiddenModuleUsage()
+ && AppUtils.isHiddenSystemModule(mContext, pkgName)) {
return false;
}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 432b711..a87fc0d 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -243,7 +243,7 @@
if (!ensurePackageInfoAvailable(activity)) {
return;
}
- if (!ensureDisplayableModule(activity)) {
+ if (!android.content.pm.Flags.removeHiddenModuleUsage() && !ensureDisplayableModule(activity)) {
return;
}
startListeningToPackageRemove();
@@ -386,6 +386,7 @@
* If it's not, the fragment will finish.
*
* @return true if package is displayable.
+ * TODO(b/382016780): to be removed after flag cleanup.
*/
@VisibleForTesting
boolean ensureDisplayableModule(Activity activity) {
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 1f7b3e5..5d1c478 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -71,7 +71,7 @@
private boolean mParentalConsentRequired;
private boolean mHasScrolledToBottom = false;
- @Nullable private PorterDuffColorFilter mIconColorFilter;
+ @Nullable protected PorterDuffColorFilter mIconColorFilter;
/**
* @return true if the biometric is disabled by a device administrator
diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java
index 2a457f5..e080ef4 100644
--- a/src/com/android/settings/biometrics/BiometricUtils.java
+++ b/src/com/android/settings/biometrics/BiometricUtils.java
@@ -43,7 +43,6 @@
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
-import com.android.settings.biometrics.face.FaceEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.FingerprintEnroll;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
@@ -281,7 +280,9 @@
*/
public static Intent getFaceIntroIntent(@NonNull Context context,
@NonNull Intent activityIntent) {
- final Intent intent = new Intent(context, FaceEnrollIntroduction.class);
+ final Intent intent = new Intent(context,
+ FeatureFactory.getFeatureFactory().getFaceFeatureProvider()
+ .getEnrollActivityClassProvider().getNext());
WizardManagerHelper.copyWizardManagerExtras(activityIntent, intent);
return intent;
}
diff --git a/src/com/android/settings/biometrics/face/FaceEnroll.kt b/src/com/android/settings/biometrics/face/FaceEnroll.kt
new file mode 100644
index 0000000..0a3dae5
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceEnroll.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import androidx.appcompat.app.AppCompatActivity
+
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+
+class FaceEnroll: AppCompatActivity() {
+
+ /**
+ * The class of the next activity to launch. This is open to allow subclasses to provide their
+ * own behavior. Defaults to the default activity class provided by the
+ * enrollActivityClassProvider.
+ */
+ private val nextActivityClass: Class<*>
+ get() = enrollActivityProvider.next
+
+ private val enrollActivityProvider: FaceEnrollActivityClassProvider
+ get() = featureFactory.faceFeatureProvider.enrollActivityClassProvider
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ /**
+ * Logs the next activity to be launched, creates an intent for that activity,
+ * adds flags to forward the result, includes any existing extras from the current intent,
+ * starts the new activity and then finishes the current one
+ */
+ Log.d("FaceEnroll", "forward to $nextActivityClass")
+ val nextIntent = Intent(this, nextActivityClass)
+ nextIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
+ nextIntent.putExtras(intent)
+ startActivity(nextIntent)
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollActivityClassProvider.kt b/src/com/android/settings/biometrics/face/FaceEnrollActivityClassProvider.kt
new file mode 100644
index 0000000..938b725
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceEnrollActivityClassProvider.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face
+
+import android.app.Activity
+
+open class FaceEnrollActivityClassProvider {
+ open val next: Class<out Activity>
+ get() = FaceEnrollIntroduction::class.java
+
+ companion object {
+ @JvmStatic
+ val instance = FaceEnrollActivityClassProvider()
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index d3f7519..946d9b3 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -625,7 +625,7 @@
updateDescriptionText();
}
- private boolean isPrivateProfile() {
+ protected boolean isPrivateProfile() {
return Utils.isPrivateProfile(mUserId, getApplicationContext());
}
}
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
index 51d3a3a..062d5df 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroductionInternal.java
@@ -16,13 +16,13 @@
package com.android.settings.biometrics.face;
-import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
-
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
+import com.android.settings.overlay.FeatureFactory;
+
/**
* Wrapper of {@link FaceEnrollIntroduction} to use with a pre-defined task affinity.
*
@@ -42,7 +42,9 @@
trampoline.setFlags(0);
// Trampoline to the intended activity, and finish
- trampoline.setClassName(SETTINGS_PACKAGE_NAME, FaceEnrollIntroduction.class.getName());
+ trampoline.setClass(getApplicationContext(),
+ FeatureFactory.getFeatureFactory().getFaceFeatureProvider()
+ .getEnrollActivityClassProvider().getNext());
startActivity(trampoline);
finish();
}
diff --git a/src/com/android/settings/biometrics/face/FaceFeatureProvider.java b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
index 1a4fd90..d38ce6d 100644
--- a/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
+++ b/src/com/android/settings/biometrics/face/FaceFeatureProvider.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/** Feature provider for face unlock */
@@ -32,4 +33,13 @@
/** Returns true if setup wizard supported face enrollment. */
boolean isSetupWizardSupported(Context context);
+
+ /**
+ * Gets the provider for current face enrollment activity classes
+ * @return the provider
+ */
+ @NonNull
+ default FaceEnrollActivityClassProvider getEnrollActivityClassProvider() {
+ return FaceEnrollActivityClassProvider.getInstance();
+ }
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
index 7413354..e7badde 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
@@ -16,8 +16,6 @@
package com.android.settings.biometrics.face;
-import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
-
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
@@ -28,6 +26,7 @@
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.widget.LayoutPreference;
@@ -83,7 +82,8 @@
public void onClick(View v) {
mIsClicked = true;
final Intent intent = new Intent();
- intent.setClassName(SETTINGS_PACKAGE_NAME, FaceEnrollIntroduction.class.getName());
+ intent.setClass(mContext, FeatureFactory.getFeatureFactory().getFaceFeatureProvider()
+ .getEnrollActivityClassProvider().getNext());
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
if (mListener != null) {
diff --git a/src/com/android/settings/biometrics/face/FaceStatusUtils.java b/src/com/android/settings/biometrics/face/FaceStatusUtils.java
index 5af0a8a..302d677 100644
--- a/src/com/android/settings/biometrics/face/FaceStatusUtils.java
+++ b/src/com/android/settings/biometrics/face/FaceStatusUtils.java
@@ -26,12 +26,11 @@
import com.android.settings.Settings;
import com.android.settings.Utils;
import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settings.flags.Flags;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
-/**
- * Utilities for face details shared between Security Settings and Safety Center.
- */
+/** Utilities for face details shared between Security Settings and Safety Center. */
public class FaceStatusUtils {
private final int mUserId;
@@ -44,9 +43,7 @@
mUserId = userId;
}
- /**
- * Returns whether the face settings entity should be shown.
- */
+ /** Returns whether the face settings entity should be shown. */
public boolean isAvailable() {
return !Utils.isMultipleBiometricsSupported(mContext) && Utils.hasFaceHardware(mContext);
}
@@ -61,55 +58,70 @@
mContext, BiometricAuthenticator.TYPE_FACE);
}
- /**
- * Returns the title of face settings entity.
- */
+ /** Returns the title of face settings entity. */
public String getTitle() {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return mContext.getString(
Utils.isPrivateProfile(mUserId, mContext)
- ? R.string.private_space_face_unlock_title
- : R.string.security_settings_face_profile_preference_title);
+ ? getPrivateSpaceTitle()
+ : getWorkProfileTitle());
} else {
- return mContext.getString(R.string.security_settings_face_preference_title);
+ return mContext.getString(getRegularTitle());
}
}
- /**
- * Returns the summary of face settings entity.
- */
+ private int getPrivateSpaceTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.private_space_face_unlock_title_new;
+ }
+ return R.string.private_space_face_unlock_title;
+ }
+
+ private int getWorkProfileTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.security_settings_face_profile_preference_title_new;
+ }
+ return R.string.security_settings_face_profile_preference_title;
+ }
+
+ private int getRegularTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.security_settings_face_preference_title_new;
+ }
+ return R.string.security_settings_face_preference_title;
+ }
+
+ /** Returns the summary of face settings entity. */
public String getSummary() {
if (shouldShowDisabledByAdminStr()) {
return mContext.getString(
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
} else {
- return mContext.getResources().getString(hasEnrolled()
- ? R.string.security_settings_face_preference_summary
- : R.string.security_settings_face_preference_summary_none);
+ return mContext.getResources()
+ .getString(
+ hasEnrolled()
+ ? R.string.security_settings_face_preference_summary
+ : R.string.security_settings_face_preference_summary_none);
}
}
- /**
- * Returns the class name of the Settings page corresponding to face settings.
- */
+ /** Returns the class name of the Settings page corresponding to face settings. */
public String getSettingsClassName() {
- return hasEnrolled() ? Settings.FaceSettingsInternalActivity.class.getName()
+ return hasEnrolled()
+ ? Settings.FaceSettingsInternalActivity.class.getName()
: FaceEnrollIntroductionInternal.class.getName();
}
- /**
- * Returns whether at least one face template has been enrolled.
- */
+ /** Returns whether at least one face template has been enrolled. */
public boolean hasEnrolled() {
return mFaceManager.hasEnrolledTemplates(mUserId);
}
- /**
- * Indicates if the face feature is enabled or disabled by the Device Admin.
- */
+ /** Indicates if the face feature is enabled or disabled by the Device Admin. */
private boolean shouldShowDisabledByAdminStr() {
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
- mContext, DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId) != null;
+ mContext, DevicePolicyManager.KEYGUARD_DISABLE_FACE, mUserId)
+ != null;
}
}
diff --git a/src/com/android/settings/biometrics/face/FaceUpdater.java b/src/com/android/settings/biometrics/face/FaceUpdater.java
index ddb6812..99d6f09 100644
--- a/src/com/android/settings/biometrics/face/FaceUpdater.java
+++ b/src/com/android/settings/biometrics/face/FaceUpdater.java
@@ -29,7 +29,9 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricUtils;
+import com.android.settings.flags.Flags;
import com.android.settings.safetycenter.BiometricsSafetySource;
+import com.android.settings.safetycenter.FaceSafetySource;
/**
* Responsible for making {@link FaceManager#enroll} and {@link FaceManager#remove} calls and thus
@@ -51,20 +53,43 @@
}
/** Wrapper around the {@link FaceManager#enroll} method. */
- public void enroll(int userId, byte[] hardwareAuthToken, CancellationSignal cancel,
- FaceManager.EnrollmentCallback callback, int[] disabledFeatures, Intent intent) {
- this.enroll(userId, hardwareAuthToken, cancel,
- new NotifyingEnrollmentCallback(mContext, callback), disabledFeatures,
- null, false, intent);
+ public void enroll(
+ int userId,
+ byte[] hardwareAuthToken,
+ CancellationSignal cancel,
+ FaceManager.EnrollmentCallback callback,
+ int[] disabledFeatures,
+ Intent intent) {
+ this.enroll(
+ userId,
+ hardwareAuthToken,
+ cancel,
+ new NotifyingEnrollmentCallback(mContext, callback),
+ disabledFeatures,
+ null,
+ false,
+ intent);
}
/** 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, Intent intent) {
- mFaceManager.enroll(userId, hardwareAuthToken, cancel,
- new NotifyingEnrollmentCallback(mContext, callback), disabledFeatures,
- previewSurface, debugConsent, toFaceEnrollOptions(intent));
+ public void enroll(
+ int userId,
+ byte[] hardwareAuthToken,
+ CancellationSignal cancel,
+ FaceManager.EnrollmentCallback callback,
+ int[] disabledFeatures,
+ @Nullable Surface previewSurface,
+ boolean debugConsent,
+ Intent intent) {
+ mFaceManager.enroll(
+ userId,
+ hardwareAuthToken,
+ cancel,
+ new NotifyingEnrollmentCallback(mContext, callback),
+ disabledFeatures,
+ previewSurface,
+ debugConsent,
+ toFaceEnrollOptions(intent));
}
/** Wrapper around the {@link FaceManager#remove} method. */
@@ -73,17 +98,15 @@
}
/**
- * Decorator of the {@link FaceManager.EnrollmentCallback} class that notifies other
- * interested parties that a face setting has changed.
+ * 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 static class NotifyingEnrollmentCallback extends FaceManager.EnrollmentCallback {
private final Context mContext;
private final FaceManager.EnrollmentCallback mCallback;
- NotifyingEnrollmentCallback(Context context,
- FaceManager.EnrollmentCallback callback) {
+ NotifyingEnrollmentCallback(Context context, FaceManager.EnrollmentCallback callback) {
mContext = context;
mCallback = callback;
}
@@ -99,8 +122,14 @@
}
@Override
- public void onEnrollmentFrame(int helpCode, @Nullable CharSequence helpMessage,
- @Nullable FaceEnrollCell cell, int stage, float pan, float tilt, float distance) {
+ 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);
}
@@ -108,14 +137,18 @@
public void onEnrollmentProgress(int remaining) {
mCallback.onEnrollmentProgress(remaining);
if (remaining == 0) {
- BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ if (Flags.biometricsOnboardingEducation()) {
+ FaceSafetySource.onBiometricsChanged(mContext);
+ } else {
+ BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ }
}
}
}
/**
- * Decorator of the {@link FaceManager.RemovalCallback} class that notifies other
- * interested parties that a face setting has 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 {
@@ -135,7 +168,11 @@
@Override
public void onRemovalSucceeded(@Nullable Face fp, int remaining) {
mCallback.onRemovalSucceeded(fp, remaining);
- BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ if (Flags.biometricsOnboardingEducation()) {
+ FaceSafetySource.onBiometricsChanged(mContext);
+ } else {
+ BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ }
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index 8d6f3cb..e50b0e5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -99,7 +99,9 @@
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.transition.SettingsTransitionHelper;
+import com.android.settingslib.widget.ButtonPreference;
import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.SettingsThemeHelper;
import com.android.settingslib.widget.TwoTargetPreference;
import com.google.android.setupdesign.util.DeviceHelper;
@@ -250,6 +252,8 @@
"key_fingerprint_check_enrolled";
@VisibleForTesting
static final String KEY_FINGERPRINT_ADD = "key_fingerprint_add";
+ @VisibleForTesting
+ static final String KEY_FINGERPRINT_ADD_EXPRESSIVE = "key_fingerprint_add_expressive";
private static final String KEY_FINGERPRINT_ENABLE_KEYGUARD_TOGGLE =
"fingerprint_enable_keyguard_toggle";
private static final String KEY_LAUNCHED_CONFIRM = "launched_confirm";
@@ -325,6 +329,8 @@
@Nullable
private UdfpsEnrollCalibrator mCalibrator;
+ private boolean mIsExpressiveThemeStyle;
+
FingerprintAuthenticateSidecar.Listener mAuthenticateListener =
new FingerprintAuthenticateSidecar.Listener() {
@Override
@@ -471,6 +477,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mIsExpressiveThemeStyle = SettingsThemeHelper.isExpressiveTheme(getPrefContext());
Activity activity = getActivity();
mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
@@ -679,7 +686,8 @@
mFingerprintsEnrolledCategory.removeAll();
}
- String keyToReturn = KEY_FINGERPRINT_ADD;
+ String keyToReturn = mIsExpressiveThemeStyle
+ ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD;
final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints(mUserId);
final int fingerprintCount = items.size();
for (int i = 0; i < fingerprintCount; i++) {
@@ -715,13 +723,30 @@
mFingerprintsEnrolledCategory.addPreference(pref);
pref.setOnPreferenceChangeListener(this);
}
- mAddFingerprintPreference = findPreference(KEY_FINGERPRINT_ADD);
+ mAddFingerprintPreference = findPreference(mIsExpressiveThemeStyle
+ ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD);
setupAddFingerprintPreference();
return keyToReturn;
}
private void setupAddFingerprintPreference() {
mAddFingerprintPreference.setOnPreferenceChangeListener(this);
+ if (mIsExpressiveThemeStyle
+ && (mAddFingerprintPreference instanceof ButtonPreference)) {
+ ((ButtonPreference) mAddFingerprintPreference).setOnClickListener(view -> {
+ mIsEnrolling = true;
+ Intent intent = new Intent();
+ intent.setClassName(SETTINGS_PACKAGE_NAME,
+ FingerprintEnroll.AddAdditionalFingerprint.class.getName());
+ intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
+ if (mCalibrator != null) {
+ intent.putExtras(mCalibrator.getExtrasForNextIntent());
+ }
+ startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
+ });
+ }
+
updateAddPreference();
}
@@ -803,12 +828,15 @@
return; // Activity went away
}
- mAddFingerprintPreference = findPreference(KEY_FINGERPRINT_ADD);
+ mAddFingerprintPreference = findPreference(
+ mIsExpressiveThemeStyle ? KEY_FINGERPRINT_ADD_EXPRESSIVE : KEY_FINGERPRINT_ADD);
if (mAddFingerprintPreference == null) {
return; // b/275519315 Skip if updateAddPreference() invoke before addPreference()
}
+ updateAddingButtonStyle();
+
/* Disable preference if too many fingerprints added */
final int max = getContext().getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
@@ -828,6 +856,20 @@
&& !tooMany && !removalInProgress && mToken != null);
}
+ private void updateAddingButtonStyle() {
+ final Preference nonExpressiveBtnPreference = findPreference(KEY_FINGERPRINT_ADD);
+ final ButtonPreference expressiveBtnPreference =
+ findPreference(KEY_FINGERPRINT_ADD_EXPRESSIVE);
+
+ if (nonExpressiveBtnPreference != null) {
+ nonExpressiveBtnPreference.setVisible(!mIsExpressiveThemeStyle);
+ }
+
+ if (expressiveBtnPreference != null) {
+ expressiveBtnPreference.setVisible(mIsExpressiveThemeStyle);
+ }
+ }
+
private void createFooterPreference(PreferenceGroup root) {
final Context context = getActivity();
if (context == null) {
@@ -925,11 +967,11 @@
@Override
public boolean onPreferenceTreeClick(Preference pref) {
final String key = pref.getKey();
- if (KEY_FINGERPRINT_ADD.equals(key)) {
+ if (!mIsExpressiveThemeStyle && KEY_FINGERPRINT_ADD.equals(key)) {
mIsEnrolling = true;
Intent intent = new Intent();
intent.setClassName(SETTINGS_PACKAGE_NAME,
- FingerprintEnroll.AddAdditionalFingerprint.class.getName());
+ FingerprintEnroll.AddAdditionalFingerprint.class.getName());
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
if (mCalibrator != null) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
index a7c9e9d..1ca564c 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
@@ -25,29 +25,26 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.biometrics.ParentalControlsUtils;
+import com.android.settings.flags.Flags;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.utils.StringUtil;
-/**
- * Utilities for fingerprint details shared between Security Settings and Safety Center.
- */
+/** Utilities for fingerprint details shared between Security Settings and Safety Center. */
public class FingerprintStatusUtils {
private final int mUserId;
private final Context mContext;
private final FingerprintManager mFingerprintManager;
- public FingerprintStatusUtils(Context context, FingerprintManager fingerprintManager,
- int userId) {
+ public FingerprintStatusUtils(
+ Context context, FingerprintManager fingerprintManager, int userId) {
mContext = context;
mFingerprintManager = fingerprintManager;
mUserId = userId;
}
- /**
- * Returns whether the fingerprint settings entity should be shown.
- */
+ /** Returns whether the fingerprint settings entity should be shown. */
public boolean isAvailable() {
return !Utils.isMultipleBiometricsSupported(mContext)
&& Utils.hasFingerprintHardware(mContext);
@@ -62,24 +59,42 @@
return ParentalControlsUtils.parentConsentRequired(
mContext, BiometricAuthenticator.TYPE_FINGERPRINT);
}
- /**
- * Returns the title of fingerprint settings entity.
- */
+
+ /** Returns the title of fingerprint settings entity. */
public String getTitle() {
UserManager userManager = mContext.getSystemService(UserManager.class);
if (userManager != null && userManager.isProfile()) {
return mContext.getString(
Utils.isPrivateProfile(mUserId, mContext)
- ? R.string.private_space_fingerprint_unlock_title
- : R.string.security_settings_work_fingerprint_preference_title);
+ ? getPrivateSpaceTitle()
+ : getWorkProfileTitle());
} else {
- return mContext.getString(R.string.security_settings_fingerprint_preference_title);
+ return mContext.getString(getRegularTitle());
}
}
- /**
- * Returns the summary of fingerprint settings entity.
- */
+ private int getPrivateSpaceTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.private_space_fingerprint_unlock_title_new;
+ }
+ return R.string.private_space_fingerprint_unlock_title;
+ }
+
+ private int getWorkProfileTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.security_settings_work_fingerprint_preference_title_new;
+ }
+ return R.string.security_settings_work_fingerprint_preference_title;
+ }
+
+ private int getRegularTitle() {
+ if (Flags.biometricsOnboardingEducation()) {
+ return R.string.security_settings_fingerprint; // doesn't have an overlay
+ }
+ return R.string.security_settings_fingerprint_preference_title;
+ }
+
+ /** Returns the summary of fingerprint settings entity. */
public String getSummary() {
if (shouldShowDisabledByAdminStr()) {
return mContext.getString(
@@ -87,7 +102,9 @@
}
if (hasEnrolled()) {
final int numEnrolled = mFingerprintManager.getEnrolledFingerprints(mUserId).size();
- return StringUtil.getIcuPluralsString(mContext, numEnrolled,
+ return StringUtil.getIcuPluralsString(
+ mContext,
+ numEnrolled,
R.string.security_settings_fingerprint_preference_summary);
} else {
return mContext.getString(
@@ -95,25 +112,20 @@
}
}
- /**
- * Returns the class name of the Settings page corresponding to fingerprint settings.
- */
+ /** Returns the class name of the Settings page corresponding to fingerprint settings. */
public String getSettingsClassName() {
return FingerprintSettings.class.getName();
}
- /**
- * Returns whether at least one fingerprint has been enrolled.
- */
+ /** Returns whether at least one fingerprint has been enrolled. */
public boolean hasEnrolled() {
return mFingerprintManager.hasEnrolledFingerprints(mUserId);
}
- /**
- * Indicates if the fingerprint feature should show the "Disabled by Admin" string.
- */
+ /** Indicates if the fingerprint feature should show the "Disabled by Admin" string. */
private boolean shouldShowDisabledByAdminStr() {
return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
- mContext, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId) != null;
+ mContext, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT, mUserId)
+ != null;
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java b/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java
index ea9abf1..84ee27e 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintUpdater.java
@@ -27,7 +27,9 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricUtils;
+import com.android.settings.flags.Flags;
import com.android.settings.safetycenter.BiometricsSafetySource;
+import com.android.settings.safetycenter.FingerprintSafetySource;
/**
* Responsible for making {@link FingerprintManager#enroll} and {@link FingerprintManager#remove}
@@ -49,11 +51,19 @@
}
/** Wrapper around the {@link FingerprintManager#enroll} method. */
- public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
+ public void enroll(
+ byte[] hardwareAuthToken,
+ CancellationSignal cancel,
+ int userId,
FingerprintManager.EnrollmentCallback callback,
- @FingerprintManager.EnrollReason int enrollReason, Intent intent) {
- mFingerprintManager.enroll(hardwareAuthToken, cancel, userId,
- new NotifyingEnrollmentCallback(mContext, callback), enrollReason,
+ @FingerprintManager.EnrollReason int enrollReason,
+ Intent intent) {
+ mFingerprintManager.enroll(
+ hardwareAuthToken,
+ cancel,
+ userId,
+ new NotifyingEnrollmentCallback(mContext, callback),
+ enrollReason,
toFingerprintEnrollOptions(intent));
}
@@ -66,14 +76,13 @@
* 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 static class NotifyingEnrollmentCallback extends FingerprintManager.EnrollmentCallback {
private final Context mContext;
private final FingerprintManager.EnrollmentCallback mCallback;
- NotifyingEnrollmentCallback(Context context,
- FingerprintManager.EnrollmentCallback callback) {
+ NotifyingEnrollmentCallback(
+ Context context, FingerprintManager.EnrollmentCallback callback) {
mContext = context;
mCallback = callback;
}
@@ -92,7 +101,11 @@
public void onEnrollmentProgress(int remaining) {
mCallback.onEnrollmentProgress(remaining);
if (remaining == 0) {
- BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ if (Flags.biometricsOnboardingEducation()) {
+ FingerprintSafetySource.onBiometricsChanged(mContext);
+ } else {
+ BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ }
}
}
@@ -139,7 +152,11 @@
@Override
public void onRemovalSucceeded(@Nullable Fingerprint fp, int remaining) {
mCallback.onRemovalSucceeded(fp, remaining);
- BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ if (Flags.biometricsOnboardingEducation()) {
+ FingerprintSafetySource.onBiometricsChanged(mContext);
+ } else {
+ BiometricsSafetySource.onBiometricsChanged(mContext); // biometrics data changed
+ }
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java
index 01f8bb4..64f6277 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceController.java
@@ -22,7 +22,6 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
-import com.android.settings.accessibility.Flags;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -107,10 +106,8 @@
mControllers.add(new BluetoothDetailsHearingDeviceSettingsController(mContext,
mFragment, mCachedDevice, mLifecycle));
}
- if (Flags.enableHearingAidPresetControl()) {
- mControllers.add(new BluetoothDetailsHearingAidsPresetsController(mContext, mFragment,
- mManager, mCachedDevice, mLifecycle));
- }
+ mControllers.add(new BluetoothDetailsHearingAidsPresetsController(mContext, mFragment,
+ mManager, mCachedDevice, mLifecycle));
if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) {
mControllers.add(new BluetoothDetailsAmbientVolumePreferenceController(mContext,
mManager, mFragment, mCachedDevice, mLifecycle));
diff --git a/src/com/android/settings/bluetooth/BluetoothKeyMissingDialog.java b/src/com/android/settings/bluetooth/BluetoothKeyMissingDialog.java
index 46975f7..fa43c24 100644
--- a/src/com/android/settings/bluetooth/BluetoothKeyMissingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothKeyMissingDialog.java
@@ -40,7 +40,8 @@
finish();
return;
}
- BluetoothKeyMissingDialogFragment fragment = new BluetoothKeyMissingDialogFragment(device);
+ BluetoothKeyMissingDialogFragment fragment =
+ BluetoothKeyMissingDialogFragment.newInstance(device);
fragment.show(getSupportFragmentManager(), FRAGMENT_TAG);
closeSystemDialogs();
}
diff --git a/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogFragment.java
index a8e3aae..342af34 100644
--- a/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogFragment.java
@@ -31,6 +31,7 @@
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
/**
* A dialogFragment used by {@link BluetoothKeyMissingDialog} to create a dialog for the
@@ -40,16 +41,26 @@
implements OnClickListener {
private static final String TAG = "BTKeyMissingDialogFragment";
+ private static final String KEY_CACHED_DEVICE_ADDRESS = "cached_device";
private BluetoothDevice mBluetoothDevice;
- public BluetoothKeyMissingDialogFragment(@NonNull BluetoothDevice bluetoothDevice) {
- mBluetoothDevice = bluetoothDevice;
+ /** Creates a new instant of the fragment. */
+ public static BluetoothKeyMissingDialogFragment newInstance(BluetoothDevice device) {
+ Bundle args = new Bundle(1);
+ args.putString(KEY_CACHED_DEVICE_ADDRESS, device.getAddress());
+ BluetoothKeyMissingDialogFragment fragment = new BluetoothKeyMissingDialogFragment();
+ fragment.setArguments(args);
+ return fragment;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ String deviceAddress = getArguments().getString(KEY_CACHED_DEVICE_ADDRESS);
+ LocalBluetoothManager manager = Utils.getLocalBtManager(getContext());
+ mBluetoothDevice = manager.getBluetoothAdapter().getRemoteDevice(deviceAddress);
+
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_key_missing, null);
TextView keyMissingTitle = view.findViewById(R.id.bluetooth_key_missing_title);
@@ -66,7 +77,7 @@
@Override
public void onDestroy() {
super.onDestroy();
- if (!getActivity().isFinishing()) {
+ if (!getActivity().isChangingConfigurations() && !getActivity().isFinishing()) {
getActivity().finish();
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
index c5b29f3..196219d 100644
--- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
@@ -117,6 +117,7 @@
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.dialog_edittext, null);
mDeviceNameView = (EditText) view.findViewById(R.id.edittext);
+ mDeviceNameView.setHint(R.string.bluetooth_device_name);
mDeviceNameView.setFilters(new InputFilter[] {
new BluetoothLengthDeviceNameFilter()
});
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index e6b197c..9d54b1d 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -41,7 +41,6 @@
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-import com.android.settings.flags.Flags;
/**
* A dialogFragment used by {@link BluetoothPairingDialog} to create an appropriately styled dialog
@@ -91,9 +90,7 @@
/* Cancel pairing unless 1) explicitly accepted by user 2) the event is triggered by
* orientation change. */
boolean shouldCancelPairing =
- Flags.disableBondingCancellationForOrientationChange()
- ? !mPositiveClicked && !getActivity().isChangingConfigurations()
- : !mPositiveClicked;
+ !mPositiveClicked && !getActivity().isChangingConfigurations();
if (mPairingController.getDialogType() != BluetoothPairingController.DISPLAY_PASSKEY_DIALOG
&& shouldCancelPairing) {
mPairingController.onCancel();
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index 2acabff..b7ec32e 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -214,7 +214,7 @@
}
}
- fragment.listView.post {
+ fragment.lifecycleScope.launch {
if (isLoading) {
fragment.setLoading(false, false)
isLoading = false
diff --git a/src/com/android/settings/connecteddevice/BluetoothPreference.kt b/src/com/android/settings/connecteddevice/BluetoothPreference.kt
index 4d4853e..8c12024 100644
--- a/src/com/android/settings/connecteddevice/BluetoothPreference.kt
+++ b/src/com/android/settings/connecteddevice/BluetoothPreference.kt
@@ -34,9 +34,9 @@
import com.android.settings.widget.MainSwitchBarMetadata
import com.android.settingslib.WirelessUtils
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel
@@ -152,7 +152,14 @@
broadcastReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- notifyChange(KEY, DataChangeReason.UPDATE)
+ val state =
+ intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
+ if (
+ state == BluetoothAdapter.STATE_ON ||
+ state == BluetoothAdapter.STATE_OFF
+ ) {
+ notifyChange(KEY, PreferenceChangeReason.STATE)
+ }
}
}
context.registerReceiver(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
index 719d6cb..3130a0c 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceController.java
@@ -52,6 +52,7 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
import com.google.common.collect.ImmutableList;
@@ -63,6 +64,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
/** PreferenceController to control the dialog to choose the active device for calls and alarms */
public class AudioSharingCallAudioPreferenceController extends AudioSharingBasePreferenceController
@@ -379,11 +381,21 @@
private void updateDeviceItemsInSharingSession() {
mGroupedConnectedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(mBtManager);
+ if (Flags.enableTemporaryBondDevicesUi()) {
+ mGroupedConnectedDevices =
+ mGroupedConnectedDevices.entrySet().stream()
+ .filter(entry -> !anyTemporaryBondDevice(entry.getValue()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ }
mDeviceItemsInSharingSession =
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ true);
}
+ private boolean anyTemporaryBondDevice(List<BluetoothDevice> connectedDevices) {
+ return connectedDevices.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice);
+ }
+
@Nullable
private Pair<Integer, AudioSharingDeviceItem> getActiveItemWithIndex() {
List<AudioSharingDeviceItem> deviceItems = new ArrayList<>(mDeviceItemsInSharingSession);
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedState.java
index dffb235..bdb62e8 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedState.java
@@ -18,9 +18,12 @@
import android.app.AlertDialog;
import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
@@ -109,6 +112,20 @@
controller.handleSourceAddRequest(preference, metadata);
})
.create();
+ EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+ .setEnabled(s.length() >= 4 && s.length() <= 16);
+ }
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+ @Override
+ public void afterTextChanged(Editable s) {}
+ });
alertDialog.show();
+ Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ positiveButton.setEnabled(false);
}
}
diff --git a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt
index 288035e..c4f0b29 100644
--- a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt
+++ b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt
@@ -45,7 +45,9 @@
import androidx.preference.PreferenceViewHolder
import java.util.Locale
+import java.util.function.Consumer
+import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -210,6 +212,8 @@
*/
private var mPaneNeedsRefresh = false
+ private val mTopologyListener = Consumer<DisplayTopology> { applyTopology(it) }
+
init {
layoutResource = R.layout.display_topology_preference
@@ -238,10 +242,17 @@
}
override fun onAttached() {
+ super.onAttached()
// We don't know if topology changes happened when we were detached, as it is impossible to
// listen at that time (we must remove listeners when detaching). Setting this flag makes
// the following onGlobalLayout call refresh the pane.
mPaneNeedsRefresh = true
+ injector.registerTopologyListener(mTopologyListener)
+ }
+
+ override fun onDetached() {
+ super.onDetached()
+ injector.unregisterTopologyListener(mTopologyListener)
}
override fun onGlobalLayout() {
@@ -265,6 +276,14 @@
open val wallpaper : Drawable
get() = WallpaperManager.getInstance(context).drawable ?: ColorDrawable(Color.BLACK)
+
+ open fun registerTopologyListener(listener: Consumer<DisplayTopology>) {
+ displayManager.registerTopologyListener(context.mainExecutor, listener)
+ }
+
+ open fun unregisterTopologyListener(listener: Consumer<DisplayTopology>) {
+ displayManager.unregisterTopologyListener(listener)
+ }
}
/**
@@ -294,12 +313,18 @@
private var mTopologyInfo : TopologyInfo? = null
private var mDrag : BlockDrag? = null
- @VisibleForTesting fun refreshPane() {
- val recycleableBlocks = ArrayDeque<DisplayBlock>()
- for (i in 0..mPaneContent.childCount-1) {
- recycleableBlocks.add(mPaneContent.getChildAt(i) as DisplayBlock)
- }
+ private fun sameDisplayPosition(a: RectF, b: RectF): Boolean {
+ // Comparing in display coordinates, so a 1 pixel difference will be less than one dp in
+ // pane coordinates. Canceling the drag and refreshing the pane will not change the apparent
+ // position of displays in the pane.
+ val EPSILON = 1f
+ return EPSILON > abs(a.left - b.left) &&
+ EPSILON > abs(a.right - b.right) &&
+ EPSILON > abs(a.top - b.top) &&
+ EPSILON > abs(a.bottom - b.bottom)
+ }
+ @VisibleForTesting fun refreshPane() {
val topology = injector.displayTopology
if (topology == null) {
// This occurs when no topology is active.
@@ -309,18 +334,39 @@
mTopologyInfo = null
return
}
+
+ applyTopology(topology)
+ }
+
+ @VisibleForTesting var mTimesReceivedSameTopology = 0
+
+ private fun applyTopology(topology: DisplayTopology) {
mTopologyHint.text = context.getString(R.string.external_display_topology_hint)
- val blocksPos = buildList {
+ val oldBounds = mTopologyInfo?.positions
+ val newBounds = buildList {
val bounds = topology.absoluteBounds
(0..bounds.size()-1).forEach {
add(Pair(bounds.keyAt(it), bounds.valueAt(it)))
}
}
+ if (oldBounds != null && oldBounds.size == newBounds.size &&
+ oldBounds.zip(newBounds).all { (old, new) ->
+ old.first == new.first && sameDisplayPosition(old.second, new.second)
+ }) {
+ mTimesReceivedSameTopology++
+ return
+ }
+
+ val recycleableBlocks = ArrayDeque<DisplayBlock>()
+ for (i in 0..mPaneContent.childCount-1) {
+ recycleableBlocks.add(mPaneContent.getChildAt(i) as DisplayBlock)
+ }
+
val scaling = TopologyScale(
mPaneContent.width, minEdgeLength = 60, maxBlockRatio = 0.12f,
- blocksPos.map { it.second }.toList())
+ newBounds.map { it.second }.toList())
mPaneHolder.layoutParams.let {
val newHeight = scaling.paneHeight.toInt()
if (it.height != newHeight) {
@@ -329,7 +375,7 @@
}
}
- blocksPos.forEach { (id, pos) ->
+ newBounds.forEach { (id, pos) ->
val block = recycleableBlocks.removeFirstOrNull() ?: DisplayBlock(context).apply {
// We need a separate wallpaper Drawable for each display block, since each needs to
// be drawn at a separate size.
@@ -348,9 +394,12 @@
}
}
}
- mPaneContent.removeViews(blocksPos.size, recycleableBlocks.size)
+ mPaneContent.removeViews(newBounds.size, recycleableBlocks.size)
- mTopologyInfo = TopologyInfo(topology, scaling, blocksPos)
+ mTopologyInfo = TopologyInfo(topology, scaling, newBounds)
+
+ // Cancel the drag if one is in progress.
+ mDrag = null
}
private fun onBlockTouchDown(
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index 3f91fb7..7acf95c 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -29,6 +29,7 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -119,7 +120,9 @@
*/
public static final int DISABLED_DEPENDENT_SETTING = 5;
+ @NonNull
protected final String mPreferenceKey;
+ @Nullable
protected UiBlockListener mUiBlockListener;
protected boolean mUiBlockerFinished;
private boolean mIsForWork;
@@ -194,7 +197,7 @@
}
}
- public BasePreferenceController(Context context, String preferenceKey) {
+ public BasePreferenceController(@NonNull Context context, @NonNull String preferenceKey) {
super(context);
mPreferenceKey = preferenceKey;
mPrefVisibility = true;
diff --git a/src/com/android/settings/core/SliderPreferenceController.java b/src/com/android/settings/core/SliderPreferenceController.java
index 8c936f2..9cd4697 100644
--- a/src/com/android/settings/core/SliderPreferenceController.java
+++ b/src/com/android/settings/core/SliderPreferenceController.java
@@ -16,6 +16,7 @@
import android.content.Context;
+import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.slice.builders.SliceAction;
@@ -24,7 +25,7 @@
public abstract class SliderPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener {
- public SliderPreferenceController(Context context, String preferenceKey) {
+ public SliderPreferenceController(@NonNull Context context, @NonNull String preferenceKey) {
super(context, preferenceKey);
}
diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java
index 459312a..8889f8d 100644
--- a/src/com/android/settings/core/TogglePreferenceController.java
+++ b/src/com/android/settings/core/TogglePreferenceController.java
@@ -15,13 +15,14 @@
import android.content.Context;
+import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
+import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SliceData;
-import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.widget.TwoStateButtonPreference;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.core.instrumentation.SettingsJankMonitor;
@@ -37,7 +38,7 @@
private static final String TAG = "TogglePrefController";
- public TogglePreferenceController(Context context, String preferenceKey) {
+ public TogglePreferenceController(@NonNull Context context, @NonNull String preferenceKey) {
super(context, preferenceKey);
}
diff --git a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
index a05bd87..e73fe94 100644
--- a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
+++ b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
@@ -21,9 +21,9 @@
import com.android.settings.R
import com.android.settings.widget.MainSwitchBarMetadata
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel
@@ -36,6 +36,9 @@
override val title
get() = R.string.data_saver_switch_title
+ override val disableWidgetOnCheckedChanged: Boolean
+ get() = false
+
override fun storage(context: Context) = createDataStore(context)
override fun getReadPermissions(context: Context) =
@@ -75,7 +78,7 @@
override fun onLastObserverRemoved() = dataSaverBackend.remListener(this)
override fun onDataSaverChanged(isDataSaving: Boolean) =
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.VALUE)
}
companion object {
diff --git a/src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java b/src/com/android/settings/datetime/DateTimeLaunchUtils.java
similarity index 85%
rename from src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java
rename to src/com/android/settings/datetime/DateTimeLaunchUtils.java
index 8a023cb..aef0ff2 100644
--- a/src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java
+++ b/src/com/android/settings/datetime/DateTimeLaunchUtils.java
@@ -22,7 +22,7 @@
import com.android.settings.flags.Flags;
/** A class to avoid duplication of launch-control logic for "time feedback" support. */
-final class TimeFeedbackLaunchUtils {
+final class DateTimeLaunchUtils {
/**
* A {@link DeviceConfig} flag that influences whether the settings entries related to help and
* feedback are supported on this device / for this user.
@@ -30,21 +30,21 @@
public static final String KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED =
"time_help_and_feedback_feature_supported";
- private TimeFeedbackLaunchUtils() {}
+ private DateTimeLaunchUtils() {}
static boolean isFeedbackFeatureSupported() {
// Support is determined according to:
// 1) A build-time flag to determine release feature availability.
// 2) A runtime / server-side flag to determine which devices / who gets to see the feature.
// This is launch control for limiting the feedback to droidfooding.
- return isFeatureSupportedThisRelease() && isFeatureSupportedOnThisDevice();
+ return isFeedbackFeatureSupportedThisRelease() && isFeedbackFeatureSupportedOnThisDevice();
}
- private static boolean isFeatureSupportedThisRelease() {
+ private static boolean isFeedbackFeatureSupportedThisRelease() {
return Flags.datetimeFeedback();
}
- private static boolean isFeatureSupportedOnThisDevice() {
+ private static boolean isFeedbackFeatureSupportedOnThisDevice() {
boolean defaultIsSupported = false;
return DeviceConfig.getBoolean(
NAMESPACE_SETTINGS_UI, KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, defaultIsSupported);
diff --git a/src/com/android/settings/datetime/DateTimeSettings.java b/src/com/android/settings/datetime/DateTimeSettings.java
index f3c11d4..f57adc8 100644
--- a/src/com/android/settings/datetime/DateTimeSettings.java
+++ b/src/com/android/settings/datetime/DateTimeSettings.java
@@ -74,6 +74,15 @@
use(TimeFeedbackPreferenceCategoryController.class);
use(TimeFeedbackPreferenceController.class)
.registerWithOptionalCategoryController(helpAndFeedbackCategoryController);
+
+ // All the elements in the category are optional, so we must ensure the category is only
+ // available if any of the elements are available.
+ NotificationsPreferenceCategoryController
+ notificationsPreferenceCategoryController =
+ use(NotificationsPreferenceCategoryController.class);
+ use(TimeZoneNotificationsPreferenceController.class)
+ .registerIn(
+ notificationsPreferenceCategoryController);
}
@Override
diff --git a/src/com/android/settings/datetime/NotificationsPreferenceCategoryController.java b/src/com/android/settings/datetime/NotificationsPreferenceCategoryController.java
new file mode 100644
index 0000000..02a2b9e
--- /dev/null
+++ b/src/com/android/settings/datetime/NotificationsPreferenceCategoryController.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.datetime;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.flags.Flags;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * A controller for the Settings category for "time notifications".
+ */
+public class NotificationsPreferenceCategoryController extends BasePreferenceController {
+
+ private final List<AbstractPreferenceController> mChildControllers = new ArrayList<>();
+
+ public NotificationsPreferenceCategoryController(@NonNull Context context,
+ @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ /**
+ * Adds a controller whose own availability can determine the category's availability status.
+ */
+ void addChildController(@NonNull AbstractPreferenceController childController) {
+ mChildControllers.add(Objects.requireNonNull(childController));
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // Firstly, hide the category if it is not enabled by flags.
+ if (!Flags.datetimeNotifications()) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+
+ // Secondly, only show the category if there's one or more controllers available within it.
+ for (AbstractPreferenceController childController : mChildControllers) {
+ if (childController.isAvailable()) {
+ return AVAILABLE;
+ }
+ }
+ return UNSUPPORTED_ON_DEVICE;
+ }
+}
diff --git a/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java b/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java
index 0b70af7..372eee8 100644
--- a/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java
+++ b/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java
@@ -62,6 +62,6 @@
}
protected boolean isTimeFeedbackFeatureEnabled() {
- return TimeFeedbackLaunchUtils.isFeedbackFeatureSupported();
+ return DateTimeLaunchUtils.isFeedbackFeatureSupported();
}
}
diff --git a/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
index 5abe4af..907c202 100644
--- a/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
+++ b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
@@ -67,7 +67,7 @@
@Override
public int getAvailabilityStatus() {
- if (!TimeFeedbackLaunchUtils.isFeedbackFeatureSupported()) {
+ if (!DateTimeLaunchUtils.isFeedbackFeatureSupported()) {
return UNSUPPORTED_ON_DEVICE;
}
return mAvailabilityStatus;
diff --git a/src/com/android/settings/datetime/TimeZoneNotificationsPreferenceController.java b/src/com/android/settings/datetime/TimeZoneNotificationsPreferenceController.java
new file mode 100644
index 0000000..105a376
--- /dev/null
+++ b/src/com/android/settings/datetime/TimeZoneNotificationsPreferenceController.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datetime;
+
+import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED;
+import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE;
+import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
+
+import android.app.time.TimeManager;
+import android.app.time.TimeZoneCapabilities;
+import android.app.time.TimeZoneCapabilitiesAndConfig;
+import android.app.time.TimeZoneConfiguration;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.concurrent.Executor;
+
+public final class TimeZoneNotificationsPreferenceController
+ extends TogglePreferenceController
+ implements LifecycleObserver, OnStart, OnStop, TimeManager.TimeZoneDetectorListener {
+
+ private static final String TAG = "TZNotificationsSettings";
+
+ private final TimeManager mTimeManager;
+ private @Nullable TimeZoneCapabilitiesAndConfig mTimeZoneCapabilitiesAndConfig;
+ private @Nullable Preference mPreference;
+
+ public TimeZoneNotificationsPreferenceController(@NonNull Context context,
+ @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ mTimeManager = context.getSystemService(TimeManager.class);
+ }
+
+ /**
+ * Registers this controller with a category controller so that the category can be optionally
+ * displayed, i.e. if all the child controllers are not available, the category heading won't be
+ * available.
+ */
+ public void registerIn(@NonNull NotificationsPreferenceCategoryController categoryController) {
+ categoryController.addChildController(this);
+ }
+
+ @Override
+ public boolean isChecked() {
+ if (!isAutoTimeZoneEnabled()) {
+ return false;
+ }
+
+ // forceRefresh set to true as the notifications toggle may have been turned off by
+ // switching off automatic time zone
+ TimeZoneCapabilitiesAndConfig capabilitiesAndConfig =
+ getTimeZoneCapabilitiesAndConfig(/* forceRefresh= */ true);
+ TimeZoneConfiguration configuration = capabilitiesAndConfig.getConfiguration();
+ return configuration.areNotificationsEnabled();
+ }
+
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
+ .setNotificationsEnabled(isChecked)
+ .build();
+ return mTimeManager.updateTimeZoneConfiguration(configuration);
+ }
+
+ @Override
+ public void displayPreference(@NonNull PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void onStart() {
+ // Register for updates to the user's time zone capabilities or configuration which could
+ // require UI changes.
+ Executor mainExecutor = mContext.getMainExecutor();
+ mTimeManager.addTimeZoneDetectorListener(mainExecutor, this);
+ // Setup the initial state.
+ refreshUi();
+ }
+
+ @Override
+ public void onStop() {
+ mTimeManager.removeTimeZoneDetectorListener(this);
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_system;
+ }
+
+ @Override
+ public void updateState(@NonNull Preference preference) {
+ super.updateState(preference);
+
+ // enable / disable the toggle based on automatic time zone being enabled or not
+ preference.setEnabled(isAutoTimeZoneEnabled());
+ }
+
+
+ @Override
+ public int getAvailabilityStatus() {
+ TimeZoneCapabilities timeZoneCapabilities =
+ getTimeZoneCapabilitiesAndConfig(/* forceRefresh= */ false).getCapabilities();
+ int capability = timeZoneCapabilities.getConfigureNotificationsEnabledCapability();
+
+ // The preference can be present and enabled, present and disabled or not present.
+ if (capability == CAPABILITY_NOT_SUPPORTED || capability == CAPABILITY_NOT_ALLOWED) {
+ return UNSUPPORTED_ON_DEVICE;
+ } else if (capability == CAPABILITY_NOT_APPLICABLE || capability == CAPABILITY_POSSESSED) {
+ return isAutoTimeZoneEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
+ } else {
+ Log.e(TAG, "Unknown capability=" + capability);
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ }
+
+ /**
+ * Implementation of {@link TimeManager.TimeZoneDetectorListener#onChange()}. Called by the
+ * system server after a change that affects {@link TimeZoneCapabilitiesAndConfig}.
+ */
+ @Override
+ public void onChange() {
+ refreshUi();
+ }
+
+ @Override
+ @NonNull
+ public CharSequence getSummary() {
+ return mContext.getString(R.string.time_zone_change_notifications_toggle_summary);
+ }
+
+ private void refreshUi() {
+ // Force a refresh of cached user capabilities and config.
+ getTimeZoneCapabilitiesAndConfig(/* forceRefresh= */ true);
+ refreshSummary(mPreference);
+ }
+
+ /**
+ * Returns the current user capabilities and configuration. {@code forceRefresh} can be {@code
+ * true} to discard any cached copy.
+ */
+ private TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig(boolean forceRefresh) {
+ if (forceRefresh || mTimeZoneCapabilitiesAndConfig == null) {
+ mTimeZoneCapabilitiesAndConfig = mTimeManager.getTimeZoneCapabilitiesAndConfig();
+ }
+ return mTimeZoneCapabilitiesAndConfig;
+ }
+
+ /**
+ * Returns whether the user can select this preference or not, as it is a sub toggle of
+ * automatic time zone.
+ */
+ private boolean isAutoTimeZoneEnabled() {
+ return mTimeManager.getTimeZoneCapabilitiesAndConfig().getConfiguration()
+ .isAutoDetectionEnabled();
+ }
+}
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
index 3bd9587..0835081 100644
--- a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
@@ -34,8 +34,6 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
-import java.util.Objects;
-
/** Preference controller for Linux terminal option in developers option */
public class LinuxTerminalPreferenceController extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin {
@@ -59,13 +57,15 @@
mTerminalPackageName =
isPackageInstalled(context.getPackageManager(), packageName) ? packageName : null;
- StorageManager storageManager =
- Objects.requireNonNull(context.getSystemService(StorageManager.class));
+ StorageManager storageManager = context.getSystemService(StorageManager.class);
VirtualMachineManager virtualMachineManager =
- Objects.requireNonNull(context.getSystemService(VirtualMachineManager.class));
+ context.getSystemService(VirtualMachineManager.class);
+
mIsDeviceCapable =
getTotalMemory() >= MEMORY_MIN_BYTES
+ && storageManager != null
&& storageManager.getPrimaryStorageSize() >= STORAGE_MIN_BYTES
+ && virtualMachineManager != null
&& ((virtualMachineManager.getCapabilities() & CAPABILITY_NON_PROTECTED_VM)
!= 0);
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index b5ee1d8..89f286c 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -100,11 +100,17 @@
@VisibleForTesting
static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
- private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
+ @VisibleForTesting
+ final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
+ SubscriptionInfo oldSubInfo = mSubscriptionInfo;
mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
+ if (getSubId(oldSubInfo) != getSubId(mSubscriptionInfo)) {
+ unregisterTelephonyCallback(oldSubInfo);
+ registerTelephonyCallback(mSubscriptionInfo);
+ }
updateSubscriptionStatus();
}
};
@@ -123,7 +129,6 @@
private final Context mContext;
private boolean mShowLatestAreaInfo;
- private boolean mIsRegisteredListener = false;
private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
@Override
@@ -137,7 +142,8 @@
};
@VisibleForTesting
- protected SimStatusDialogTelephonyCallback mTelephonyCallback;
+ protected final SimStatusDialogTelephonyCallback mTelephonyCallback =
+ new SimStatusDialogTelephonyCallback();
private CellBroadcastServiceConnection mCellBroadcastServiceConnection;
@@ -181,8 +187,6 @@
mContext = dialog.getContext();
mSlotIndex = slotId;
mSubscriptionInfo = getPhoneSubscriptionInfo(slotId);
-
- mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
mEuiccManager = mContext.getSystemService(EuiccManager.class);
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
@@ -201,11 +205,13 @@
public void initialize() {
if (mSubscriptionInfo == null) {
- return;
+ // Should not depend on default sub TelephonyManager, but lots of code already uses it
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ } else {
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
}
- mTelephonyManager =
- getTelephonyManager().createForSubscriptionId(mSubscriptionInfo.getSubscriptionId());
- mTelephonyCallback = new SimStatusDialogTelephonyCallback();
+
updateLatestAreaInfo();
updateSubscriptionStatus();
}
@@ -222,6 +228,10 @@
updateNetworkType();
updateRoamingStatus(serviceState);
updateIccidNumber();
+
+ if (mSubscriptionInfo == null) {
+ updateDataState(TelephonyManager.DATA_UNKNOWN);
+ }
}
/**
@@ -242,13 +252,9 @@
*/
@Override
public void onResume(@NonNull LifecycleOwner owner) {
- if (mSubscriptionInfo == null) {
- return;
- }
- mTelephonyManager = getTelephonyManager().createForSubscriptionId(
- mSubscriptionInfo.getSubscriptionId());
- getTelephonyManager()
- .registerTelephonyCallback(mContext.getMainExecutor(), mTelephonyCallback);
+ // get the latest sub info for it may be updated in onPause/onStop status.
+ mSubscriptionInfo = getPhoneSubscriptionInfo(mSlotIndex);
+ registerTelephonyCallback(mSubscriptionInfo);
mSubscriptionManager.addOnSubscriptionsChangedListener(
mContext.getMainExecutor(), mOnSubscriptionsChangedListener);
collectSimStatusDialogInfo(owner);
@@ -259,8 +265,6 @@
new IntentFilter(CellBroadcastIntents.ACTION_AREA_INFO_UPDATED),
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
}
-
- mIsRegisteredListener = true;
}
/**
@@ -268,22 +272,9 @@
*/
@Override
public void onPause(@NonNull LifecycleOwner owner) {
- if (mSubscriptionInfo == null) {
- if (mIsRegisteredListener) {
- mSubscriptionManager.removeOnSubscriptionsChangedListener(
- mOnSubscriptionsChangedListener);
- getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
- if (mShowLatestAreaInfo) {
- mContext.unregisterReceiver(mAreaInfoReceiver);
- }
- mIsRegisteredListener = false;
- }
- return;
- }
-
- mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
- getTelephonyManager().unregisterTelephonyCallback(mTelephonyCallback);
-
+ mSubscriptionManager.removeOnSubscriptionsChangedListener(
+ mOnSubscriptionsChangedListener);
+ unregisterTelephonyCallback(mSubscriptionInfo);
if (mShowLatestAreaInfo) {
mContext.unregisterReceiver(mAreaInfoReceiver);
}
@@ -555,6 +546,34 @@
return SubscriptionManager.from(mContext).getActiveSubscriptionInfoForSimSlotIndex(slotId);
}
+ private void registerTelephonyCallback(SubscriptionInfo subInfo) {
+ if (subInfo == null) {
+ return;
+ }
+
+ // No need to have a member to hold mTelephonyManager, leaving it as lots of code
+ // depending on it
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subInfo.getSubscriptionId());
+ mTelephonyManager.registerTelephonyCallback(
+ mContext.getMainExecutor(), mTelephonyCallback);
+ }
+
+ private void unregisterTelephonyCallback(SubscriptionInfo subInfo) {
+ if (subInfo == null) {
+ return;
+ }
+
+ mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subInfo.getSubscriptionId())
+ .unregisterTelephonyCallback(mTelephonyCallback);
+ }
+
+ private int getSubId(SubscriptionInfo subInfo) {
+ return subInfo == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
+ subInfo.getSubscriptionId();
+ }
+
@VisibleForTesting
class SimStatusDialogTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.DataConnectionStateListener,
diff --git a/src/com/android/settings/display/BrightnessLevelPreference.kt b/src/com/android/settings/display/BrightnessLevelPreference.kt
index f87edcb..e14db6b 100644
--- a/src/com/android/settings/display/BrightnessLevelPreference.kt
+++ b/src/com/android/settings/display/BrightnessLevelPreference.kt
@@ -33,7 +33,6 @@
import com.android.settings.core.SettingsBaseActivity
import com.android.settingslib.RestrictedPreference
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObserver
@@ -43,6 +42,7 @@
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN
import com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat
import com.android.settingslib.metadata.PersistentPreference
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.RangeValue
@@ -155,7 +155,7 @@
}
override fun onKeyChanged(key: String, reason: Int) {
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, reason)
}
override fun onDisplayAdded(displayId: Int) {}
@@ -163,7 +163,7 @@
override fun onDisplayRemoved(displayId: Int) {}
override fun onDisplayChanged(displayId: Int) {
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.STATE)
}
}
diff --git a/src/com/android/settings/display/darkmode/DarkModeStorage.kt b/src/com/android/settings/display/darkmode/DarkModeStorage.kt
index 9c53379..768a552 100644
--- a/src/com/android/settings/display/darkmode/DarkModeStorage.kt
+++ b/src/com/android/settings/display/darkmode/DarkModeStorage.kt
@@ -24,8 +24,8 @@
import android.content.res.Configuration
import android.os.PowerManager
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
+import com.android.settingslib.metadata.PreferenceChangeReason
/**
* Abstract storage for dark mode settings.
@@ -54,7 +54,7 @@
broadcastReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
- notifyChange(DataChangeReason.UPDATE)
+ notifyChange(PreferenceChangeReason.STATE)
}
}
context.registerReceiver(
@@ -63,7 +63,7 @@
)
darkModeObserver = DarkModeObserver(context)
- darkModeObserver.subscribe { notifyChange(DataChangeReason.UPDATE) }
+ darkModeObserver.subscribe { notifyChange(PreferenceChangeReason.VALUE) }
}
override fun onLastObserverRemoved() {
diff --git a/src/com/android/settings/dream/DreamSettings.java b/src/com/android/settings/dream/DreamSettings.java
index 4854fc6..c237061 100644
--- a/src/com/android/settings/dream/DreamSettings.java
+++ b/src/com/android/settings/dream/DreamSettings.java
@@ -17,10 +17,6 @@
package com.android.settings.dream;
import static com.android.settings.dream.DreamMainSwitchPreferenceController.MAIN_SWITCH_PREF_KEY;
-import static com.android.settingslib.dream.DreamBackend.EITHER;
-import static com.android.settingslib.dream.DreamBackend.NEVER;
-import static com.android.settingslib.dream.DreamBackend.WHILE_CHARGING;
-import static com.android.settingslib.dream.DreamBackend.WHILE_DOCKED;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -57,6 +53,7 @@
static final String WHILE_CHARGING_ONLY = "while_charging_only";
static final String WHILE_DOCKED_ONLY = "while_docked_only";
static final String EITHER_CHARGING_OR_DOCKED = "either_charging_or_docked";
+ static final String WHILE_POSTURED_ONLY = "while_postured_only";
static final String NEVER_DREAM = "never";
private MainSwitchPreference mMainSwitchPreference;
@@ -75,26 +72,30 @@
static int getSettingFromPrefKey(String key) {
switch (key) {
case WHILE_CHARGING_ONLY:
- return WHILE_CHARGING;
+ return DreamBackend.WHILE_CHARGING;
case WHILE_DOCKED_ONLY:
- return WHILE_DOCKED;
+ return DreamBackend.WHILE_DOCKED;
case EITHER_CHARGING_OR_DOCKED:
- return EITHER;
+ return DreamBackend.WHILE_CHARGING_OR_DOCKED;
+ case WHILE_POSTURED_ONLY:
+ return DreamBackend.WHILE_POSTURED;
case NEVER_DREAM:
default:
- return NEVER;
+ return DreamBackend.NEVER;
}
}
static String getKeyFromSetting(@WhenToDream int dreamSetting) {
switch (dreamSetting) {
- case WHILE_CHARGING:
+ case DreamBackend.WHILE_CHARGING:
return WHILE_CHARGING_ONLY;
- case WHILE_DOCKED:
+ case DreamBackend.WHILE_DOCKED:
return WHILE_DOCKED_ONLY;
- case EITHER:
+ case DreamBackend.WHILE_CHARGING_OR_DOCKED:
return EITHER_CHARGING_OR_DOCKED;
- case NEVER:
+ case DreamBackend.WHILE_POSTURED:
+ return WHILE_POSTURED_ONLY;
+ case DreamBackend.NEVER:
default:
return NEVER_DREAM;
}
@@ -103,14 +104,17 @@
static int getDreamSettingDescriptionResId(@WhenToDream int dreamSetting,
boolean enabledOnBattery) {
switch (dreamSetting) {
- case WHILE_CHARGING:
+ case DreamBackend.WHILE_CHARGING:
return R.string.screensaver_settings_summary_sleep;
- case WHILE_DOCKED:
+ case DreamBackend.WHILE_DOCKED:
return enabledOnBattery ? R.string.screensaver_settings_summary_dock
: R.string.screensaver_settings_summary_dock_and_charging;
- case EITHER:
+ case DreamBackend.WHILE_CHARGING_OR_DOCKED:
return R.string.screensaver_settings_summary_either_long;
- case NEVER:
+ case DreamBackend.WHILE_POSTURED:
+ return enabledOnBattery ? R.string.screensaver_settings_summary_postured
+ : R.string.screensaver_settings_summary_postured_and_charging;
+ case DreamBackend.NEVER:
default:
return R.string.screensaver_settings_summary_never;
}
diff --git a/src/com/android/settings/dream/WhenToDreamPicker.java b/src/com/android/settings/dream/WhenToDreamPicker.java
index 3052d20..b3b0c90 100644
--- a/src/com/android/settings/dream/WhenToDreamPicker.java
+++ b/src/com/android/settings/dream/WhenToDreamPicker.java
@@ -16,6 +16,8 @@
package com.android.settings.dream;
+import static android.service.dreams.Flags.allowDreamWhenPostured;
+
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -65,7 +67,11 @@
}
for (int i = 0; i < entries.length; i++) {
- candidates.add(new WhenToDreamCandidateInfo(entries[i], values[i]));
+ final String key = values[i];
+ if (DreamSettings.WHILE_POSTURED_ONLY.equals(key) && !allowDreamWhenPostured()) {
+ continue;
+ }
+ candidates.add(new WhenToDreamCandidateInfo(entries[i], key));
}
return candidates;
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt b/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
index 9029a85..f0a3ae6 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
@@ -32,6 +32,7 @@
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.preference.PreferenceBinding
import com.android.settingslib.widget.UsageProgressBarPreference
@@ -113,6 +114,9 @@
override fun getWritePermit(context: Context, value: Int?, callingPid: Int, callingUid: Int) =
ReadWritePermit.DISALLOW
+ override val sensitivityLevel: Int
+ get() = SensitivityLevel.NO_SENSITIVITY
+
companion object {
private const val KEY = "battery_header"
private const val BATTERY_MAX_LEVEL: Long = 100L
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 7cb5733..3ef5650 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -223,10 +223,16 @@
public boolean shouldHideUidBatteryConsumerUnconditionally(
UidBatteryConsumer consumer, String[] packages) {
final int uid = consumer.getUid();
+ if (android.content.pm.Flags.removeHiddenModuleUsage()) {
+ return uid == UID_TETHERING ? false : uid < 0;
+ }
return uid == UID_TETHERING ? false : uid < 0 || isHiddenSystemModule(packages);
}
- /** Returns true if one the specified packages belongs to a hidden system module. */
+ /**
+ * Returns true if one the specified packages belongs to a hidden system module.
+ * TODO(b/382016780): to be removed after flag cleanup.
+ */
public boolean isHiddenSystemModule(String[] packages) {
if (packages != null) {
for (int i = 0, length = packages.length; i < length; i++) {
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
index be3a3b8..3e5cee9 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
@@ -22,7 +22,6 @@
import com.android.settings.fuelgauge.BatterySaverReceiver
import com.android.settings.fuelgauge.BatterySaverReceiver.BatterySaverListener
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions
import com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_SETTINGS
@@ -30,6 +29,7 @@
import com.android.settingslib.fuelgauge.BatteryStatus
import com.android.settingslib.fuelgauge.BatteryUtils
import com.android.settingslib.metadata.MainSwitchPreference
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel
import kotlinx.coroutines.CoroutineScope
@@ -105,12 +105,12 @@
override fun onPowerSaveModeChanged() {
scope.launch {
delay(SWITCH_ANIMATION_DURATION)
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.VALUE)
}
}
override fun onBatteryChanged(pluggedIn: Boolean) =
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.STATE)
}
companion object {
diff --git a/src/com/android/settings/inputmethod/InputSettingPreferenceController.java b/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
index 9cc8d05..f18c9f4 100644
--- a/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
+++ b/src/com/android/settings/inputmethod/InputSettingPreferenceController.java
@@ -43,6 +43,7 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import java.text.NumberFormat;
import java.util.concurrent.TimeUnit;
/**
@@ -214,7 +215,7 @@
}
private static String progressToThresholdInSecond(int progress) {
- return String.valueOf((double) progress * CUSTOM_PROGRESS_INTERVAL
+ return NumberFormat.getInstance().format((float) progress * CUSTOM_PROGRESS_INTERVAL
/ MILLISECOND_IN_SECONDS);
}
diff --git a/src/com/android/settings/inputmethod/MouseKeysImageListAdapter.java b/src/com/android/settings/inputmethod/MouseKeysImageListAdapter.java
index 65024b1..9aab3a4 100644
--- a/src/com/android/settings/inputmethod/MouseKeysImageListAdapter.java
+++ b/src/com/android/settings/inputmethod/MouseKeysImageListAdapter.java
@@ -38,6 +38,7 @@
public class MouseKeysImageListAdapter extends
RecyclerView.Adapter<MouseKeysImageListAdapter.MouseKeyImageViewHolder> {
+ private static final String LABEL_DELIMITER = ", ";
private static final ImmutableList<Integer> DRAWABLE_LIST = ImmutableList.of(
R.drawable.mouse_keys_directional, R.drawable.mouse_keys_click,
R.drawable.mouse_keys_press_hold, R.drawable.mouse_keys_release,
@@ -93,7 +94,7 @@
List<String> directionalLabelList = DIRECTIONAL_CHAR_KEYCODE_LIST.stream().map(
(key) -> getDisplayLabel(currentInputDevice, key)).toList();
mComposedSummaryList.add(context.getString(R.string.mouse_keys_directional_summary,
- String.join(",", directionalLabelList)));
+ String.join(LABEL_DELIMITER, directionalLabelList)));
String leftClickLabel = getDisplayLabel(currentInputDevice, LEFT_CLICK_CHAR_KEYCODE);
mComposedSummaryList.add(
context.getString(R.string.mouse_keys_click_summary, leftClickLabel));
@@ -107,7 +108,8 @@
(key) -> getDisplayLabel(currentInputDevice, key)).toList();
mComposedSummaryList.add(context.getString(R.string.mouse_keys_toggle_scroll_summary,
toggleScrollLabelList.getFirst(),
- String.join(",", toggleScrollLabelList.subList(1, toggleScrollLabelList.size()))
+ String.join(LABEL_DELIMITER,
+ toggleScrollLabelList.subList(1, toggleScrollLabelList.size()))
));
String rightClickLabel = getDisplayLabel(currentInputDevice, RIGHT_CLICK_CHAR_KEYCODE);
mComposedSummaryList.add(
@@ -116,7 +118,8 @@
private String getDisplayLabel(InputDevice currentInputDevice, int keycode) {
return String.valueOf(currentInputDevice.getKeyCharacterMap().getDisplayLabel(
- currentInputDevice.getKeyCodeForKeyLocation(keycode))).toLowerCase(Locale.ROOT);
+ currentInputDevice.getKeyCodeForKeyLocation(keycode))).toLowerCase(
+ Locale.getDefault());
}
public static class MouseKeyImageViewHolder extends RecyclerView.ViewHolder {
diff --git a/src/com/android/settings/inputmethod/MouseScrollingSpeedPreferenceController.java b/src/com/android/settings/inputmethod/MouseScrollingSpeedPreferenceController.java
new file mode 100644
index 0000000..0a57085
--- /dev/null
+++ b/src/com/android/settings/inputmethod/MouseScrollingSpeedPreferenceController.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.SliderPreferenceController;
+import com.android.settings.widget.SeekBarPreference;
+
+public class MouseScrollingSpeedPreferenceController extends SliderPreferenceController {
+
+ public MouseScrollingSpeedPreferenceController(@NonNull Context context, @NonNull String key) {
+ super(context, key);
+ }
+
+ @Override
+ public void displayPreference(@NonNull PreferenceScreen screen) {
+ super.displayPreference(screen);
+ SeekBarPreference preference = screen.findPreference(getPreferenceKey());
+ preference.setMax(getMax());
+ preference.setMin(getMin());
+ preference.setProgress(getSliderPosition());
+ updateState(preference);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (!InputSettings.isMouseScrollingAccelerationFeatureFlagEnabled()) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean setSliderPosition(int position) {
+ if (position < getMin() || position > getMax()) {
+ return false;
+ }
+ InputSettings.setMouseScrollingSpeed(mContext, position);
+
+ return true;
+ }
+
+ @Override
+ public int getSliderPosition() {
+ return InputSettings.getMouseScrollingSpeed(mContext);
+ }
+
+ @Override
+ public int getMin() {
+ return InputSettings.MIN_MOUSE_SCROLLING_SPEED;
+ }
+
+ @Override
+ public int getMax() {
+ return InputSettings.MAX_MOUSE_SCROLLING_SPEED;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java b/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java
index 14c580b..97bf3aa 100644
--- a/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java
+++ b/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java
@@ -36,7 +36,7 @@
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
- use(TouchGesturesButtonPreferenceController.class).setFragment(this /*parent*/);
+ use(TouchpadGesturesTutorialButtonPreferenceController.class).setFragment(this /*parent*/);
}
@Override
diff --git a/src/com/android/settings/inputmethod/TrackpadGestureDialogFragment.java b/src/com/android/settings/inputmethod/TouchpadGestureDialogFragment.java
similarity index 88%
rename from src/com/android/settings/inputmethod/TrackpadGestureDialogFragment.java
rename to src/com/android/settings/inputmethod/TouchpadGestureDialogFragment.java
index 1a90376..3a0effc 100644
--- a/src/com/android/settings/inputmethod/TrackpadGestureDialogFragment.java
+++ b/src/com/android/settings/inputmethod/TouchpadGestureDialogFragment.java
@@ -37,6 +37,7 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
@@ -48,13 +49,9 @@
import java.util.ArrayList;
import java.util.Arrays;
-public class TrackpadGestureDialogFragment extends BottomSheetDialogFragment {
+public class TouchpadGestureDialogFragment extends BottomSheetDialogFragment {
private Context mContext;
- private LayoutInflater mInflater;
- private View mViewArrowPrevious;
- private View mViewArrowNext;
- private ViewPager mViewPager;
private ArrayList<View> mPageList;
private ImageView[] mDotIndicators;
private View[] mViewPagerItems;
@@ -67,10 +64,8 @@
private static final int DOT_INDICATOR_LEFT_PADDING = 6;
private static final int DOT_INDICATOR_RIGHT_PADDING = 6;
- public TrackpadGestureDialogFragment() {}
-
@Override
- public void onAttach(Context context) {
+ public void onAttach(@NonNull Context context) {
super.onAttach(context);
mContext = context;
}
@@ -113,13 +108,14 @@
window.setNavigationBarColor(Color.TRANSPARENT);
}
+ @NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
- mInflater = mContext.getSystemService(LayoutInflater.class);
- View contentView = mInflater.inflate(R.layout.trackpad_gesture_preview, null);
- addViewPager(contentView);
+ LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+ View contentView = inflater.inflate(R.layout.touchpad_gesture_preview, null);
+ addViewPager(contentView, inflater);
dialog.setContentView(contentView);
Window gestureDialogWindow = dialog.getWindow();
gestureDialogWindow.setType(TYPE_SYSTEM_DIALOG);
@@ -147,7 +143,7 @@
// The gesture education view shouldn't be draggable."
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
- public void onStateChanged(View bottomSheet, int newState) {
+ public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
if (isGestureNavigationEnabled()) {
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
@@ -158,7 +154,7 @@
}
@Override
- public void onSlide(View bottomSheet, float slideOffset) {
+ public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// Do nothing.
}
});
@@ -176,13 +172,12 @@
R.layout.gesture_tip5_switch_apps));
}
- private void addViewPager(View preview) {
- mViewPager = preview.findViewById(R.id.viewpager);
+ private void addViewPager(View preview, LayoutInflater inflater) {
+ ViewPager viewPager = preview.findViewById(R.id.viewpager);
int viewPagerResourceSize = getViewPagerResource().size();
mViewPagerItems = new View[viewPagerResourceSize];
for (int i = 0; i < viewPagerResourceSize; i++) {
- mViewPagerItems[i] =
- mInflater.inflate(getViewPagerResource().get(i), null /* root */);
+ mViewPagerItems[i] = inflater.inflate(getViewPagerResource().get(i), null /* root */);
}
mPageList = new ArrayList<View>();
@@ -190,12 +185,12 @@
mPageList.add(mViewPagerItems[i]);
}
- mViewPager.setAdapter(new GesturePagerAdapter(mPageList));
+ viewPager.setAdapter(new GesturePagerAdapter(mPageList));
mButtonStartRestart = (Button) preview.findViewById(R.id.button_restart);
mButtonStartRestart.setOnClickListener(v -> {
- final int firstPos = mViewPager.getCurrentItem() - mViewPagerItems.length;
- mViewPager.setCurrentItem(firstPos, true);
+ final int firstPos = viewPager.getCurrentItem() - mViewPagerItems.length;
+ viewPager.setCurrentItem(firstPos, true);
});
mButtonEndDone = (Button) preview.findViewById(R.id.button_done);
@@ -210,11 +205,11 @@
mButtonEndNext = (Button) preview.findViewById(R.id.button_next);
mButtonEndNext.setOnClickListener(v -> {
- final int nextPos = mViewPager.getCurrentItem() + 1;
- mViewPager.setCurrentItem(nextPos, true);
+ final int nextPos = viewPager.getCurrentItem() + 1;
+ viewPager.setCurrentItem(nextPos, true);
});
- mViewPager.addOnPageChangeListener(createPageListener());
+ viewPager.addOnPageChangeListener(createPageListener());
final ViewGroup viewGroup = (ViewGroup) preview.findViewById(R.id.viewGroup);
mDotIndicators = new ImageView[mPageList.size()];
for (int i = 0; i < mPageList.size(); i++) {
@@ -236,12 +231,14 @@
}
@Override
- public void destroyItem(ViewGroup container, int position, Object object) {
+ public void destroyItem(@NonNull ViewGroup container, int position,
+ @NonNull Object object) {
if (mPageViewList.get(position) != null) {
container.removeView(mPageViewList.get(position));
}
}
+ @NonNull
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mPageViewList.get(position));
@@ -254,7 +251,7 @@
}
@Override
- public boolean isViewFromObject(View view, Object object) {
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return object == view;
}
}
diff --git a/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadGesturesDisabledFooterPreferenceController.java
similarity index 79%
rename from src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadGesturesDisabledFooterPreferenceController.java
index 1fed57e..a99a7f8 100644
--- a/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadGesturesDisabledFooterPreferenceController.java
@@ -19,11 +19,14 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
+
import com.android.settings.core.BasePreferenceController;
-public class TrackpadGesturesDisabledFooterPreferenceController extends BasePreferenceController {
+public class TouchpadGesturesDisabledFooterPreferenceController extends BasePreferenceController {
- public TrackpadGesturesDisabledFooterPreferenceController(Context context, String key) {
+ public TouchpadGesturesDisabledFooterPreferenceController(@NonNull Context context,
+ @NonNull String key) {
super(context, key);
}
diff --git a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadGesturesTutorialButtonPreferenceController.java
similarity index 85%
rename from src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadGesturesTutorialButtonPreferenceController.java
index babee95..845ce47 100644
--- a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadGesturesTutorialButtonPreferenceController.java
@@ -24,6 +24,8 @@
import android.hardware.input.InputSettings;
import android.os.UserHandle;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceScreen;
@@ -33,17 +35,18 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.widget.ButtonPreference;
-public class TouchGesturesButtonPreferenceController extends BasePreferenceController {
+public class TouchpadGesturesTutorialButtonPreferenceController extends BasePreferenceController {
private static final int ORDER_BOTTOM = 100;
- private static final String PREFERENCE_KEY = "trackpad_touch_gesture";
+ private static final String PREFERENCE_KEY = "touchpad_touch_gesture";
private static final String GESTURE_DIALOG_TAG = "GESTURE_DIALOG_TAG";
private static final String TUTORIAL_ACTION = "com.android.systemui.action.TOUCHPAD_TUTORIAL";
- private Fragment mParent;
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private @Nullable Fragment mParent;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TouchGesturesButtonPreferenceController(Context context, String key) {
+ public TouchpadGesturesTutorialButtonPreferenceController(@NonNull Context context,
+ @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
@@ -88,7 +91,7 @@
// of user 0 sysui instance
mContext.startActivityAsUser(intent, UserHandle.SYSTEM);
} else {
- TrackpadGestureDialogFragment fragment = new TrackpadGestureDialogFragment();
+ TouchpadGestureDialogFragment fragment = new TouchpadGestureDialogFragment();
fragment.setTargetFragment(mParent, 0);
fragment.show(mParent.getActivity().getSupportFragmentManager(), GESTURE_DIALOG_TAG);
}
diff --git a/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceController.java
similarity index 80%
rename from src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceController.java
index d024546..945ff43 100644
--- a/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceController.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.SliderPreferenceController;
@@ -27,12 +28,11 @@
import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-public class TrackpadPointerSpeedPreferenceController extends SliderPreferenceController {
+public class TouchpadPointerSpeedPreferenceController extends SliderPreferenceController {
- private SeekBarPreference mPreference;
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TrackpadPointerSpeedPreferenceController(Context context, String key) {
+ public TouchpadPointerSpeedPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
@@ -40,11 +40,11 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
- mPreference.setMax(getMax());
- mPreference.setMin(getMin());
- mPreference.setProgress(getSliderPosition());
- updateState(mPreference);
+ SeekBarPreference preference = screen.findPreference(getPreferenceKey());
+ preference.setMax(getMax());
+ preference.setMin(getMin());
+ preference.setProgress(getSliderPosition());
+ updateState(preference);
}
@Override
diff --git a/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceController.java
similarity index 85%
rename from src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceController.java
index e752c1e..68f2679 100644
--- a/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceController.java
@@ -20,16 +20,19 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
+
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-public class TrackpadReverseScrollingPreferenceController extends TogglePreferenceController {
+public class TouchpadReverseScrollingPreferenceController extends TogglePreferenceController {
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TrackpadReverseScrollingPreferenceController(Context context, String key) {
+ public TouchpadReverseScrollingPreferenceController(@NonNull Context context,
+ @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
diff --git a/src/com/android/settings/inputmethod/TrackpadBottomPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceController.java
similarity index 84%
rename from src/com/android/settings/inputmethod/TrackpadBottomPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceController.java
index 8e77e0c..73c051d 100644
--- a/src/com/android/settings/inputmethod/TrackpadBottomPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceController.java
@@ -20,16 +20,19 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
+
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-public class TrackpadBottomPreferenceController extends TogglePreferenceController {
+public class TouchpadRightClickZonePreferenceController extends TogglePreferenceController {
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TrackpadBottomPreferenceController(Context context, String key) {
+ public TouchpadRightClickZonePreferenceController(@NonNull Context context,
+ @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
diff --git a/src/com/android/settings/inputmethod/TrackpadTapDraggingPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadTapDraggingPreferenceController.java
similarity index 87%
rename from src/com/android/settings/inputmethod/TrackpadTapDraggingPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadTapDraggingPreferenceController.java
index ddf6b44..ecd1b10 100644
--- a/src/com/android/settings/inputmethod/TrackpadTapDraggingPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadTapDraggingPreferenceController.java
@@ -20,16 +20,18 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
+
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-public class TrackpadTapDraggingPreferenceController extends TogglePreferenceController {
+public class TouchpadTapDraggingPreferenceController extends TogglePreferenceController {
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TrackpadTapDraggingPreferenceController(Context context, String key) {
+ public TouchpadTapDraggingPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
diff --git a/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceController.java
similarity index 87%
rename from src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceController.java
rename to src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceController.java
index 86d7311..e052415 100644
--- a/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceController.java
@@ -20,16 +20,18 @@
import android.content.Context;
import android.hardware.input.InputSettings;
+import androidx.annotation.NonNull;
+
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-public class TrackpadTapToClickPreferenceController extends TogglePreferenceController {
+public class TouchpadTapToClickPreferenceController extends TogglePreferenceController {
- private MetricsFeatureProvider mMetricsFeatureProvider;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
- public TrackpadTapToClickPreferenceController(Context context, String key) {
+ public TouchpadTapToClickPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt
index 11790d0..b870f30 100644
--- a/src/com/android/settings/network/AirplaneModePreference.kt
+++ b/src/com/android/settings/network/AirplaneModePreference.kt
@@ -37,11 +37,11 @@
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
@@ -126,7 +126,7 @@
phoneStateListener =
object : PhoneStateListener(Looper.getMainLooper()) {
override fun onRadioPowerStateChanged(state: Int) {
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.VALUE)
}
}
it.listen(phoneStateListener, PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)
diff --git a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
index f0d1da4..6218e05 100644
--- a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
+++ b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
@@ -18,21 +18,13 @@
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
-import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA;
-import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS;
import android.content.Context;
import android.os.PersistableBundle;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyManager;
-import android.telephony.satellite.NtnSignalStrength;
import android.telephony.satellite.SatelliteManager;
import android.util.Log;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -40,9 +32,6 @@
import com.android.settings.flags.Flags;
import com.android.settings.network.CarrierConfigCache;
-import java.util.Arrays;
-import java.util.List;
-
/** Preference controller for Satellite functions in mobile network settings. */
public class SatelliteSettingsPreferenceCategoryController
extends TelephonyBasePreferenceController implements DefaultLifecycleObserver {
@@ -51,17 +40,11 @@
private CarrierConfigCache mCarrierConfigCache;
private SatelliteManager mSatelliteManager;
private PreferenceCategory mPreferenceCategory;
- private TelephonyManager mTelephonyManager;
-
- @VisibleForTesting
- final CarrierRoamingNtnModeCallback mCarrierRoamingNtnModeCallback =
- new CarrierRoamingNtnModeCallback();
public SatelliteSettingsPreferenceCategoryController(Context context, String key) {
super(context, key);
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
mSatelliteManager = context.getSystemService(SatelliteManager.class);
- mTelephonyManager = context.getSystemService(TelephonyManager.class);
}
/**
@@ -72,13 +55,13 @@
public void init(int subId) {
Log.d(TAG, "init(), subId=" + subId);
mSubId = subId;
- mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceCategory = screen.findPreference(getPreferenceKey());
+ mPreferenceCategory.setTitle(R.string.category_title_satellite_connectivity);
}
@Override
@@ -103,58 +86,4 @@
return (isSatelliteAttachSupported || isSatelliteSosSupported)
? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
}
-
- @Override
- public void onResume(@NonNull LifecycleOwner owner) {
- if (Flags.satelliteOemSettingsUxMigration()) {
- mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
- mCarrierRoamingNtnModeCallback);
- }
- }
-
- @Override
- public void onPause(@NonNull LifecycleOwner owner) {
- if (Flags.satelliteOemSettingsUxMigration()) {
- mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback);
- }
- }
-
- @VisibleForTesting
- class CarrierRoamingNtnModeCallback extends TelephonyCallback implements
- TelephonyCallback.CarrierRoamingNtnListener {
- @Override
- public void onCarrierRoamingNtnAvailableServicesChanged(int[] availableServices) {
- CarrierRoamingNtnListener.super.onCarrierRoamingNtnAvailableServicesChanged(
- availableServices);
- List<Integer> availableServicesList = Arrays.stream(availableServices).boxed().toList();
- boolean isSmsAvailable = availableServicesList.contains(SERVICE_TYPE_SMS);
- boolean isDataAvailable = availableServicesList.contains(SERVICE_TYPE_DATA);
- Log.i(TAG, "isSmsAvailable : " + isSmsAvailable
- + " / isDataAvailable " + isDataAvailable);
- if (mPreferenceCategory == null) {
- Log.d(TAG, "Satellite preference category is not initialized yet");
- return;
- }
- if (isDataAvailable) {
- mPreferenceCategory.setTitle(R.string.category_title_satellite_connectivity);
- } else if (isSmsAvailable) {
- mPreferenceCategory.setTitle(R.string.satellite_setting_title);
- }
- }
-
- @Override
- public void onCarrierRoamingNtnEligibleStateChanged(boolean eligible) {
- // Do nothing
- }
-
- @Override
- public void onCarrierRoamingNtnModeChanged(boolean active) {
- // Do nothing
- }
-
- @Override
- public void onCarrierRoamingNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
- // Do nothing
- }
- }
}
diff --git a/src/com/android/settings/notification/app/AllConversationsPreferenceController.java b/src/com/android/settings/notification/app/AllConversationsPreferenceController.java
index c863190..1fb8e35 100644
--- a/src/com/android/settings/notification/app/AllConversationsPreferenceController.java
+++ b/src/com/android/settings/notification/app/AllConversationsPreferenceController.java
@@ -23,6 +23,7 @@
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.widget.TopIntroPreference;
public class AllConversationsPreferenceController extends ConversationListPreferenceController {
@@ -39,9 +40,9 @@
@Override
Preference getSummaryPreference() {
- Preference pref = new Preference(mContext);
+ Preference pref = new TopIntroPreference(mContext);
pref.setOrder(1);
- pref.setSummary(R.string.other_conversations_summary);
+ pref.setTitle(R.string.other_conversations_summary);
pref.setSelectable(false);
return pref;
}
diff --git a/src/com/android/settings/notification/app/AllowSoundPreferenceController.java b/src/com/android/settings/notification/app/AllowSoundPreferenceController.java
index 0664c54..b1333b3 100644
--- a/src/com/android/settings/notification/app/AllowSoundPreferenceController.java
+++ b/src/com/android/settings/notification/app/AllowSoundPreferenceController.java
@@ -71,6 +71,9 @@
pref.setEnabled(!pref.isDisabledByAdmin());
pref.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
|| mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
} else { Log.i(TAG, "tried to updatestate on a null channel?!"); }
}
diff --git a/src/com/android/settings/notification/app/AppLinkPreferenceController.java b/src/com/android/settings/notification/app/AppLinkPreferenceController.java
index 043ae69..4b397d0 100644
--- a/src/com/android/settings/notification/app/AppLinkPreferenceController.java
+++ b/src/com/android/settings/notification/app/AppLinkPreferenceController.java
@@ -54,6 +54,9 @@
}
public void updateState(Preference preference) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
if (mAppRow != null) {
preference.setIntent(mAppRow.settingsIntent);
}
diff --git a/src/com/android/settings/notification/app/BadgePreferenceController.java b/src/com/android/settings/notification/app/BadgePreferenceController.java
index 9d55fa3..b5e65fc 100644
--- a/src/com/android/settings/notification/app/BadgePreferenceController.java
+++ b/src/com/android/settings/notification/app/BadgePreferenceController.java
@@ -82,6 +82,9 @@
public void updateState(Preference preference) {
if (mAppRow != null) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setDisabledByAdmin(mAdmin);
if (mChannel != null) {
diff --git a/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java b/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
index 8c22f92..e82fe0b 100644
--- a/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
+++ b/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
@@ -82,6 +82,9 @@
intent.putExtra(Settings.EXTRA_APP_UID, mAppRow.uid);
preference.setIntent(intent);
}
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
}
@Override
diff --git a/src/com/android/settings/notification/app/ChannelListPreferenceController.java b/src/com/android/settings/notification/app/ChannelListPreferenceController.java
index b8dfb6a..66094a0 100644
--- a/src/com/android/settings/notification/app/ChannelListPreferenceController.java
+++ b/src/com/android/settings/notification/app/ChannelListPreferenceController.java
@@ -58,6 +58,7 @@
private List<NotificationChannelGroup> mChannelGroupList;
private PreferenceCategory mPreference;
+ int mChannelCount;
public ChannelListPreferenceController(Context context, NotificationBackend backend) {
super(context, backend);
@@ -107,6 +108,7 @@
} else {
mChannelGroupList = mBackend.getGroups(mAppRow.pkg, mAppRow.uid).getList();
}
+ mChannelCount = mBackend.getChannelCount(mAppRow.pkg, mAppRow.uid);
Collections.sort(mChannelGroupList, CHANNEL_GROUP_COMPARATOR);
return null;
}
@@ -116,6 +118,7 @@
if (mContext == null) {
return;
}
+
updateFullList(mPreference, mChannelGroupList);
}
}.execute();
@@ -129,25 +132,30 @@
void updateFullList(@NonNull PreferenceCategory groupPrefsList,
@NonNull List<NotificationChannelGroup> channelGroups) {
if (channelGroups.isEmpty()) {
- if (groupPrefsList.getPreferenceCount() == 1
- && KEY_ZERO_CATEGORIES.equals(groupPrefsList.getPreference(0).getKey())) {
- // Ensure the titles are correct for the current language, but otherwise leave alone
- PreferenceGroup groupCategory = (PreferenceGroup) groupPrefsList.getPreference(0);
- groupCategory.setTitle(R.string.notification_channels);
- groupCategory.getPreference(0).setTitle(R.string.no_channels);
- } else {
- // Clear any contents and create the 'zero-categories' group.
+ if (mChannelCount > 0) {
groupPrefsList.removeAll();
+ } else {
+ if (groupPrefsList.getPreferenceCount() == 1
+ && KEY_ZERO_CATEGORIES.equals(groupPrefsList.getPreference(0).getKey())) {
+ // Ensure the titles are correct for the current language, but otherwise leave alone
+ PreferenceGroup groupCategory = (PreferenceGroup) groupPrefsList.getPreference(
+ 0);
+ groupCategory.setTitle(R.string.notification_channels);
+ groupCategory.getPreference(0).setTitle(R.string.no_channels);
+ } else {
+ // Clear any contents and create the 'zero-categories' group.
+ groupPrefsList.removeAll();
- PreferenceCategory groupCategory = new PreferenceCategory(mContext);
- groupCategory.setTitle(R.string.notification_channels);
- groupCategory.setKey(KEY_ZERO_CATEGORIES);
- groupPrefsList.addPreference(groupCategory);
+ PreferenceCategory groupCategory = new PreferenceCategory(mContext);
+ groupCategory.setTitle(R.string.notification_channels);
+ groupCategory.setKey(KEY_ZERO_CATEGORIES);
+ groupPrefsList.addPreference(groupCategory);
- Preference empty = new Preference(mContext);
- empty.setTitle(R.string.no_channels);
- empty.setEnabled(false);
- groupCategory.addPreference(empty);
+ Preference empty = new Preference(mContext);
+ empty.setTitle(R.string.no_channels);
+ empty.setEnabled(false);
+ groupCategory.addPreference(empty);
+ }
}
} else {
updateGroupList(groupPrefsList, channelGroups);
@@ -211,6 +219,11 @@
groupPrefsList.addPreference(group);
}
}
+ Preference otherGroup = groupPrefsList.findPreference(KEY_GENERAL_CATEGORY);
+ if (otherGroup != null) {
+ otherGroup.setTitle(numFinalGroups == 1
+ ? R.string.notification_channels : R.string.notification_channels_other);
+ }
}
/**
@@ -248,8 +261,7 @@
List<Preference> finalOrderedPrefs = new ArrayList<>();
Preference appDefinedGroupToggle;
if (group.getId() == null) {
- // For the 'null' group, set the "Other" title.
- groupPrefGroup.setTitle(R.string.notification_channels_other);
+ groupPrefGroup.setTitle(R.string.notification_channels);
appDefinedGroupToggle = null;
} else {
// For an app-defined group, set their name and create a row to toggle 'isBlocked'.
diff --git a/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java b/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java
index 07b7fda..004afe2 100644
--- a/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java
+++ b/src/com/android/settings/notification/app/DeletedChannelsPreferenceController.java
@@ -63,6 +63,9 @@
}
public void updateState(Preference preference) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
if (mAppRow != null) {
int deletedChannelCount = mBackend.getDeletedChannelCount(mAppRow.pkg, mAppRow.uid);
preference.setTitle(StringUtil.getIcuPluralsString(mContext, deletedChannelCount,
diff --git a/src/com/android/settings/notification/app/DndPreferenceController.java b/src/com/android/settings/notification/app/DndPreferenceController.java
index b65928a..2533787 100644
--- a/src/com/android/settings/notification/app/DndPreferenceController.java
+++ b/src/com/android/settings/notification/app/DndPreferenceController.java
@@ -54,6 +54,9 @@
public void updateState(Preference preference) {
if (mChannel != null) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setDisabledByAdmin(mAdmin);
pref.setEnabled(!pref.isDisabledByAdmin());
diff --git a/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt b/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
index 4349b4c..6977a99 100644
--- a/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
+++ b/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceController.kt
@@ -21,9 +21,9 @@
import android.app.AppOpsManager.OP_USE_FULL_SCREEN_INTENT
import android.content.AttributionSource
import android.content.Context
-import android.content.pm.PackageManager.NameNotFoundException
import android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET
import android.content.pm.PackageManager.GET_PERMISSIONS
+import android.content.pm.PackageManager.NameNotFoundException
import android.os.UserHandle
import android.permission.PermissionManager
import android.util.Log
@@ -65,6 +65,7 @@
preference.setDisabledByAdmin(mAdmin)
preference.isEnabled = !preference.isDisabledByAdmin
preference.isChecked = isPermissionGranted()
+ preference.parent?.isVisible = true
}
override fun onPreferenceChange(preference: Preference, value: Any): Boolean {
diff --git a/src/com/android/settings/notification/app/HeaderPreferenceController.java b/src/com/android/settings/notification/app/HeaderPreferenceController.java
index 220e7b5..91abe81 100644
--- a/src/com/android/settings/notification/app/HeaderPreferenceController.java
+++ b/src/com/android/settings/notification/app/HeaderPreferenceController.java
@@ -81,9 +81,8 @@
mHeaderController = EntityHeaderController.newInstance(
activity, mFragment, pref.findViewById(R.id.entity_header));
pref = mHeaderController.setIcon(mAppRow.icon)
- .setLabel(getLabel())
- .setSummary(getSummary())
- .setSecondSummary(getSecondSummary())
+ .setLabel(getSummary())
+ .setSummary(getSecondSummary())
.setPackageName(mAppRow.pkg)
.setUid(mAppRow.uid)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NOTIF_PREFERENCE,
@@ -95,14 +94,6 @@
}
}
- public CharSequence getLabel() {
- if (mChannel != null && !isDefaultChannel()) {
- return mChannel.getName();
- } else {
- return mAppRow.label;
- }
- }
-
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
mStarted = true;
@@ -113,15 +104,7 @@
if (mChannel != null) {
if (mChannelGroup != null
&& !TextUtils.isEmpty(mChannelGroup.getName())) {
- final SpannableStringBuilder summary = new SpannableStringBuilder();
- BidiFormatter bidi = BidiFormatter.getInstance();
- summary.append(bidi.unicodeWrap(mAppRow.label));
- summary.append(bidi.unicodeWrap(mContext.getText(
- R.string.notification_header_divider_symbol_with_spaces)));
- summary.append(bidi.unicodeWrap(mChannelGroup.getName().toString()));
- return summary.toString();
- } else {
- return mAppRow.label.toString();
+ return mChannelGroup.getName().toString();
}
}
return "";
diff --git a/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceController.java b/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceController.java
index 478607b..2194579 100644
--- a/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceController.java
+++ b/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceController.java
@@ -23,6 +23,7 @@
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.widget.SettingsThemeHelper;
public class InvalidConversationInfoPreferenceController extends NotificationPreferenceController {
@@ -49,6 +50,9 @@
if (mPreferenceFilter != null && !isIncludedInFilter()) {
return false;
}
+ if (SettingsThemeHelper.isExpressiveTheme(mContext)) {
+ return false;
+ }
return mBackend.isInInvalidMsgState(mAppRow.pkg, mAppRow.uid);
}
diff --git a/src/com/android/settings/notification/app/InvalidConversationPreferenceController.java b/src/com/android/settings/notification/app/InvalidConversationPreferenceController.java
index 5c502dc..57eaad9 100644
--- a/src/com/android/settings/notification/app/InvalidConversationPreferenceController.java
+++ b/src/com/android/settings/notification/app/InvalidConversationPreferenceController.java
@@ -24,6 +24,7 @@
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.widget.SettingsThemeHelper;
public class InvalidConversationPreferenceController extends NotificationPreferenceController
implements Preference.OnPreferenceChangeListener {
@@ -67,7 +68,15 @@
pref.setDisabledByAdmin(mAdmin);
pref.setEnabled(!pref.isDisabledByAdmin());
pref.setChecked(!mBackend.hasUserDemotedInvalidMsgApp(mAppRow.pkg, mAppRow.uid));
- preference.setSummary(mContext.getString(R.string.conversation_section_switch_summary));
+ if (SettingsThemeHelper.isExpressiveTheme(mContext)) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
+ preference.setSummary(mContext.getString(
+ R.string.conversation_section_switch_complete_summary));
+ } else {
+ preference.setSummary(mContext.getString(R.string.conversation_section_switch_summary));
+ }
}
@Override
diff --git a/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java b/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java
index 18fc917..55b50df 100644
--- a/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java
+++ b/src/com/android/settings/notification/app/PriorityConversationsPreferenceController.java
@@ -23,6 +23,7 @@
import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.widget.TopIntroPreference;
public class PriorityConversationsPreferenceController extends
ConversationListPreferenceController {
@@ -40,9 +41,9 @@
@Override
Preference getSummaryPreference() {
- Preference pref = new Preference(mContext);
+ Preference pref = new TopIntroPreference(mContext);
pref.setOrder(1);
- pref.setSummary(R.string.important_conversations_summary_bubbles);
+ pref.setTitle(R.string.important_conversations_summary_bubbles);
pref.setSelectable(false);
return pref;
}
diff --git a/src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java b/src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java
index 13417b2..bd8229e 100644
--- a/src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java
+++ b/src/com/android/settings/notification/app/PromotedNotificationsPreferenceController.java
@@ -20,14 +20,12 @@
import androidx.annotation.NonNull;
import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedSwitchPreference;
public class PromotedNotificationsPreferenceController extends
NotificationPreferenceController implements Preference.OnPreferenceChangeListener {
- private static final String KEY_PROMOTED_CATEGORY = "promoted_category";
protected static final String KEY_PROMOTED_SWITCH = "promoted_switch";
public PromotedNotificationsPreferenceController(@NonNull Context context,
@@ -38,7 +36,7 @@
@Override
@NonNull
public String getPreferenceKey() {
- return KEY_PROMOTED_CATEGORY;
+ return KEY_PROMOTED_SWITCH;
}
@Override
@@ -56,12 +54,13 @@
}
/**
- * Updates the state of the promoted notifications switch. Because this controller governs
- * the full PreferenceCategory, we must find the switch preference within the category first.
+ * Updates the state of the promoted notifications switch.
*/
public void updateState(@NonNull Preference preference) {
- PreferenceCategory category = (PreferenceCategory) preference;
- RestrictedSwitchPreference pref = category.findPreference(KEY_PROMOTED_SWITCH);
+ RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+ if (pref.getParent() != null) {
+ pref.getParent().setVisible(true);
+ }
if (pref != null && mAppRow != null) {
pref.setDisabledByAdmin(mAdmin);
diff --git a/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java b/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java
index f5f2e97..4fe0a87 100644
--- a/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java
+++ b/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java
@@ -40,6 +40,7 @@
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.ButtonPreference;
import com.android.settingslib.widget.LayoutPreference;
import java.text.Collator;
@@ -75,14 +76,12 @@
return true;
}
- //TODO(b/233325816): Use ButtonPreference instead.
- LayoutPreference getClearAll(PreferenceGroup parent) {
- LayoutPreference pref = new LayoutPreference(
- mContext, R.layout.conversations_clear_recents);
+ ButtonPreference getClearAll(PreferenceGroup parent) {
+ ButtonPreference pref = new ButtonPreference(mContext);
+ pref.setTitle(R.string.conversation_settings_clear_recents);
pref.setKey(getPreferenceKey() + CLEAR_ALL_KEY_SUFFIX);
pref.setOrder(1);
- Button button = pref.findViewById(R.id.conversation_settings_clear_recents);
- button.setOnClickListener(v -> {
+ pref.setOnClickListener(v -> {
try {
mPs.removeAllRecentConversations();
// Removing recents is asynchronous, so we can't immediately reload the list from
@@ -97,7 +96,8 @@
}
}
}
- button.announceForAccessibility(mContext.getString(R.string.recent_convos_removed));
+ pref.getButton().announceForAccessibility(
+ mContext.getString(R.string.recent_convos_removed));
} catch (RemoteException e) {
Slog.w(TAG, "Could not clear recents", e);
}
@@ -160,25 +160,27 @@
.forEachOrdered(pref -> {
pref.setOrder(order.getAndIncrement());
mPreferenceGroup.addPreference(pref);
- if (pref.hasClearListener()) {
+ if (pref instanceof RecentConversationPreference
+ && ((RecentConversationPreference) pref).hasClearListener()) {
hasClearable.set(true);
}
});
return hasClearable.get();
}
- protected RecentConversationPreference createConversationPref(
+ protected Preference createConversationPref(
final ConversationChannel conversation) {
final String pkg = conversation.getShortcutInfo().getPackage();
final int uid = conversation.getUid();
final String conversationId = conversation.getShortcutInfo().getId();
- RecentConversationPreference pref = new RecentConversationPreference(mContext);
+ Preference pref = conversation.hasActiveNotifications() ? new Preference(mContext)
+ : new RecentConversationPreference(mContext);
if (!conversation.hasActiveNotifications()) {
- pref.setOnClearClickListener(() -> {
+ ((RecentConversationPreference) pref).setOnClearClickListener(() -> {
try {
mPs.removeRecentConversation(pkg, UserHandle.getUserId(uid), conversationId);
- pref.getClearView().announceForAccessibility(
+ ((RecentConversationPreference) pref).getClearView().announceForAccessibility(
mContext.getString(R.string.recent_convo_removed));
mPreferenceGroup.removePreference(pref);
} catch (RemoteException e) {
diff --git a/src/com/android/settings/notification/app/ShowMorePreferenceController.java b/src/com/android/settings/notification/app/ShowMorePreferenceController.java
index dbc279a..f44a0c8 100644
--- a/src/com/android/settings/notification/app/ShowMorePreferenceController.java
+++ b/src/com/android/settings/notification/app/ShowMorePreferenceController.java
@@ -56,6 +56,9 @@
if (mAppRow.banned || mAppRow.showAllChannels) {
return false;
}
+ if (mBackend.getChannelCount(mAppRow.pkg, mAppRow.uid) == 0) {
+ return false;
+ }
return true;
}
diff --git a/src/com/android/settings/notification/app/VisibilityPreferenceController.java b/src/com/android/settings/notification/app/VisibilityPreferenceController.java
index a2a1d76..0cec7e2 100644
--- a/src/com/android/settings/notification/app/VisibilityPreferenceController.java
+++ b/src/com/android/settings/notification/app/VisibilityPreferenceController.java
@@ -75,6 +75,10 @@
public void updateState(Preference preference) {
if (mChannel != null && mAppRow != null) {
+ if (preference.getParent() != null) {
+ preference.getParent().setVisible(true);
+ }
+
RestrictedListPreference pref = (RestrictedListPreference) preference;
ArrayList<CharSequence> entries = new ArrayList<>();
ArrayList<CharSequence> values = new ArrayList<>();
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
index 13d5c6e..bbed5b9 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
@@ -109,9 +109,11 @@
tryParseScheduleConditionId(mode.getRule().getConditionId());
if (schedule != null) {
preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
- preference.setSummary(Utils.createAccessibleSequence(
- SystemZenRules.getDaysOfWeekShort(mContext, schedule),
- SystemZenRules.getDaysOfWeekFull(mContext, schedule)));
+ String shortDaysSummary = SystemZenRules.getDaysOfWeekShort(mContext, schedule);
+ String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule);
+ preference.setSummary(shortDaysSummary != null && fullDaysSummary != null
+ ? Utils.createAccessibleSequence(shortDaysSummary, fullDaysSummary)
+ : shortDaysSummary);
} else {
// Fallback, but shouldn't happen.
Log.wtf(TAG, "SCHEDULE_TIME mode without schedule: " + mode);
diff --git a/src/com/android/settings/overlay/SurveyFeatureProvider.java b/src/com/android/settings/overlay/SurveyFeatureProvider.java
index ce5be98..85d123d 100644
--- a/src/com/android/settings/overlay/SurveyFeatureProvider.java
+++ b/src/com/android/settings/overlay/SurveyFeatureProvider.java
@@ -19,7 +19,10 @@
import android.content.BroadcastReceiver;
import android.content.Context;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
+import androidx.lifecycle.LifecycleOwner;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
@@ -109,4 +112,14 @@
* @param simpleKey The simple name of the key to get the surveyId for.
*/
void sendActivityIfAvailable(String simpleKey);
+
+ /**
+ * Checks if a survey is available for the given key by binding to the survey service.
+ *
+ * @param lifecycleOwner The lifecycle owner to manage the service connection.
+ * @param simpleKey The simple name of the key to get the surveyId for.
+ * @param listener The callback to be invoked when the survey availability is checked.
+ */
+ void checkSurveyAvailable(@NonNull LifecycleOwner lifecycleOwner, @NonNull String simpleKey,
+ @NonNull Consumer<Boolean> listener);
}
diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemLocaleListFragment.java b/src/com/android/settings/regionalpreferences/NumberingSystemLocaleListFragment.java
index 6a39b23..5846403 100644
--- a/src/com/android/settings/regionalpreferences/NumberingSystemLocaleListFragment.java
+++ b/src/com/android/settings/regionalpreferences/NumberingSystemLocaleListFragment.java
@@ -16,8 +16,6 @@
package com.android.settings.regionalpreferences;
-import static android.provider.Settings.ACTION_NUMBERING_SYSTEM_SETTINGS;
-
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -49,10 +47,6 @@
finish();
}
- if (getIntent().getAction().equals(ACTION_NUMBERING_SYSTEM_SETTINGS)) {
- // TODO: Generically log action.
- }
-
getActivity().setTitle(R.string.numbers_preferences_title);
getActivity().setResult(Activity.RESULT_OK);
}
diff --git a/src/com/android/settings/restriction/UserRestrictionBindingHelper.kt b/src/com/android/settings/restriction/UserRestrictionBindingHelper.kt
index a1329c2..4dca003 100644
--- a/src/com/android/settings/restriction/UserRestrictionBindingHelper.kt
+++ b/src/com/android/settings/restriction/UserRestrictionBindingHelper.kt
@@ -20,8 +20,8 @@
import com.android.settings.PreferenceRestrictionMixin
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyedObserver
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.preference.PreferenceScreenBindingHelper
-import com.android.settingslib.preference.PreferenceScreenBindingHelper.Companion.CHANGE_REASON_STATE
/** Helper to rebind preference immediately when user restriction is changed. */
class UserRestrictionBindingHelper(
@@ -55,7 +55,7 @@
override fun onKeyChanged(restrictionKey: String, reason: Int) {
val keys = restrictionKeysToPreferenceKeys[restrictionKey] ?: return
- for (key in keys) screenBindingHelper.notifyChange(key, CHANGE_REASON_STATE)
+ for (key in keys) screenBindingHelper.notifyChange(key, PreferenceChangeReason.STATE)
}
override fun close() {
diff --git a/src/com/android/settings/restriction/UserRestrictions.kt b/src/com/android/settings/restriction/UserRestrictions.kt
index 880aa5d..3d78e8e 100644
--- a/src/com/android/settings/restriction/UserRestrictions.kt
+++ b/src/com/android/settings/restriction/UserRestrictions.kt
@@ -24,6 +24,7 @@
import com.android.settingslib.datastore.AbstractKeyedDataObservable
import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyedObserver
+import com.android.settingslib.metadata.PreferenceChangeReason
import java.util.concurrent.Executor
/** Helper class to monitor user restriction changes. */
@@ -46,7 +47,7 @@
object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// there is no way to get the changed keys, just notify all observers
- observable.notifyChange(DataChangeReason.UPDATE)
+ observable.notifyChange(PreferenceChangeReason.STATE)
}
}
diff --git a/src/com/android/settings/safetycenter/BiometricSourcesUtils.java b/src/com/android/settings/safetycenter/BiometricSourcesUtils.java
new file mode 100644
index 0000000..fcda654
--- /dev/null
+++ b/src/com/android/settings/safetycenter/BiometricSourcesUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
+
+/** Static helpers for setting SafetyCenter data for biometric safety sources. */
+public final class BiometricSourcesUtils {
+
+ public static final int REQUEST_CODE_COMBINED_BIOMETRIC_SETTING = 10;
+ public static final int REQUEST_CODE_FACE_SETTING = 20;
+ public static final int REQUEST_CODE_FINGERPRINT_SETTING = 30;
+
+ private BiometricSourcesUtils() {}
+
+ /** Sets data for one of the biometrics sources */
+ public static void setBiometricSafetySourceData(
+ String safetySourceId,
+ Context context,
+ String title,
+ String summary,
+ PendingIntent pendingIntent,
+ boolean enabled,
+ boolean hasEnrolled,
+ SafetyEvent safetyEvent) {
+ int severityLevel =
+ enabled && hasEnrolled
+ ? SafetySourceData.SEVERITY_LEVEL_INFORMATION
+ : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
+
+ SafetySourceStatus status =
+ new SafetySourceStatus.Builder(title, summary, severityLevel)
+ .setPendingIntent(pendingIntent)
+ .setEnabled(enabled)
+ .build();
+ SafetySourceData safetySourceData =
+ new SafetySourceData.Builder().setStatus(status).build();
+
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(context, safetySourceId, safetySourceData, safetyEvent);
+ }
+
+ /** Helper method for creating a pending intent. */
+ public static PendingIntent createPendingIntent(
+ Context context, Intent intent, int requestCode) {
+ return PendingIntent.getActivity(
+ context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);
+ }
+}
diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
index c93ced1..97a922e 100644
--- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java
+++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java
@@ -16,9 +16,11 @@
package com.android.settings.safetycenter;
-import android.app.PendingIntent;
+import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_COMBINED_BIOMETRIC_SETTING;
+import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_FACE_SETTING;
+import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_FINGERPRINT_SETTING;
+
import android.content.Context;
-import android.content.Intent;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
@@ -26,8 +28,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.safetycenter.SafetyEvent;
-import android.safetycenter.SafetySourceData;
-import android.safetycenter.SafetySourceStatus;
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricNavigationUtils;
@@ -41,9 +41,6 @@
public final class BiometricsSafetySource {
public static final String SAFETY_SOURCE_ID = "AndroidBiometrics";
- private static final int REQUEST_CODE_COMBINED_BIOMETRIC_SETTING = 10;
- private static final int REQUEST_CODE_FACE_SETTING = 20;
- private static final int REQUEST_CODE_FINGERPRINT_SETTING = 30;
private BiometricsSafetySource() {}
@@ -53,42 +50,38 @@
return;
}
- final UserHandle userHandle = Process.myUserHandle();
- final int userId = userHandle.getIdentifier();
- final UserManager userManager = UserManager.get(context);
+ UserHandle userHandle = Process.myUserHandle();
+ int userId = userHandle.getIdentifier();
+ UserManager userManager = UserManager.get(context);
UserHandle profileParentUserHandle = userManager.getProfileParent(userHandle);
if (profileParentUserHandle == null) {
profileParentUserHandle = userHandle;
}
- final Context profileParentContext =
- context.createContextAsUser(profileParentUserHandle, 0);
+ Context profileParentContext = context.createContextAsUser(profileParentUserHandle, 0);
if (android.os.Flags.allowPrivateProfile()
&& android.multiuser.Flags.enablePrivateSpaceFeatures()
&& userManager.isPrivateProfile()) {
// SC always expects a response from the source if the broadcast has been sent for this
// source, therefore, we need to send a null SafetySourceData.
- SafetyCenterManagerWrapper.get().setSafetySourceData(
- context,
- SAFETY_SOURCE_ID,
- /* safetySourceData= */ null,
- safetyEvent);
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
return;
}
- final BiometricNavigationUtils biometricNavigationUtils =
- new BiometricNavigationUtils(userId);
- final CombinedBiometricStatusUtils combinedBiometricStatusUtils =
+ BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils(userId);
+ CombinedBiometricStatusUtils combinedBiometricStatusUtils =
new CombinedBiometricStatusUtils(context, userId);
- final ActiveUnlockStatusUtils activeUnlockStatusUtils =
- new ActiveUnlockStatusUtils(context);
+ ActiveUnlockStatusUtils activeUnlockStatusUtils = new ActiveUnlockStatusUtils(context);
if (!userManager.isProfile() && activeUnlockStatusUtils.isAvailable()) {
- final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin =
combinedBiometricStatusUtils.getDisablingAdmin();
- setBiometricSafetySourceData(
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
context,
activeUnlockStatusUtils.getTitleForActiveUnlock(),
combinedBiometricStatusUtils.getSummary(),
- createPendingIntent(
+ BiometricSourcesUtils.createPendingIntent(
context,
biometricNavigationUtils.getBiometricSettingsIntent(
context,
@@ -102,13 +95,14 @@
return;
}
if (combinedBiometricStatusUtils.isAvailable()) {
- final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin =
combinedBiometricStatusUtils.getDisablingAdmin();
- setBiometricSafetySourceData(
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
context,
combinedBiometricStatusUtils.getTitle(),
combinedBiometricStatusUtils.getSummary(),
- createPendingIntent(
+ BiometricSourcesUtils.createPendingIntent(
profileParentContext,
biometricNavigationUtils
.getBiometricSettingsIntent(
@@ -125,17 +119,17 @@
return;
}
- final FaceManager faceManager = Utils.getFaceManagerOrNull(context);
- final FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager, userId);
+ FaceManager faceManager = Utils.getFaceManagerOrNull(context);
+ FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager, userId);
if (faceStatusUtils.isAvailable()) {
- final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
- faceStatusUtils.getDisablingAdmin();
- setBiometricSafetySourceData(
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin = faceStatusUtils.getDisablingAdmin();
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
context,
faceStatusUtils.getTitle(),
faceStatusUtils.getSummary(),
- createPendingIntent(
+ BiometricSourcesUtils.createPendingIntent(
profileParentContext,
biometricNavigationUtils
.getBiometricSettingsIntent(
@@ -152,18 +146,19 @@
return;
}
- final FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
- final FingerprintStatusUtils fingerprintStatusUtils =
+ FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
+ FingerprintStatusUtils fingerprintStatusUtils =
new FingerprintStatusUtils(context, fingerprintManager, userId);
if (fingerprintStatusUtils.isAvailable()) {
- final RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin =
fingerprintStatusUtils.getDisablingAdmin();
- setBiometricSafetySourceData(
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
context,
fingerprintStatusUtils.getTitle(),
fingerprintStatusUtils.getSummary(),
- createPendingIntent(
+ BiometricSourcesUtils.createPendingIntent(
profileParentContext,
biometricNavigationUtils
.getBiometricSettingsIntent(
@@ -191,35 +186,4 @@
new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
.build());
}
-
- private static void setBiometricSafetySourceData(
- Context context,
- String title,
- String summary,
- PendingIntent pendingIntent,
- boolean enabled,
- boolean hasEnrolled,
- SafetyEvent safetyEvent) {
- final int severityLevel =
- enabled && hasEnrolled
- ? SafetySourceData.SEVERITY_LEVEL_INFORMATION
- : SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
-
- final SafetySourceStatus status =
- new SafetySourceStatus.Builder(title, summary, severityLevel)
- .setPendingIntent(pendingIntent)
- .setEnabled(enabled)
- .build();
- final SafetySourceData safetySourceData =
- new SafetySourceData.Builder().setStatus(status).build();
-
- SafetyCenterManagerWrapper.get()
- .setSafetySourceData(context, SAFETY_SOURCE_ID, safetySourceData, safetyEvent);
- }
-
- private static PendingIntent createPendingIntent(
- Context context, Intent intent, int requestCode) {
- return PendingIntent.getActivity(
- context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);
- }
}
diff --git a/src/com/android/settings/safetycenter/FaceSafetySource.java b/src/com/android/settings/safetycenter/FaceSafetySource.java
new file mode 100644
index 0000000..a945bc0
--- /dev/null
+++ b/src/com/android/settings/safetycenter/FaceSafetySource.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_FACE_SETTING;
+
+import android.content.Context;
+import android.hardware.face.FaceManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.safetycenter.SafetyEvent;
+
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricNavigationUtils;
+import com.android.settings.biometrics.face.FaceStatusUtils;
+import com.android.settingslib.RestrictedLockUtils;
+
+/** Face biometrics Safety Source for Safety Center. */
+public final class FaceSafetySource {
+
+ public static final String SAFETY_SOURCE_ID = "AndroidFaceUnlock";
+
+ private FaceSafetySource() {}
+
+ /** Sets biometric safety data for Safety Center. */
+ public static void setSafetySourceData(Context context, SafetyEvent safetyEvent) {
+ if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ return;
+ }
+
+ // Handle private profile case
+ UserManager userManager = UserManager.get(context);
+ if (android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enablePrivateSpaceFeatures()
+ && userManager.isPrivateProfile()) {
+ // SC always expects a response from the source if the broadcast has been sent for this
+ // source, therefore, we need to send a null SafetySourceData.
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
+ return;
+ }
+
+ UserHandle userHandle = Process.myUserHandle();
+ int userId = userHandle.getIdentifier();
+ FaceManager faceManager = Utils.getFaceManagerOrNull(context);
+ FaceStatusUtils faceStatusUtils = new FaceStatusUtils(context, faceManager, userId);
+ BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils(userId);
+ UserHandle profileParentUserHandle = userManager.getProfileParent(userHandle);
+ if (profileParentUserHandle == null) {
+ profileParentUserHandle = userHandle;
+ }
+ Context profileParentContext = context.createContextAsUser(profileParentUserHandle, 0);
+
+ if (Utils.hasFaceHardware(context)) {
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin = faceStatusUtils.getDisablingAdmin();
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
+ context,
+ faceStatusUtils.getTitle(),
+ faceStatusUtils.getSummary(),
+ BiometricSourcesUtils.createPendingIntent(
+ profileParentContext,
+ biometricNavigationUtils
+ .getBiometricSettingsIntent(
+ context,
+ faceStatusUtils.getSettingsClassName(),
+ disablingAdmin,
+ Bundle.EMPTY)
+ .setIdentifier(Integer.toString(userId)),
+ REQUEST_CODE_FACE_SETTING),
+ disablingAdmin == null /* enabled */,
+ faceStatusUtils.hasEnrolled(),
+ safetyEvent);
+
+ return;
+ }
+
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
+ }
+
+ /** Notifies Safety Center of a change in face biometrics settings. */
+ public static void onBiometricsChanged(Context context) {
+ setSafetySourceData(
+ context,
+ new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build());
+ }
+}
diff --git a/src/com/android/settings/safetycenter/FingerprintSafetySource.java b/src/com/android/settings/safetycenter/FingerprintSafetySource.java
new file mode 100644
index 0000000..9d5d3b7
--- /dev/null
+++ b/src/com/android/settings/safetycenter/FingerprintSafetySource.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+import static com.android.settings.safetycenter.BiometricSourcesUtils.REQUEST_CODE_FINGERPRINT_SETTING;
+
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.safetycenter.SafetyEvent;
+
+import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricNavigationUtils;
+import com.android.settings.biometrics.fingerprint.FingerprintStatusUtils;
+import com.android.settingslib.RestrictedLockUtils;
+
+/** Fingerprint biometrics Safety Source for Safety Center. */
+public final class FingerprintSafetySource {
+
+ public static final String SAFETY_SOURCE_ID = "AndroidFingerprintUnlock";
+
+ private FingerprintSafetySource() {}
+
+ /** Sets biometric safety data for Safety Center. */
+ public static void setSafetySourceData(Context context, SafetyEvent safetyEvent) {
+ if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ return;
+ }
+
+ // Handle private profile case
+ UserManager userManager = UserManager.get(context);
+ if (android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enablePrivateSpaceFeatures()
+ && userManager.isPrivateProfile()) {
+ // SC always expects a response from the source if the broadcast has been sent for this
+ // source, therefore, we need to send a null SafetySourceData.
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
+ return;
+ }
+
+ UserHandle userHandle = Process.myUserHandle();
+ int userId = userHandle.getIdentifier();
+ FingerprintManager fingerprintManager = Utils.getFingerprintManagerOrNull(context);
+ FingerprintStatusUtils fingerprintStatusUtils =
+ new FingerprintStatusUtils(context, fingerprintManager, userId);
+ BiometricNavigationUtils biometricNavigationUtils = new BiometricNavigationUtils(userId);
+ UserHandle profileParentUserHandle = userManager.getProfileParent(userHandle);
+ if (profileParentUserHandle == null) {
+ profileParentUserHandle = userHandle;
+ }
+ Context profileParentContext = context.createContextAsUser(profileParentUserHandle, 0);
+
+ if (Utils.hasFingerprintHardware(context)) {
+ RestrictedLockUtils.EnforcedAdmin disablingAdmin =
+ fingerprintStatusUtils.getDisablingAdmin();
+ BiometricSourcesUtils.setBiometricSafetySourceData(
+ SAFETY_SOURCE_ID,
+ context,
+ fingerprintStatusUtils.getTitle(),
+ fingerprintStatusUtils.getSummary(),
+ BiometricSourcesUtils.createPendingIntent(
+ profileParentContext,
+ biometricNavigationUtils
+ .getBiometricSettingsIntent(
+ context,
+ fingerprintStatusUtils.getSettingsClassName(),
+ disablingAdmin,
+ Bundle.EMPTY)
+ .setIdentifier(Integer.toString(userId)),
+ REQUEST_CODE_FINGERPRINT_SETTING),
+ disablingAdmin == null /* enabled */,
+ fingerprintStatusUtils.hasEnrolled(),
+ safetyEvent);
+ return;
+ }
+
+ SafetyCenterManagerWrapper.get()
+ .setSafetySourceData(
+ context, SAFETY_SOURCE_ID, /* safetySourceData= */ null, safetyEvent);
+ }
+
+ /** Notifies Safety Center of a change in fingerprint biometrics settings. */
+ public static void onBiometricsChanged(Context context) {
+ setSafetySourceData(
+ context,
+ new SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED)
+ .build());
+ }
+}
diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
index 6960fc6..14ad268 100644
--- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java
+++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java
@@ -31,6 +31,7 @@
import android.safetycenter.SafetySourceStatus.IconAction;
import com.android.settings.R;
+import com.android.settings.flags.Flags;
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -122,7 +123,12 @@
// Also send refreshed safety center data for biometrics, since changing lockscreen settings
// can unset biometrics.
- BiometricsSafetySource.onBiometricsChanged(context);
+ if (Flags.biometricsOnboardingEducation()) {
+ FaceSafetySource.onBiometricsChanged(context);
+ FingerprintSafetySource.onBiometricsChanged(context);
+ } else {
+ BiometricsSafetySource.onBiometricsChanged(context);
+ }
}
private static IconAction createGearMenuIconAction(
diff --git a/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java b/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java
index cc0f892..992c0ec 100644
--- a/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java
+++ b/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java
@@ -28,6 +28,7 @@
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
+import com.android.settings.flags.Flags;
import com.android.settings.privatespace.PrivateSpaceSafetySource;
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
@@ -48,48 +49,60 @@
}
if (ACTION_REFRESH_SAFETY_SOURCES.equals(intent.getAction())) {
- String[] sourceIdsExtra =
- intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
- final String refreshBroadcastId = intent.getStringExtra(
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
+ String[] sourceIdsExtra = intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
+ final String refreshBroadcastId =
+ intent.getStringExtra(
+ SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
if (sourceIdsExtra != null && sourceIdsExtra.length > 0 && refreshBroadcastId != null) {
- final SafetyEvent safetyEvent = new SafetyEvent.Builder(
- SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(refreshBroadcastId).build();
- refreshSafetySources(
- context,
- ImmutableList.copyOf(sourceIdsExtra),
- safetyEvent);
+ final SafetyEvent safetyEvent =
+ new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
+ .setRefreshBroadcastId(refreshBroadcastId)
+ .build();
+ refreshSafetySources(context, ImmutableList.copyOf(sourceIdsExtra), safetyEvent);
}
return;
}
-
if (ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
refreshAllSafetySources(context, EVENT_DEVICE_REBOOTED);
}
}
- private static void refreshSafetySources(Context context, List<String> sourceIds,
- SafetyEvent safetyEvent) {
+ private static void refreshSafetySources(
+ Context context, List<String> sourceIds, SafetyEvent safetyEvent) {
if (sourceIds.contains(LockScreenSafetySource.SAFETY_SOURCE_ID)) {
- LockScreenSafetySource.setSafetySourceData(context,
- new ScreenLockPreferenceDetailsUtils(context), safetyEvent);
+ LockScreenSafetySource.setSafetySourceData(
+ context, new ScreenLockPreferenceDetailsUtils(context), safetyEvent);
}
- if (sourceIds.contains(BiometricsSafetySource.SAFETY_SOURCE_ID)) {
+ if (sourceIds.contains(BiometricsSafetySource.SAFETY_SOURCE_ID)
+ && !Flags.biometricsOnboardingEducation()) {
BiometricsSafetySource.setSafetySourceData(context, safetyEvent);
}
if (sourceIds.contains(PrivateSpaceSafetySource.SAFETY_SOURCE_ID)) {
PrivateSpaceSafetySource.setSafetySourceData(context, safetyEvent);
}
+ if (sourceIds.contains(FaceSafetySource.SAFETY_SOURCE_ID)
+ && Flags.biometricsOnboardingEducation()) {
+ FaceSafetySource.setSafetySourceData(context, safetyEvent);
+ }
+ if (sourceIds.contains(FingerprintSafetySource.SAFETY_SOURCE_ID)
+ && Flags.biometricsOnboardingEducation()) {
+ FingerprintSafetySource.setSafetySourceData(context, safetyEvent);
+ }
}
private static void refreshAllSafetySources(Context context, SafetyEvent safetyEvent) {
- LockScreenSafetySource.setSafetySourceData(context,
- new ScreenLockPreferenceDetailsUtils(context), safetyEvent);
- BiometricsSafetySource.setSafetySourceData(context, safetyEvent);
+ LockScreenSafetySource.setSafetySourceData(
+ context, new ScreenLockPreferenceDetailsUtils(context), safetyEvent);
+ if (!Flags.biometricsOnboardingEducation()) {
+ BiometricsSafetySource.setSafetySourceData(context, safetyEvent);
+ }
PrivateSpaceSafetySource.setSafetySourceData(context, safetyEvent);
+ if (Flags.biometricsOnboardingEducation()) {
+ FaceSafetySource.setSafetySourceData(context, safetyEvent);
+ FingerprintSafetySource.setSafetySourceData(context, safetyEvent);
+ }
}
}
diff --git a/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt b/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
index f25d20c..b0f9d0d 100644
--- a/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
+++ b/src/com/android/settings/service/PreferenceServiceRequestTransformer.kt
@@ -25,7 +25,6 @@
import android.service.settings.preferences.SetValueResult
import android.service.settings.preferences.SettingsPreferenceMetadata
import android.service.settings.preferences.SettingsPreferenceValue
-import com.android.settingslib.graph.PreferenceCoordinate
import com.android.settingslib.graph.PreferenceGetterErrorCode
import com.android.settingslib.graph.PreferenceGetterFlags
import com.android.settingslib.graph.PreferenceGetterRequest
@@ -40,6 +39,7 @@
import com.android.settingslib.graph.proto.PreferenceProto
import com.android.settingslib.graph.proto.PreferenceValueProto
import com.android.settingslib.graph.toIntent
+import com.android.settingslib.metadata.PreferenceCoordinate
import com.android.settingslib.metadata.SensitivityLevel
/** Transform Catalyst Graph result to Framework GET METADATA result */
diff --git a/src/com/android/settings/spa/app/storage/StorageAppList.kt b/src/com/android/settings/spa/app/storage/StorageAppList.kt
index c33de33..be145e0 100644
--- a/src/com/android/settings/spa/app/storage/StorageAppList.kt
+++ b/src/com/android/settings/spa/app/storage/StorageAppList.kt
@@ -34,12 +34,12 @@
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.AppStorageRepositoryImpl
import com.android.settingslib.spaprivileged.template.app.AppList
import com.android.settingslib.spaprivileged.template.app.AppListInput
import com.android.settingslib.spaprivileged.template.app.AppListItem
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
import com.android.settingslib.spaprivileged.template.app.AppListPage
-import com.android.settingslib.spaprivileged.template.app.calculateSizeBytes
import com.android.settingslib.spaprivileged.template.app.getStorageSize
import kotlinx.coroutines.flow.Flow
@@ -109,9 +109,11 @@
getStorageSize()
}
) : AppListModel<AppRecordWithSize> {
+ private val appStorageRepository = AppStorageRepositoryImpl(context)
+
override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
- appListFlow.mapItem {
- AppRecordWithSize(it, it.calculateSizeBytes(context) ?: 0L)
+ appListFlow.mapItem { app ->
+ AppRecordWithSize(app, appStorageRepository.calculateSizeBytes(app) ?: 0L)
}
override fun filter(
diff --git a/src/com/android/settings/tts/OWNERS b/src/com/android/settings/tts/OWNERS
index 7ba7dc1..0fbf340 100644
--- a/src/com/android/settings/tts/OWNERS
+++ b/src/com/android/settings/tts/OWNERS
@@ -1,2 +1,5 @@
# Default reviewers for this and subdirectories.
-rni@google.com
+adudani@google.com
+chitturu@google.com
+jamesodonnell@google.com
+joshimbriani@google.com
diff --git a/src/com/android/settings/vpn2/OWNERS b/src/com/android/settings/vpn2/OWNERS
index 4135645..919c56e 100644
--- a/src/com/android/settings/vpn2/OWNERS
+++ b/src/com/android/settings/vpn2/OWNERS
@@ -1,13 +1,7 @@
# People who can approve changes for submission.
-jchalard@google.com
-lorenzo@google.com
-maze@google.com
-reminv@google.com
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking_xts
xiaom@google.com
hughchen@google.com
robertluo@google.com
timhypeng@google.com
vincentwei@google.com
-
-# Emergency approvers in case the above are not available
-satk@google.com
diff --git a/src/com/android/settings/widget/MainSwitchBarMetadata.kt b/src/com/android/settings/widget/MainSwitchBarMetadata.kt
index f55cfd0..4fc89bc 100644
--- a/src/com/android/settings/widget/MainSwitchBarMetadata.kt
+++ b/src/com/android/settings/widget/MainSwitchBarMetadata.kt
@@ -27,6 +27,16 @@
interface MainSwitchBarMetadata :
TwoStatePreference, TwoStatePreferenceBinding, PreferenceBindingPlaceholder {
+ /**
+ * Disable main switch bar when user toggles the switch. By this way, user cannot toggle again
+ * before last operation is done.
+ *
+ * Side-effect: If the underlying operation is completed quickly, this will causes UI flicker.
+ * Override and return `false` to get rid of the flicker.
+ */
+ val disableWidgetOnCheckedChanged: Boolean
+ get() = true
+
override fun createWidget(context: Context) = MainSwitchBarPreference(context, this)
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
diff --git a/src/com/android/settings/widget/MainSwitchBarPreference.kt b/src/com/android/settings/widget/MainSwitchBarPreference.kt
index b3b341c..a23409a 100644
--- a/src/com/android/settings/widget/MainSwitchBarPreference.kt
+++ b/src/com/android/settings/widget/MainSwitchBarPreference.kt
@@ -80,7 +80,7 @@
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
// prevent user from toggling the switch before data store operation is done
- isEnabled = false
+ if (metadata.disableWidgetOnCheckedChanged) isEnabled = false
// once data store is updated, isEnabled will be reset due to rebind
persistBoolean(isChecked)
}
diff --git a/src/com/android/settings/wifi/WifiSwitchPreference.kt b/src/com/android/settings/wifi/WifiSwitchPreference.kt
index 627a78b..2b2b344 100644
--- a/src/com/android/settings/wifi/WifiSwitchPreference.kt
+++ b/src/com/android/settings/wifi/WifiSwitchPreference.kt
@@ -17,6 +17,8 @@
package com.android.settings.wifi
import android.Manifest
+import android.app.settings.SettingsEnums.ACTION_WIFI_OFF
+import android.app.settings.SettingsEnums.ACTION_WIFI_ON
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@@ -31,14 +33,16 @@
import com.android.settings.R
import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
import com.android.settings.network.SatelliteWarningDialogActivity
+import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
+import com.android.settings.wifi.utils.isDefaultNetworkWifi
import com.android.settings.wifi.utils.isWifiEnabled
import com.android.settings.wifi.utils.wifiManager
import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.WirelessUtils
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.Permissions
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ReadWritePermit
@@ -137,8 +141,15 @@
context.isWifiEnabled as T?
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
- if (value is Boolean) {
- context.isWifiEnabled = value
+ if (value !is Boolean) return
+
+ context.isWifiEnabled = value
+
+ val metricsFeature = featureFactory.metricsFeatureProvider
+ if (value) {
+ metricsFeature.action(context, ACTION_WIFI_ON)
+ } else {
+ metricsFeature.action(context, ACTION_WIFI_OFF, context.isDefaultNetworkWifi)
}
}
@@ -152,7 +163,7 @@
wifiState == WifiManager.WIFI_STATE_ENABLED ||
wifiState == WifiManager.WIFI_STATE_DISABLED
) {
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.VALUE)
}
}
}
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSwitchPreference.kt b/src/com/android/settings/wifi/tether/WifiHotspotSwitchPreference.kt
index c93099e..3877a02 100644
--- a/src/com/android/settings/wifi/tether/WifiHotspotSwitchPreference.kt
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSwitchPreference.kt
@@ -32,7 +32,6 @@
import com.android.settings.R
import com.android.settings.Utils
import com.android.settings.core.SubSettingLauncher
-import com.android.settings.datausage.DataSaverMainSwitchPreference.Companion.KEY as DATA_SAVER_KEY
import com.android.settings.wifi.WifiUtils.canShowWifiHotspot
import com.android.settings.wifi.utils.tetheringManager
import com.android.settings.wifi.utils.wifiApState
@@ -41,12 +40,12 @@
import com.android.settingslib.PrimarySwitchPreference
import com.android.settingslib.TetherUtil
import com.android.settingslib.datastore.AbstractKeyedDataObservable
-import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyedObserver
import com.android.settingslib.datastore.Permissions
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.PreferenceChangeReason
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ReadWritePermit
@@ -54,6 +53,7 @@
import com.android.settingslib.metadata.SwitchPreference
import com.android.settingslib.preference.PreferenceBinding
import com.android.settingslib.wifi.WifiUtils.Companion.getWifiTetherSummaryForConnectedDevices
+import com.android.settings.datausage.DataSaverMainSwitchPreference.Companion.KEY as DATA_SAVER_KEY
// LINT.IfChange
class WifiHotspotSwitchPreference(context: Context, dataSaverStore: KeyValueStore) :
@@ -186,13 +186,13 @@
Log.d(TAG, "onStateChanged(),state=$state,failureReason=$failureReason")
sapFailureReason = failureReason
if (state == WifiManager.WIFI_AP_STATE_DISABLED) sapClientsSize = null
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.VALUE)
}
override fun onConnectedClientsChanged(clients: List<WifiClient>?) {
sapClientsSize = clients?.size ?: 0
Log.d(TAG, "onConnectedClientsChanged(),sapClientsSize=$sapClientsSize")
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, PreferenceChangeReason.STATE)
}
override fun onTetheringStarted() {}
@@ -202,7 +202,7 @@
}
override fun onKeyChanged(key: String, reason: Int) =
- notifyChange(KEY, DataChangeReason.UPDATE)
+ notifyChange(KEY, reason)
}
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
diff --git a/src/com/android/settings/wifi/utils/Contexts.kt b/src/com/android/settings/wifi/utils/Contexts.kt
index 42a6b98..bd8ecaa 100644
--- a/src/com/android/settings/wifi/utils/Contexts.kt
+++ b/src/com/android/settings/wifi/utils/Contexts.kt
@@ -19,6 +19,8 @@
package com.android.settings.wifi.utils
import android.content.Context
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
import android.net.TetheringManager
import android.net.wifi.WifiManager
@@ -52,3 +54,18 @@
*/
val Context.tetheringManager: TetheringManager?
get() = applicationContext.getSystemService(TetheringManager::class.java)
+
+/**
+ * Gets the {@link android.net.ConnectivityManager} system service.
+ *
+ * Use application context to get system services to avoid memory leaks.
+ */
+val Context.connectivityManager: ConnectivityManager?
+ get() = applicationContext.getSystemService(ConnectivityManager::class.java)
+
+/** Return true if the default network is a Wi-Fi network */
+val Context.isDefaultNetworkWifi: Boolean
+ get() =
+ connectivityManager
+ ?.getNetworkCapabilities(connectivityManager?.activeNetwork)
+ ?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index c70ffcd..935c687 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -103,8 +103,6 @@
"SettingsLib-search",
],
- upstream: true,
-
strict_mode: false,
}
@@ -115,7 +113,7 @@
"testutils/**/*.kt",
],
libs: [
- "Robolectric_all-target_upstream",
+ "Robolectric_all-target",
"Settings-core",
"mockito-robolectric-prebuilt",
"truth",
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 9315995..91d7d91 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -503,9 +503,8 @@
}
private String getPreferenceCategory(ComponentName componentName) {
- return mFragment.mServicePreferenceToPreferenceCategoryMap.get(
- mFragment.getPreferenceScreen().findPreference(
- componentName.flattenToString())).getKey();
+ return mFragment.getPreferenceScreen().findPreference(
+ componentName.flattenToString()).getParent().getKey();
}
private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceControllerTest.java
new file mode 100644
index 0000000..389e127
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationFeedbackPreferenceControllerTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.android.settings.accessibility.MagnificationFeedbackPreferenceController.FEEDBACK_KEY;
+import static com.android.settings.accessibility.MagnificationFeedbackPreferenceController.PREF_KEY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.core.util.Consumer;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.SurveyFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link MagnificationFeedbackPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class MagnificationFeedbackPreferenceControllerTest {
+
+ @Rule
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock private PreferenceScreen mScreen;
+ @Mock private PreferenceManager mPreferenceManager;
+ @Mock private DashboardFragment mFragment;
+ private SurveyFeatureProvider mSurveyFeatureProvider;
+ private MagnificationFeedbackPreferenceController mController;
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ FakeFeatureFactory.setupForTest();
+ mSurveyFeatureProvider =
+ FakeFeatureFactory.getFeatureFactory().getSurveyFeatureProvider(mContext);
+ mController = new MagnificationFeedbackPreferenceController(mContext, mFragment, PREF_KEY);
+ mPreference = new Preference(mContext);
+ when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
+ when(mPreferenceManager.findPreference(PREF_KEY)).thenReturn(mPreference);
+ when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
+ }
+
+ @Test
+ public void getAvailabilityStatus_shouldAlwaysBeAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ MagnificationFeedbackPreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void updateState_surveyAvailable_preferenceEnabledWithSummary() {
+ doAnswer(invocation -> {
+ Consumer<Boolean> consumer = invocation.getArgument(2);
+ consumer.accept(true);
+ return null;
+ }).when(mSurveyFeatureProvider).checkSurveyAvailable(any(), eq(FEEDBACK_KEY), any());
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.getSummary()).isEqualTo(
+ mContext.getString(R.string.accessibility_feedback_summary));
+ }
+
+ @Test
+ public void updateState_surveyUnavailable_preferenceDisabledWithSummary() {
+ doAnswer(invocation -> {
+ Consumer<Boolean> consumer = invocation.getArgument(2);
+ consumer.accept(false);
+ return null;
+ }).when(mSurveyFeatureProvider).checkSurveyAvailable(any(), eq(FEEDBACK_KEY), any());
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.getSummary()).isEqualTo(
+ mContext.getString(R.string.accessibility_feedback_disabled_summary));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_shouldStartSurvey() {
+ mController.handlePreferenceTreeClick(mPreference);
+
+ verify(mSurveyFeatureProvider).sendActivityIfAvailable(FEEDBACK_KEY);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeControllerTest.java
index 0a22e4a..f67053d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickCursorAreaSizeControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.accessibility;
+import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_MAX;
+import static android.view.accessibility.AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_MIN;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -32,9 +35,11 @@
import android.provider.Settings;
import android.view.accessibility.AccessibilityManager;
+import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.SliderPreference;
import com.google.common.collect.ImmutableList;
@@ -106,21 +111,74 @@
}
@Test
- public void getProgress_matchesSetting() {
- assertThat(mController.getSliderPosition()).isEqualTo(readSetting());
+ public void getProgress_matchesSetting_inRangeValue() {
+ // TODO(388844952): Use parameter testing.
+ for (int size : ImmutableList.of(20, 40, 60, 80, 100)) {
+ updateSetting(size);
+
+ assertThat(mController.getSliderPosition()).isEqualTo(size);
+ }
}
@Test
- public void setProgress_updatesSetting() {
- for (int size : ImmutableList.of(20, 40, 60, 80, 100)) {
- mController.setSliderPosition(size);
- assertThat(readSetting()).isEqualTo(size);
+ public void getProgress_matchesSetting_aboveMaxValue() {
+ updateSetting(120);
+
+ assertThat(mController.getSliderPosition()).isEqualTo(AUTOCLICK_CURSOR_AREA_SIZE_MAX);
+ }
+
+ @Test
+ public void getProgress_matchesSetting_belowMinValue() {
+ updateSetting(0);
+
+ assertThat(mController.getSliderPosition()).isEqualTo(AUTOCLICK_CURSOR_AREA_SIZE_MIN);
+ }
+
+ @Test
+ public void setProgress_updatesSetting_inRangeValue() {
+ // TODO(388844952): Use parameter testing.
+ for (int position : ImmutableList.of(20, 40, 60, 80, 100)) {
+ mController.setSliderPosition(position);
+
+ assertThat(readSetting()).isEqualTo(position);
}
}
+ @Test
+ public void setProgress_updatesSetting_aboveMaxValue() {
+ mController.setSliderPosition(120);
+
+ assertThat(readSetting()).isEqualTo(AUTOCLICK_CURSOR_AREA_SIZE_MAX);
+ }
+
+ @Test
+ public void setProgress_updatesSetting_belowMinValue() {
+ mController.setSliderPosition(0);
+
+ assertThat(readSetting()).isEqualTo(AUTOCLICK_CURSOR_AREA_SIZE_MIN);
+ }
+
+ @Test
+ public void sliderPreference_setCorrectInitialValue() {
+ SliderPreference preference = mock(SliderPreference.class);
+ PreferenceScreen screen = mock(PreferenceScreen.class);
+ doReturn(preference).when(screen).findPreference(anyString());
+
+ mController.displayPreference(screen);
+
+ verify(preference).setValue(mController.getSliderPosition());
+ }
+
private int readSetting() {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
AccessibilityManager.AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT);
}
+
+ private void updateSetting(int value) {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE,
+ value);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementControllerTest.java
new file mode 100644
index 0000000..889b732
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleAutoclickIgnoreMinorCursorMovementControllerTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link ToggleAutoclickIgnoreMinorCursorMovementController}. */
+@RunWith(RobolectricTestRunner.class)
+public class ToggleAutoclickIgnoreMinorCursorMovementControllerTest {
+
+ private static final String PREFERENCE_KEY =
+ "accessibility_control_autoclick_ignore_minor_cursor_movement";
+
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private ToggleAutoclickIgnoreMinorCursorMovementController mController;
+
+ @Before
+ public void setUp() {
+ mController =
+ new ToggleAutoclickIgnoreMinorCursorMovementController(mContext, PREFERENCE_KEY);
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void getAvailabilityStatus_availableWhenFlagOn() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR)
+ public void getAvailabilityStatus_conditionallyUnavailableWhenFlagOn() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
index 0b38594..863452f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
@@ -337,6 +337,26 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_HATS)
+ public void onResume_enableLowVisionHaTS_feedbackPreferenceShouldReturnNotNull() {
+ mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
+
+ final Preference feedbackPreference = mFragController.get().findPreference(
+ MagnificationFeedbackPreferenceController.PREF_KEY);
+ assertThat(feedbackPreference).isNotNull();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_LOW_VISION_HATS)
+ public void onResume_disableLowVisionHaTS_feedbackPreferenceShouldReturnNull() {
+ mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
+
+ final Preference feedbackPreference = mFragController.get().findPreference(
+ MagnificationFeedbackPreferenceController.PREF_KEY);
+ assertThat(feedbackPreference).isNull();
+ }
+
+ @Test
public void onResume_haveRegisterToSpecificUris() {
ShadowContentResolver shadowContentResolver = Shadows.shadowOf(
mContext.getContentResolver());
@@ -893,13 +913,14 @@
@Test
@EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
public void getRawDataToIndex_returnsAllPreferenceKeys() {
- List<String> expectedSearchKeys = List.of(
+ final List<String> expectedSearchKeys = List.of(
KEY_MAGNIFICATION_SHORTCUT_PREFERENCE,
MagnificationModePreferenceController.PREF_KEY,
MagnificationFollowTypingPreferenceController.PREF_KEY,
MagnificationOneFingerPanningPreferenceController.PREF_KEY,
MagnificationAlwaysOnPreferenceController.PREF_KEY,
- MagnificationJoystickPreferenceController.PREF_KEY);
+ MagnificationJoystickPreferenceController.PREF_KEY,
+ MagnificationFeedbackPreferenceController.PREF_KEY);
final List<SearchIndexableRaw> rawData = ToggleScreenMagnificationPreferenceFragment
.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true);
@@ -910,8 +931,7 @@
@Test
@EnableFlags(com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH)
- public void
- getNonIndexableKeys_windowMagnificationNotSupported_onlyShortcutPreferenceSearchable() {
+ public void getNonIndexableKeys_windowMagnificationNotSupported_onlyShortcutSearchable() {
setWindowMagnificationSupported(false, false);
final List<String> niks = ToggleScreenMagnificationPreferenceFragment
@@ -920,7 +940,8 @@
.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true);
// Expect all search data, except the shortcut preference, to be in NIKs.
final List<String> expectedNiks = rawData.stream().map(raw -> raw.key)
- .filter(key -> !key.equals(KEY_MAGNIFICATION_SHORTCUT_PREFERENCE)).toList();
+ .filter(key -> !key.equals(KEY_MAGNIFICATION_SHORTCUT_PREFERENCE))
+ .toList();
// In NonIndexableKeys == not searchable
assertThat(niks).containsExactlyElementsIn(expectedNiks);
@@ -929,7 +950,32 @@
@Test
@EnableFlags({
com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH,
- Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE})
+ Flags.FLAG_ENABLE_LOW_VISION_HATS})
+ public void
+ getNonIndexableKeys_windowMagnificationNotSupportedHatsOn_shortcutFeedbackSearchable() {
+ setWindowMagnificationSupported(false, false);
+
+ final List<String> niks = ToggleScreenMagnificationPreferenceFragment
+ .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+ final List<SearchIndexableRaw> rawData = ToggleScreenMagnificationPreferenceFragment
+ .SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(mContext, true);
+ // Expect all search data, except the shortcut preference and feedback preference, to be in
+ // NIKs.
+ final List<String> expectedNiks = rawData.stream().map(raw -> raw.key)
+ .filter(key ->
+ !key.equals(KEY_MAGNIFICATION_SHORTCUT_PREFERENCE)
+ && !key.equals(MagnificationFeedbackPreferenceController.PREF_KEY))
+ .toList();
+
+ // In NonIndexableKeys == not searchable
+ assertThat(niks).containsExactlyElementsIn(expectedNiks);
+ }
+
+ @Test
+ @EnableFlags({
+ com.android.settings.accessibility.Flags.FLAG_FIX_A11Y_SETTINGS_SEARCH,
+ Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE,
+ Flags.FLAG_ENABLE_LOW_VISION_HATS})
public void getNonIndexableKeys_hasShortcutAndAllFeaturesEnabled_allItemsSearchable() {
setMagnificationTripleTapEnabled(true);
setAlwaysOnSupported(true);
@@ -991,6 +1037,16 @@
assertThat(niks).contains(MagnificationJoystickPreferenceController.PREF_KEY);
}
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_LOW_VISION_HATS)
+ public void getNonIndexableKeys_hatsNotSupported_notSearchable() {
+ final List<String> niks = ToggleScreenMagnificationPreferenceFragment
+ .SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+ // In NonIndexableKeys == not searchable
+ assertThat(niks).contains(MagnificationFeedbackPreferenceController.PREF_KEY);
+ }
+
private void putStringIntoSettings(String key, String componentName) {
Settings.Secure.putString(mContext.getContentResolver(), key, componentName);
}
diff --git a/tests/robotests/src/com/android/settings/applications/AppStorageSizesControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppStorageSizesControllerTest.java
index 49d4aac..bd2579e 100644
--- a/tests/robotests/src/com/android/settings/applications/AppStorageSizesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppStorageSizesControllerTest.java
@@ -83,10 +83,10 @@
mController.setResult(result);
mController.updateUi(mContext);
- assertThat(mAppPreference.getSummary()).isEqualTo("1 B");
- assertThat(mCachePreference.getSummary()).isEqualTo("10 B");
- assertThat(mDataPreference.getSummary()).isEqualTo("90 B");
- assertThat(mTotalPreference.getSummary()).isEqualTo("101 B");
+ assertThat(mAppPreference.getSummary()).isEqualTo("1 byte");
+ assertThat(mCachePreference.getSummary()).isEqualTo("10 byte");
+ assertThat(mDataPreference.getSummary()).isEqualTo("90 byte");
+ assertThat(mTotalPreference.getSummary()).isEqualTo("101 byte");
}
@Test
@@ -101,10 +101,10 @@
mController.setCacheCleared(true);
mController.updateUi(mContext);
- assertThat(mAppPreference.getSummary()).isEqualTo("1 B");
- assertThat(mCachePreference.getSummary()).isEqualTo("0 B");
- assertThat(mDataPreference.getSummary()).isEqualTo("90 B");
- assertThat(mTotalPreference.getSummary()).isEqualTo("91 B");
+ assertThat(mAppPreference.getSummary()).isEqualTo("1 byte");
+ assertThat(mCachePreference.getSummary()).isEqualTo("0 byte");
+ assertThat(mDataPreference.getSummary()).isEqualTo("90 byte");
+ assertThat(mTotalPreference.getSummary()).isEqualTo("91 byte");
}
@Test
@@ -119,9 +119,9 @@
mController.setDataCleared(true);
mController.updateUi(mContext);
- assertThat(mAppPreference.getSummary()).isEqualTo("1 B");
- assertThat(mCachePreference.getSummary()).isEqualTo("0 B");
- assertThat(mDataPreference.getSummary()).isEqualTo("0 B");
- assertThat(mTotalPreference.getSummary()).isEqualTo("1 B");
+ assertThat(mAppPreference.getSummary()).isEqualTo("1 byte");
+ assertThat(mCachePreference.getSummary()).isEqualTo("0 byte");
+ assertThat(mDataPreference.getSummary()).isEqualTo("0 byte");
+ assertThat(mTotalPreference.getSummary()).isEqualTo("1 byte");
}
}
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
index 4fb0c05..b62430d 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppStatsMixinTest.java
@@ -38,12 +38,16 @@
import android.os.PowerManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -88,6 +92,9 @@
private RecentAppStatsMixin mRecentAppStatsMixin;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
@@ -255,6 +262,59 @@
}
@Test
+ @EnableFlags({android.content.pm.Flags.FLAG_REMOVE_HIDDEN_MODULE_USAGE})
+ public void loadDisplayableRecentApps_twoSystemModulesSet_shouldHaveTwoSystemModules() {
+ final List<UsageStats> stats = new ArrayList<>();
+
+ // System modules.
+ final UsageStats stat1 = new UsageStats();
+ stat1.mLastTimeUsed = System.currentTimeMillis();
+ stat1.mPackageName = "com.foo.module1";
+ stats.add(stat1);
+
+ final UsageStats stat2 = new UsageStats();
+ stat2.mLastTimeUsed = System.currentTimeMillis() + 200;
+ stat2.mPackageName = "com.foo.module2";
+ stats.add(stat2);
+
+ ApplicationsState.AppEntry stat1Entry = mock(ApplicationsState.AppEntry.class);
+ ApplicationsState.AppEntry stat2Entry = mock(ApplicationsState.AppEntry.class);
+ stat1Entry.info = mApplicationInfo;
+ stat2Entry.info = mApplicationInfo;
+
+ when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())).thenReturn(stat1Entry);
+ when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId())).thenReturn(stat2Entry);
+
+ // Hidden status set to false and true, but they should not cause the difference in
+ // the behavior.
+ final ModuleInfo moduleInfo1 = new ModuleInfo();
+ moduleInfo1.setPackageName(stat1.mPackageName);
+ moduleInfo1.setHidden(false);
+
+ final ModuleInfo moduleInfo2 = new ModuleInfo();
+ moduleInfo2.setPackageName(stat2.mPackageName);
+ moduleInfo2.setHidden(true);
+
+ ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", null);
+ final List<ModuleInfo> modules = new ArrayList<>();
+ modules.add(moduleInfo1);
+ modules.add(moduleInfo2);
+ when(mPackageManager.getInstalledModules(anyInt() /* flags */))
+ .thenReturn(modules);
+
+ when(mPackageManager.resolveActivityAsUser(any(Intent.class), anyInt(), anyInt()))
+ .thenReturn(new ResolveInfo());
+ when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+ .thenReturn(stats);
+
+ mRecentAppStatsMixin.loadDisplayableRecentApps(3);
+
+ assertThat(mRecentAppStatsMixin.mRecentApps.size()).isEqualTo(2);
+ }
+
+ // TODO(b/382016780): to be removed after flag cleanup.
+ @Test
+ @DisableFlags({android.content.pm.Flags.FLAG_REMOVE_HIDDEN_MODULE_USAGE})
public void loadDisplayableRecentApps_hiddenSystemModuleSet_shouldNotHaveHiddenSystemModule() {
final List<UsageStats> stats = new ArrayList<>();
// Regular app.
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
index 6c29036c..a25ff57 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
@@ -50,7 +50,9 @@
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArraySet;
import android.view.View;
@@ -69,6 +71,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -130,6 +133,9 @@
private ActionButtonsPreference mButtonPrefs;
private AppButtonsPreferenceController mController;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -546,6 +552,7 @@
@Test
@Config(shadows = ShadowAppUtils.class)
+ @DisableFlags({android.content.pm.Flags.FLAG_REMOVE_HIDDEN_MODULE_USAGE})
public void getAvailabilityStatus_systemModule() {
ShadowAppUtils.addHiddenModule(mController.mPackageName);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
@@ -553,6 +560,14 @@
}
@Test
+ @Config(shadows = ShadowAppUtils.class)
+ public void getAvailabilityStatus_mainlineModule() {
+ ShadowAppUtils.addMainlineModule(mController.mPackageName);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ AppButtonsPreferenceController.DISABLED_FOR_USER);
+ }
+
+ @Test
public void handleActivityResult_onAppUninstall_removeTask() {
mController.handleActivityResult(REQUEST_UNINSTALL, 0, new Intent());
@@ -642,15 +657,18 @@
@Implements(AppUtils.class)
public static class ShadowAppUtils {
+ // TODO(b/382016780): to be removed after flag cleanup.
public static Set<String> sSystemModules = new ArraySet<>();
public static Set<String> sMainlineModules = new ArraySet<>();
@Resetter
public static void reset() {
+ // TODO(b/382016780): to be removed after flag cleanup.
sSystemModules.clear();
sMainlineModules.clear();
}
+ // TODO(b/382016780): to be removed after flag cleanup.
public static void addHiddenModule(String pkg) {
sSystemModules.add(pkg);
}
@@ -664,6 +682,7 @@
return false;
}
+ // TODO(b/382016780): to be removed after flag cleanup.
@Implementation
protected static boolean isSystemModule(Context context, String packageName) {
return sSystemModules.contains(packageName);
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
index 46d1cc3..2699058 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
@@ -205,6 +205,7 @@
verify(mActivity, never()).finishAndRemoveTask();
}
+ // TODO(b/382016780): to be removed after flag cleanup.
@Test
@Config(shadows = ShadowAppUtils.class)
public void ensureDisplayableModule_hiddenModule_shouldReturnFalse() {
@@ -215,6 +216,7 @@
assertThat(mFragment.ensureDisplayableModule(mActivity)).isFalse();
}
+ // TODO(b/382016780): to be removed after flag cleanup.
@Test
@Config(shadows = ShadowAppUtils.class)
public void ensureDisplayableModule_regularApp_shouldReturnTrue() {
diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt
new file mode 100644
index 0000000..e600061
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollTest.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.biometrics.face
+
+import android.app.Activity
+import android.content.Intent
+import com.android.settings.overlay.FeatureFactory
+import com.android.settings.testutils.FakeFeatureFactory
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.robolectric.Robolectric
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.Shadows
+
+@RunWith(RobolectricTestRunner::class)
+class FaceEnrollTest {
+ private lateinit var featureFactory: FeatureFactory
+
+ private companion object {
+ const val INTENT_KEY = "testKey"
+ const val INTENT_VALUE = "testValue"
+ val INTENT = Intent().apply {
+ putExtra(INTENT_KEY, INTENT_VALUE)
+ }
+ }
+
+ private val activityProvider = FaceEnrollActivityClassProvider()
+
+ @Before
+ fun setUp() {
+ featureFactory = FakeFeatureFactory.setupForTest()
+ Mockito.`when`(featureFactory.faceFeatureProvider.enrollActivityClassProvider)
+ .thenReturn(activityProvider)
+ }
+
+ private fun setupActivity(activityClass: Class<out FaceEnroll>): FaceEnroll {
+ return Robolectric.buildActivity(activityClass, INTENT).create().get()
+ }
+
+ @Test
+ fun testFinishAndLaunchDefaultActivity() {
+ // Run
+ val activity = setupActivity(FaceEnroll::class.java)
+
+ // Verify
+ verifyLaunchNextActivity(activity, activityProvider.next)
+ }
+
+ private fun verifyLaunchNextActivity(
+ currentActivityInstance : FaceEnroll,
+ nextActivityClass: Class<out Activity>
+ ) {
+ Truth.assertThat(currentActivityInstance.isFinishing).isTrue()
+ val nextActivityIntent = Shadows.shadowOf(currentActivityInstance).nextStartedActivity
+ assertThat(nextActivityIntent.component!!.className).isEqualTo(nextActivityClass.name)
+ assertThat(nextActivityIntent.extras!!.size()).isEqualTo(1)
+ assertThat(nextActivityIntent.getStringExtra(INTENT_KEY)).isEqualTo(INTENT_VALUE)
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java
index d0177a8..e96af1c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControllerTest.java
@@ -25,7 +25,6 @@
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import com.android.settings.accessibility.Flags;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -119,8 +118,7 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HEARING_AID_PRESET_CONTROL)
- public void initSubControllers_flagEnabled_presetControllerExist() {
+ public void initSubControllers_presetControllerExist() {
mHearingDeviceController.initSubControllers(false);
assertThat(mHearingDeviceController.getSubControllers().stream().anyMatch(
@@ -128,15 +126,6 @@
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_HEARING_AID_PRESET_CONTROL)
- public void initSubControllers_flagDisabled_presetControllerNotExist() {
- mHearingDeviceController.initSubControllers(false);
-
- assertThat(mHearingDeviceController.getSubControllers().stream().anyMatch(
- c -> c instanceof BluetoothDetailsHearingAidsPresetsController)).isFalse();
- }
-
- @Test
@RequiresFlagsEnabled(
com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICES_AMBIENT_VOLUME_CONTROL)
public void initSubControllers_flagEnabled_ambientVolumeControllerExist() {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogTest.java
index a47101e..14e263c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothKeyMissingDialogTest.java
@@ -19,6 +19,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothDevice;
@@ -27,10 +28,13 @@
import androidx.fragment.app.FragmentActivity;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
@@ -38,18 +42,26 @@
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@Config(shadows = {ShadowAlertDialogCompat.class, ShadowBluetoothUtils.class})
public class BluetoothKeyMissingDialogTest {
@Mock private BluetoothDevice mBluetoothDevice;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private LocalBluetoothManager mLocalBtManager;
private BluetoothKeyMissingDialogFragment mFragment = null;
private FragmentActivity mActivity = null;
+ private static final String MAC_ADDRESS = "12:34:56:78:90:12";
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
+ when(mLocalBtManager.getBluetoothAdapter().getRemoteDevice(MAC_ADDRESS))
+ .thenReturn(mBluetoothDevice);
+ ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
mActivity = Robolectric.setupActivity(FragmentActivity.class);
- mFragment = new BluetoothKeyMissingDialogFragment(mBluetoothDevice);
+ mFragment = BluetoothKeyMissingDialogFragment.newInstance(mBluetoothDevice);
mActivity
.getSupportFragmentManager()
.beginTransaction()
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java
index 4dc4dca..3075573 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingCallAudioPreferenceControllerTest.java
@@ -42,6 +42,7 @@
import android.content.Context;
import android.database.ContentObserver;
import android.os.Looper;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.view.View;
@@ -107,8 +108,11 @@
private static final String PREF_KEY = "calls_and_alarms";
private static final String TEST_DEVICE_NAME1 = "test1";
private static final String TEST_DEVICE_NAME2 = "test2";
+ private static final String TEMP_BOND_METADATA =
+ "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private static final int TEST_DEVICE_GROUP_ID1 = 1;
private static final int TEST_DEVICE_GROUP_ID2 = 2;
+ private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
private static final String TEST_SETTINGS_KEY =
"bluetooth_le_broadcast_fallback_active_group_id";
@@ -441,6 +445,23 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
+ public void displayPreference_hasTemporaryBondDevice_doNotShow() {
+ Settings.Secure.putInt(mContentResolver, TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID1);
+ when(mCachedDevice1.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
+ when(mBroadcast.isEnabled(any())).thenReturn(true);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2));
+ when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
+ when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)).thenReturn(
+ TEMP_BOND_METADATA.getBytes());
+
+ mController.displayPreference(mScreen);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mController.mGroupedConnectedDevices).hasSize(0);
+ }
+
+ @Test
public void displayPreference_clickToShowCorrectDialog() {
AlertDialog latestAlertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
if (latestAlertDialog != null) {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
index 2b19e20..12125a4 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SyncedStateTest.java
@@ -30,6 +30,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.widget.Button;
+import android.widget.EditText;
import android.widget.TextView;
import androidx.preference.Preference;
@@ -59,6 +60,8 @@
})
public class SyncedStateTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ private static final String INVALID_PASSWORD = "PAS";
+ private static final String VALID_PASSWORD = "PASSWORD";
private static final String ENCRYPTED_METADATA =
"BLUETOOTH:UUID:184F;BN:VGVzdA==;AT:1;AD:00A1A1A1A1A1;BI:1E240;BC:VGVzdENvZGU=;"
+ "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
@@ -143,15 +146,24 @@
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
assertThat(positiveButton).isNotNull();
+ assertThat(positiveButton.isEnabled()).isFalse();
assertThat(positiveButton.getText().toString())
.isEqualTo(
mMockContext.getString(R.string.bluetooth_connect_access_dialog_positive));
+ ShadowAlertDialog shadowDialog = Shadow.extract(dialog);
+ EditText editText = shadowDialog.getView().findViewById(R.id.broadcast_edit_text);
+ assertThat(editText).isNotNull();
+ editText.setText(VALID_PASSWORD);
+ assertThat(positiveButton.isEnabled()).isTrue();
+ editText.setText(INVALID_PASSWORD);
+ assertThat(positiveButton.isEnabled()).isFalse();
+
+ editText.setText(VALID_PASSWORD);
positiveButton.callOnClick();
ShadowLooper.idleMainLooper();
verify(mMockController).handleSourceAddRequest(any(), any());
- ShadowAlertDialog shadowDialog = Shadow.extract(dialog);
TextView title = shadowDialog.getView().findViewById(R.id.broadcast_name_text);
assertThat(title).isNotNull();
assertThat(title.getText().toString()).isEqualTo(BROADCAST_TITLE);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt b/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt
index 33cdb3e..9ab2cec 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt
+++ b/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt
@@ -18,6 +18,7 @@
import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM
import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT
+import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP
import android.content.Context
import android.graphics.Color
@@ -34,6 +35,10 @@
import com.android.settings.R
import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+
+import kotlin.math.abs
+
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@@ -54,8 +59,9 @@
}
class TestInjector(context : Context) : DisplayTopologyPreference.Injector(context) {
- var topology : DisplayTopology? = null
- var systemWallpaper : Drawable? = null
+ var topology: DisplayTopology? = null
+ var systemWallpaper: Drawable? = null
+ var topologyListener: Consumer<DisplayTopology>? = null
override var displayTopology : DisplayTopology?
get() = topology
@@ -63,6 +69,21 @@
override val wallpaper : Drawable
get() = systemWallpaper!!
+
+ override fun registerTopologyListener(listener: Consumer<DisplayTopology>) {
+ if (topologyListener != null) {
+ throw IllegalStateException(
+ "already have a listener registered: ${topologyListener}")
+ }
+ topologyListener = listener
+ }
+
+ override fun unregisterTopologyListener(listener: Consumer<DisplayTopology>) {
+ if (topologyListener != listener) {
+ throw IllegalStateException("no such listener registered: ${listener}")
+ }
+ topologyListener = null
+ }
}
@Test
@@ -81,20 +102,21 @@
.map { preference.mPaneContent.getChildAt(it) as DisplayBlock }
.toList()
- /**
- * Sets up a simple topology in the pane with two displays. Returns the left-hand display and
- * right-hand display in order in a list. The right-hand display is the root.
- */
- fun setupTwoDisplays(): List<DisplayBlock> {
+ fun twoDisplayTopology(childPosition: Int, childOffset: Float): DisplayTopology {
+ val primaryId = 1
+
val child = DisplayTopology.TreeNode(
/* displayId= */ 42, /* width= */ 100f, /* height= */ 80f,
- POSITION_LEFT, /* offset= */ 42f)
+ childPosition, childOffset)
val root = DisplayTopology.TreeNode(
- /* displayId= */ 0, /* width= */ 200f, /* height= */ 160f,
- POSITION_LEFT, /* offset= */ 0f)
+ primaryId, /* width= */ 200f, /* height= */ 160f, POSITION_LEFT, /* offset= */ 0f)
root.addChild(child)
- injector.topology = DisplayTopology(root, /*primaryDisplayId=*/ 0)
+ return DisplayTopology(root, primaryId)
+ }
+
+ /** Uses the topology in the injector to populate and prepare the pane for interaction. */
+ fun preparePane() {
// This layoutParams needs to be non-null for the global layout handler.
preference.mPaneHolder.layoutParams = FrameLayout.LayoutParams(
/* width= */ 640, /* height= */ 480)
@@ -106,6 +128,17 @@
preference.onAttached()
preference.onGlobalLayout()
+ }
+
+ /**
+ * Sets up a simple topology in the pane with two displays. Returns the left-hand display and
+ * right-hand display in order in a list. The right-hand display is the root.
+ */
+ fun setupTwoDisplays(childPosition: Int = POSITION_LEFT, childOffset: Float = 42f):
+ List<DisplayBlock> {
+ injector.topology = twoDisplayTopology(childPosition, childOffset)
+
+ preparePane()
val paneChildren = getPaneChildren()
assertThat(paneChildren).hasSize(2)
@@ -219,4 +252,78 @@
assertThat(childrenAfter).hasSize(3)
assertThat(childrenAfter.subList(0, 2)).isEqualTo(childrenBefore)
}
+
+ @Test
+ fun applyNewTopologyViaListenerUpdate() {
+ setupTwoDisplays()
+ val newTopology = injector.topology!!.copy()
+ newTopology.addDisplay(/* displayId= */ 8008, /* width= */ 300f, /* height= */ 320f)
+
+ injector.topology = newTopology
+ injector.topologyListener!!.accept(newTopology)
+
+ assertThat(preference.mTimesReceivedSameTopology).isEqualTo(0)
+ val paneChildren = getPaneChildren()
+ assertThat(paneChildren).hasSize(3)
+
+ // Look for a display with the same unusual aspect ratio as the one we've added.
+ val expectedAspectRatio = 300f/320f
+ assertThat(paneChildren
+ .map { (it.layoutParams.width.toFloat() + BLOCK_PADDING*2) /
+ (it.layoutParams.height.toFloat() + BLOCK_PADDING*2) }
+ .filter { abs(it - expectedAspectRatio) < 0.001f }
+ ).hasSize(1)
+ }
+
+ @Test
+ fun ignoreListenerUpdateOfUnchangedTopology() {
+ injector.topology = twoDisplayTopology(POSITION_TOP, /* offset= */ 12.0f)
+ preparePane()
+
+ assertThat(preference.mTimesReceivedSameTopology).isEqualTo(0)
+ injector.topology = twoDisplayTopology(POSITION_TOP, /* offset= */ 12.1f)
+ injector.topologyListener!!.accept(injector.topology!!)
+
+ assertThat(preference.mTimesReceivedSameTopology).isEqualTo(1)
+ }
+
+ @Test
+ fun updatedTopologyCancelsDragIfNonTrivialChange() {
+ val (leftBlock, rightBlock) = setupTwoDisplays(POSITION_LEFT, /* childOffset= */ 42f)
+
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(142.17f)
+
+ leftBlock.dispatchTouchEvent(MotionEventBuilder.newBuilder()
+ .setAction(MotionEvent.ACTION_DOWN)
+ .setPointer(0f, 0f)
+ .build())
+ leftBlock.dispatchTouchEvent(MotionEventBuilder.newBuilder()
+ .setAction(MotionEvent.ACTION_MOVE)
+ .setPointer(0f, 30f)
+ .build())
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(172.17f)
+
+ // Offset is only different by 0.5 dp, so the drag will not cancel.
+ injector.topology = twoDisplayTopology(POSITION_LEFT, /* childOffset= */ 41.5f)
+ injector.topologyListener!!.accept(injector.topology!!)
+
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(172.17f)
+ // Move block farther downward.
+ leftBlock.dispatchTouchEvent(MotionEventBuilder.newBuilder()
+ .setAction(MotionEvent.ACTION_MOVE)
+ .setPointer(0f, 50f)
+ .build())
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(192.17f)
+
+ injector.topology = twoDisplayTopology(POSITION_LEFT, /* childOffset= */ 20f)
+ injector.topologyListener!!.accept(injector.topology!!)
+
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(125.67f)
+ // Another move in the opposite direction should not move the left block.
+ leftBlock.dispatchTouchEvent(MotionEventBuilder.newBuilder()
+ .setAction(MotionEvent.ACTION_MOVE)
+ .setPointer(0f, -20f)
+ .build())
+ assertThat(leftBlock.unpaddedY).isWithin(0.01f).of(125.67f)
+ }
}
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
index 2961935..643523d 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
@@ -282,10 +282,12 @@
locationSupported ? Capabilities.CAPABILITY_POSSESSED
: Capabilities.CAPABILITY_NOT_SUPPORTED)
.setSetManualTimeZoneCapability(Capabilities.CAPABILITY_POSSESSED)
+ .setConfigureNotificationsEnabledCapability(Capabilities.CAPABILITY_POSSESSED)
.build();
TimeZoneConfiguration config = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(autoEnabled)
.setGeoDetectionEnabled(locationSupported)
+ .setNotificationsEnabled(true)
.build();
return new TimeZoneCapabilitiesAndConfig(status, capabilities, config);
}
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationProviderStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationProviderStatusPreferenceControllerTest.java
index 9ace563..f2f0577 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationProviderStatusPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationProviderStatusPreferenceControllerTest.java
@@ -261,6 +261,7 @@
.setUseLocationEnabled(true)
.setConfigureGeoDetectionEnabledCapability(configureGeoDetectionEnabledCapability)
.setSetManualTimeZoneCapability(Capabilities.CAPABILITY_POSSESSED)
+ .setConfigureNotificationsEnabledCapability(Capabilities.CAPABILITY_POSSESSED)
.build();
return new TimeZoneCapabilitiesAndConfig(status, capabilities,
diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
index 2f23257..8f94253 100644
--- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java
@@ -236,11 +236,13 @@
.setUseLocationEnabled(useLocationEnabled)
.setConfigureGeoDetectionEnabledCapability(configureGeoDetectionEnabledCapability)
.setSetManualTimeZoneCapability(CAPABILITY_NOT_APPLICABLE)
+ .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED)
.build();
TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(setAutoDetectionEnabled)
.setGeoDetectionEnabled(true)
+ .setNotificationsEnabled(true)
.build();
return new TimeZoneCapabilitiesAndConfig(status, capabilities, configuration);
diff --git a/tests/robotests/src/com/android/settings/datetime/NotificationsPreferenceCategoryControllerTest.java b/tests/robotests/src/com/android/settings/datetime/NotificationsPreferenceCategoryControllerTest.java
new file mode 100644
index 0000000..98bdfff
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datetime/NotificationsPreferenceCategoryControllerTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datetime;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import com.android.server.flags.Flags;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class NotificationsPreferenceCategoryControllerTest {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+
+ private NotificationsPreferenceCategoryController mController;
+ @Mock
+ private AbstractPreferenceController mChildController;
+
+ @Before
+ @EnableFlags({Flags.FLAG_DATETIME_NOTIFICATIONS})
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = RuntimeEnvironment.getApplication();
+
+ mController = new NotificationsPreferenceCategoryController(context, "test_key");
+ mController.addChildController(mChildController);
+ }
+
+ @Test
+ @DisableFlags({Flags.FLAG_DATETIME_NOTIFICATIONS})
+ public void getAvailabilityStatus_featureDisabled() {
+ when(mChildController.isAvailable()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_DATETIME_NOTIFICATIONS})
+ public void getAvailabilityStatus_featureEnabled() {
+ when(mChildController.isAvailable()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+
+ when(mChildController.isAvailable()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java
index 1747f17..2e603e3 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java
@@ -74,7 +74,7 @@
/**
* Extend class under test to change {@link #isTimeFeedbackFeatureEnabled} to not call
- * {@link TimeFeedbackLaunchUtils} because that's non-trivial to fake.
+ * {@link DateTimeLaunchUtils} because that's non-trivial to fake.
*/
private static class TestTimeFeedbackPreferenceCategoryController
extends TimeFeedbackPreferenceCategoryController {
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
index fec410b..649201b 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeZonePreferenceControllerTest.java
@@ -16,6 +16,7 @@
package com.android.settings.datetime;
+import static android.app.time.Capabilities.CAPABILITY_POSSESSED;
import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
import static android.app.time.DetectorStatusTypes.DETECTOR_STATUS_RUNNING;
import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
@@ -113,10 +114,12 @@
.setUseLocationEnabled(useLocationEnabled)
.setConfigureGeoDetectionEnabledCapability(Capabilities.CAPABILITY_NOT_SUPPORTED)
.setSetManualTimeZoneCapability(suggestManualCapability)
+ .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED)
.build();
TimeZoneConfiguration config = new TimeZoneConfiguration.Builder()
.setAutoDetectionEnabled(!suggestManualAllowed)
.setGeoDetectionEnabled(false)
+ .setNotificationsEnabled(true)
.build();
return new TimeZoneCapabilitiesAndConfig(status, capabilities, config);
}
diff --git a/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java b/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java
index aeb3ba0..e6a3f0e 100644
--- a/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/dream/DreamSettingsTest.java
@@ -59,6 +59,7 @@
DreamSettings.WHILE_CHARGING_ONLY,
DreamSettings.WHILE_DOCKED_ONLY,
DreamSettings.EITHER_CHARGING_OR_DOCKED,
+ DreamSettings.WHILE_POSTURED_ONLY,
DreamSettings.NEVER_DREAM
);
@@ -66,7 +67,8 @@
private static final int[] SETTINGS = {
DreamBackend.WHILE_CHARGING,
DreamBackend.WHILE_DOCKED,
- DreamBackend.EITHER,
+ DreamBackend.WHILE_CHARGING_OR_DOCKED,
+ DreamBackend.WHILE_POSTURED,
DreamBackend.NEVER,
};
@@ -74,6 +76,7 @@
R.string.screensaver_settings_summary_sleep,
R.string.screensaver_settings_summary_dock,
R.string.screensaver_settings_summary_either_long,
+ R.string.screensaver_settings_summary_postured,
R.string.screensaver_settings_summary_never
};
@@ -81,6 +84,7 @@
R.string.screensaver_settings_summary_sleep,
R.string.screensaver_settings_summary_dock_and_charging,
R.string.screensaver_settings_summary_either_long,
+ R.string.screensaver_settings_summary_postured_and_charging,
R.string.screensaver_settings_summary_never
};
diff --git a/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java b/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java
index 91ec299..f2197e7 100644
--- a/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java
+++ b/tests/robotests/src/com/android/settings/dream/WhenToDreamPickerTest.java
@@ -80,9 +80,13 @@
assertThat(mPicker.getDefaultKey())
.isEqualTo(DreamSettings.getKeyFromSetting(DreamBackend.WHILE_DOCKED));
- when(mBackend.getWhenToDreamSetting()).thenReturn(DreamBackend.EITHER);
+ when(mBackend.getWhenToDreamSetting()).thenReturn(DreamBackend.WHILE_CHARGING_OR_DOCKED);
assertThat(mPicker.getDefaultKey())
- .isEqualTo(DreamSettings.getKeyFromSetting(DreamBackend.EITHER));
+ .isEqualTo(DreamSettings.getKeyFromSetting(DreamBackend.WHILE_CHARGING_OR_DOCKED));
+
+ when(mBackend.getWhenToDreamSetting()).thenReturn(DreamBackend.WHILE_POSTURED);
+ assertThat(mPicker.getDefaultKey())
+ .isEqualTo(DreamSettings.getKeyFromSetting(DreamBackend.WHILE_POSTURED));
when(mBackend.getWhenToDreamSetting()).thenReturn(DreamBackend.NEVER);
assertThat(mPicker.getDefaultKey())
@@ -105,9 +109,16 @@
@Test
public void setDreamWhileChargingOrDocked() {
- final String key = DreamSettings.getKeyFromSetting(DreamBackend.EITHER);
+ final String key = DreamSettings.getKeyFromSetting(DreamBackend.WHILE_CHARGING_OR_DOCKED);
mPicker.setDefaultKey(key);
- verify(mBackend).setWhenToDream(DreamBackend.EITHER);
+ verify(mBackend).setWhenToDream(DreamBackend.WHILE_CHARGING_OR_DOCKED);
+ }
+
+ @Test
+ public void setDreamWhilePostured() {
+ final String key = DreamSettings.getKeyFromSetting(DreamBackend.WHILE_POSTURED);
+ mPicker.setDefaultKey(key);
+ verify(mBackend).setWhenToDream(DreamBackend.WHILE_POSTURED);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceControllerTest.java
similarity index 92%
rename from tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceControllerTest.java
index 8449dba..1b82080 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadPointerSpeedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadPointerSpeedPreferenceControllerTest.java
@@ -42,20 +42,20 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-/** Tests for {@link TrackpadPointerSpeedPreferenceController} */
+/** Tests for {@link TouchpadPointerSpeedPreferenceController} */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowSystemSettings.class,
})
-public class TrackpadPointerSpeedPreferenceControllerTest {
+public class TouchpadPointerSpeedPreferenceControllerTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- private static final String PREFERENCE_KEY = "trackpad_pointer_speed";
+ private static final String PREFERENCE_KEY = "touchpad_pointer_speed";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_POINTER_SPEED;
private Context mContext;
- private TrackpadPointerSpeedPreferenceController mController;
+ private TouchpadPointerSpeedPreferenceController mController;
private int mDefaultSpeed;
private FakeFeatureFactory mFeatureFactory;
@@ -63,7 +63,7 @@
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
- mController = new TrackpadPointerSpeedPreferenceController(mContext, PREFERENCE_KEY);
+ mController = new TouchpadPointerSpeedPreferenceController(mContext, PREFERENCE_KEY);
mDefaultSpeed = Settings.System.getIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceControllerTest.java
similarity index 93%
rename from tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceControllerTest.java
index 16b17f3..7650de2 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadReverseScrollingPreferenceControllerTest.java
@@ -44,28 +44,28 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-/** Tests for {@link TrackpadReverseScrollingPreferenceController} */
+/** Tests for {@link TouchpadReverseScrollingPreferenceController} */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowSystemSettings.class,
com.android.settings.testutils.shadow.ShadowInputDevice.class,
})
-public class TrackpadReverseScrollingPreferenceControllerTest {
+public class TouchpadReverseScrollingPreferenceControllerTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- private static final String PREFERENCE_KEY = "trackpad_reverse_scrolling";
+ private static final String PREFERENCE_KEY = "touchpad_reverse_scrolling";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_NATURAL_SCROLLING;
private Context mContext;
- private TrackpadReverseScrollingPreferenceController mController;
+ private TouchpadReverseScrollingPreferenceController mController;
private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
- mController = new TrackpadReverseScrollingPreferenceController(mContext, PREFERENCE_KEY);
+ mController = new TouchpadReverseScrollingPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceControllerTest.java
similarity index 92%
rename from tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceControllerTest.java
index a7d4bf4..206f5bb 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadBottomPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadRightClickZonePreferenceControllerTest.java
@@ -44,28 +44,28 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-/** Tests for {@link TrackpadBottomPreferenceController} */
+/** Tests for {@link TouchpadRightClickZonePreferenceController} */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowSystemSettings.class,
com.android.settings.testutils.shadow.ShadowInputDevice.class,
})
-public class TrackpadBottomPreferenceControllerTest {
+public class TouchpadRightClickZonePreferenceControllerTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- private static final String PREFERENCE_KEY = "trackpad_bottom_right_tap";
+ private static final String PREFERENCE_KEY = "touchpad_bottom_right_tap";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE;
private Context mContext;
- private TrackpadBottomPreferenceController mController;
+ private TouchpadRightClickZonePreferenceController mController;
private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
- mController = new TrackpadBottomPreferenceController(mContext, PREFERENCE_KEY);
+ mController = new TouchpadRightClickZonePreferenceController(mContext, PREFERENCE_KEY);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceControllerTest.java
similarity index 93%
rename from tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceControllerTest.java
index 979f568..a44fb81 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadTapToClickPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadTapToClickPreferenceControllerTest.java
@@ -44,28 +44,28 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-/** Tests for {@link TrackpadTapToClickPreferenceController} */
+/** Tests for {@link TouchpadTapToClickPreferenceController} */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowSystemSettings.class,
com.android.settings.testutils.shadow.ShadowInputDevice.class,
})
-public class TrackpadTapToClickPreferenceControllerTest {
+public class TouchpadTapToClickPreferenceControllerTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule();
- private static final String PREFERENCE_KEY = "trackpad_tap_to_click";
+ private static final String PREFERENCE_KEY = "touchpad_tap_to_click";
private static final String SETTING_KEY = Settings.System.TOUCHPAD_TAP_TO_CLICK;
private Context mContext;
- private TrackpadTapToClickPreferenceController mController;
+ private TouchpadTapToClickPreferenceController mController;
private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
- mController = new TrackpadTapToClickPreferenceController(mContext, PREFERENCE_KEY);
+ mController = new TouchpadTapToClickPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/AllowSoundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/AllowSoundPreferenceControllerTest.java
index 5260ff6..86a3fe4 100644
--- a/tests/robotests/src/com/android/settings/notification/app/AllowSoundPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/AllowSoundPreferenceControllerTest.java
@@ -38,6 +38,8 @@
import android.os.UserManager;
import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.notification.NotificationBackend;
@@ -68,7 +70,6 @@
private NotificationManager mNm;
@Mock
private UserManager mUm;
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
@Mock
@@ -83,6 +84,7 @@
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
mContext = RuntimeEnvironment.application;
+ mScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mController =
spy(new AllowSoundPreferenceController(mContext, mDependentFieldListener, mBackend));
}
@@ -160,6 +162,7 @@
RestrictedLockUtils.EnforcedAdmin.class), null);
Preference pref = new RestrictedSwitchPreference(mContext);
+ mScreen.addPreference(pref);
mController.updateState(pref);
assertFalse(pref.isEnabled());
@@ -173,6 +176,7 @@
mController.onResume(appRow, channel, null, null, null, null, null);
Preference pref = new RestrictedSwitchPreference(mContext);
+ mScreen.addPreference(pref);
mController.updateState(pref);
assertTrue(pref.isEnabled());
@@ -186,6 +190,7 @@
null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+ mScreen.addPreference(pref);
mController.updateState(pref);
assertTrue(pref.isChecked());
}
@@ -198,6 +203,7 @@
null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+ mScreen.addPreference(pref);
mController.updateState(pref);
assertTrue(pref.isChecked());
}
@@ -210,6 +216,7 @@
null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+ mScreen.addPreference(pref);
mController.updateState(pref);
assertFalse(pref.isChecked());
}
@@ -222,7 +229,7 @@
null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+ mScreen.addPreference(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
pref.setChecked(true);
@@ -240,7 +247,7 @@
null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+ mScreen.addPreference(pref);
mController.displayPreference(mScreen);
mController.updateState(pref);
diff --git a/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt b/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
index 89e33ee..a9abf8b 100644
--- a/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
+++ b/tests/robotests/src/com/android/settings/notification/app/FullScreenIntentPermissionPreferenceControllerTest.kt
@@ -37,6 +37,7 @@
import android.permission.PermissionManager.PERMISSION_SOFT_DENIED
import android.permission.PermissionManager.PermissionResult
import androidx.preference.Preference
+import androidx.preference.PreferenceManager
import androidx.preference.PreferenceScreen
import androidx.test.core.app.ApplicationProvider
import com.android.settings.notification.NotificationBackend
@@ -80,7 +81,6 @@
private lateinit var preference: RestrictedSwitchPreference
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var screen: PreferenceScreen
private lateinit var controller: FullScreenIntentPermissionPreferenceController
@@ -94,7 +94,8 @@
preference = RestrictedSwitchPreference(context).apply { key = KEY_FSI_PERMISSION }
- whenever(screen.findPreference<Preference>(KEY_FSI_PERMISSION)).thenReturn(preference)
+ screen = PreferenceManager(context).createPreferenceScreen(context)
+ screen.addPreference(preference)
controller = FullScreenIntentPermissionPreferenceController(
context,
diff --git a/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
index 05a41a6..b5190dd 100644
--- a/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/HeaderPreferenceControllerTest.java
@@ -114,27 +114,6 @@
}
@Test
- public void testGetLabel() {
- NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.label = "bananas";
- mController.onResume(appRow, null, null, null, null, null, null);
- assertEquals(appRow.label, mController.getLabel());
-
- NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
- mController.onResume(appRow, null, group, null, null, null, null);
- assertEquals(appRow.label, mController.getLabel());
-
- NotificationChannel channel = new NotificationChannel("cid", "cname", IMPORTANCE_NONE);
- mController.onResume(appRow, channel, group, null, null, null, null);
- assertEquals(channel.getName(), mController.getLabel());
-
- NotificationChannel defaultChannel = new NotificationChannel(
- NotificationChannel.DEFAULT_CHANNEL_ID, "", IMPORTANCE_NONE);
- mController.onResume(appRow, defaultChannel, null, null, null, null, null);
- assertEquals(appRow.label, mController.getLabel());
- }
-
- @Test
public void testGetSummary() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.label = "bananas";
@@ -146,16 +125,14 @@
NotificationChannel channel = new NotificationChannel("cid", "cname", IMPORTANCE_NONE);
mController.onResume(appRow, channel, group, null, null, null, null);
assertTrue(mController.getSummary().toString().contains(group.getName()));
- assertTrue(mController.getSummary().toString().contains(appRow.label));
mController.onResume(appRow, channel, null, null, null, null, null);
assertFalse(mController.getSummary().toString().contains(group.getName()));
- assertTrue(mController.getSummary().toString().contains(appRow.label));
NotificationChannel defaultChannel = new NotificationChannel(
NotificationChannel.DEFAULT_CHANNEL_ID, "", IMPORTANCE_NONE);
mController.onResume(appRow, defaultChannel, null, null, null, null, null);
- assertEquals(appRow.label, mController.getSummary());
+ assertEquals("", mController.getSummary());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceControllerTest.java
index eb80465..dcc9daf 100644
--- a/tests/robotests/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/InvalidConversationInfoPreferenceControllerTest.java
@@ -34,6 +34,7 @@
import com.android.settings.notification.NotificationBackend;
import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settingslib.widget.SettingsThemeHelper;
import com.google.common.collect.ImmutableList;
@@ -89,6 +90,18 @@
}
@Test
+ public void testIsAvailable_notIfExpressiveTheme() {
+ if (SettingsThemeHelper.isExpressiveTheme(mContext)) {
+ when(mBackend.isInInvalidMsgState(anyString(), anyInt())).thenReturn(true);
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.pkg = "hi";
+ appRow.uid = 0;
+ mController.onResume(appRow, null, null, null, null, null, null);
+ assertFalse(mController.isAvailable());
+ }
+ }
+
+ @Test
public void testIsAvailable_notIfAppBlocked() {
when(mBackend.isInInvalidMsgState(anyString(), anyInt())).thenReturn(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
@@ -111,6 +124,9 @@
@Test
public void testIsAvailable() {
+ if (SettingsThemeHelper.isExpressiveTheme(mContext)) {
+ return;
+ }
when(mBackend.isInInvalidMsgState(anyString(), anyInt())).thenReturn(true);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.pkg = "hi";
diff --git a/tests/robotests/src/com/android/settings/notification/app/PromotedNotificationsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/PromotedNotificationsPreferenceControllerTest.java
index 917d469..8e0ab96 100644
--- a/tests/robotests/src/com/android/settings/notification/app/PromotedNotificationsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/PromotedNotificationsPreferenceControllerTest.java
@@ -18,13 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.Flags;
import android.content.Context;
@@ -32,7 +31,7 @@
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.notification.NotificationBackend;
@@ -55,8 +54,6 @@
private NotificationBackend.AppRow mAppRow;
@Mock
private NotificationBackend mBackend;
- @Mock
- private PreferenceCategory mPrefCategory;
private RestrictedSwitchPreference mSwitch;
private PromotedNotificationsPreferenceController mPrefController;
@@ -66,7 +63,7 @@
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mSwitch = new RestrictedSwitchPreference(mContext);
- when(mPrefCategory.findPreference("promoted_switch")).thenReturn(mSwitch);
+ new PreferenceManager(mContext).createPreferenceScreen(mContext).addPreference(mSwitch);
mPrefController = new PromotedNotificationsPreferenceController(mContext, mBackend);
mAppRow = new NotificationBackend.AppRow();
@@ -93,12 +90,12 @@
mAppRow.canBePromoted = true;
mPrefController.onResume(mAppRow, null, null, null, null, null, null);
- mPrefController.updateState(mPrefCategory);
+ mPrefController.updateState(mSwitch);
assertThat(mSwitch.isChecked()).isTrue();
mAppRow.canBePromoted = false;
mPrefController.onResume(mAppRow, null, null, null, null, null, null);
- mPrefController.updateState(mPrefCategory);
+ mPrefController.updateState(mSwitch);
assertThat(mSwitch.isChecked()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/notification/app/RecentConversationsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/RecentConversationsPreferenceControllerTest.java
index 3c0a0f3..5388591 100644
--- a/tests/robotests/src/com/android/settings/notification/app/RecentConversationsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/RecentConversationsPreferenceControllerTest.java
@@ -50,6 +50,7 @@
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.notification.NotificationBackend;
+import com.android.settingslib.widget.ButtonPreference;
import com.android.settingslib.widget.LayoutPreference;
import com.google.common.collect.ImmutableList;
@@ -232,14 +233,16 @@
new NotificationChannelGroup("hi", "group"), 7,
false);
- RecentConversationPreference pref = mController.createConversationPref(ccw);
+ Preference pref = mController.createConversationPref(ccw);
final View view = View.inflate(mContext, pref.getLayoutResource(), null);
PreferenceViewHolder holder = spy(PreferenceViewHolder.createInstanceForTests(view));
- View delete = View.inflate(mContext, pref.getSecondTargetResId(), null);
- when(holder.findViewById(pref.getClearId())).thenReturn(delete);
+ View delete = View.inflate(mContext, ((RecentConversationPreference) pref)
+ .getSecondTargetResId(), null);
+ when(holder.findViewById(((RecentConversationPreference) pref).getClearId()))
+ .thenReturn(delete);
pref.onBindViewHolder(holder);
- pref.getClearView().performClick();
+ ((RecentConversationPreference) pref).getClearView().performClick();
verify(mPs).removeRecentConversation(
si.getPackage(), UserHandle.getUserId(ccw.getUid()), si.getId());
@@ -260,24 +263,24 @@
new NotificationChannelGroup("hi", "group"), 7,
true);
- RecentConversationPreference pref = mController.createConversationPref(ccw);
+ Preference pref = mController.createConversationPref(ccw);
final View view = View.inflate(mContext, pref.getLayoutResource(), null);
PreferenceViewHolder holder = spy(PreferenceViewHolder.createInstanceForTests(view));
- View delete = View.inflate(mContext, pref.getSecondTargetResId(), null);
- when(holder.findViewById(pref.getClearId())).thenReturn(delete);
+ View delete = View.inflate(mContext, ((RecentConversationPreference) pref).
+ getSecondTargetResId(), null);
+ when(holder.findViewById(((RecentConversationPreference) pref).getClearId()))
+ .thenReturn(delete);
mPreferenceGroup.addPreference(pref);
- RecentConversationPreference pref2 = mController.createConversationPref(ccw2);
- final View view2 = View.inflate(mContext, pref2.getLayoutResource(), null);
- PreferenceViewHolder holder2 = spy(PreferenceViewHolder.createInstanceForTests(view2));
- View delete2 = View.inflate(mContext, pref2.getSecondTargetResId(), null);
- when(holder2.findViewById(pref.getClearId())).thenReturn(delete2);
+ Preference pref2 = mController.createConversationPref(ccw2);
mPreferenceGroup.addPreference(pref2);
- LayoutPreference clearAll = mController.getClearAll(mPreferenceGroup);
+ ButtonPreference clearAll = mController.getClearAll(mPreferenceGroup);
+ final View rootView = View.inflate(mContext, clearAll.getLayoutResource(), null);
+ clearAll.onBindViewHolder(PreferenceViewHolder.createInstanceForTests(rootView));
mPreferenceGroup.addPreference(clearAll);
- clearAll.findViewById(R.id.conversation_settings_clear_recents).performClick();
+ clearAll.getButton().performClick();
verify(mPs).removeAllRecentConversations();
assertThat((Preference) mPreferenceGroup.findPreference("hi:person")).isNull();
@@ -294,9 +297,9 @@
new NotificationChannelGroup("hi", "group"), 7,
true);
- RecentConversationPreference pref = mController.createConversationPref(ccw);
+ Preference pref = mController.createConversationPref(ccw);
- assertThat(pref.hasClearListener()).isFalse();
+ assertThat(pref instanceof RecentConversationPreference).isFalse();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
index 8653d95..887a324 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -71,7 +71,7 @@
@Test
public void updateState_dnd_enabled() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE;
+ ZenMode dnd = TestModeBuilder.MANUAL_DND;
mController.updateState(preference, dnd);
@@ -81,7 +81,11 @@
@Test
public void updateState_specialDnd_disabled() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true);
+ ZenMode specialDnd = new TestModeBuilder()
+ .makeManualDnd()
+ .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+ .setActive(true)
+ .build();
mController.updateState(preference, specialDnd);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
index 4edb0d5..12cd2d9 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ManualDurationPreferenceControllerTest.java
@@ -70,8 +70,7 @@
@Test
public void testIsAvailable_onlyForManualDnd() {
assertThat(mPrefController.isAvailable(TestModeBuilder.EXAMPLE)).isFalse();
- assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_ACTIVE)).isTrue();
- assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND_INACTIVE)).isTrue();
+ assertThat(mPrefController.isAvailable(TestModeBuilder.MANUAL_DND)).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
index e747b42..1b54a60 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
@@ -63,7 +63,6 @@
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
-import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
@@ -153,14 +152,18 @@
@Test
public void updateState_dnd_enabled() {
- ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE;
+ ZenMode dnd = TestModeBuilder.MANUAL_DND;
mController.updateState(mPreference, dnd);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void updateState_specialDnd_disabled() {
- ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true);
+ ZenMode specialDnd = new TestModeBuilder()
+ .makeManualDnd()
+ .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+ .setActive(true)
+ .build();
mController.updateState(mPreference, specialDnd);
assertThat(mPreference.isEnabled()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
index 159dada..6427f7b 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
@@ -190,7 +190,7 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
+ ZenMode zenMode = TestModeBuilder.MANUAL_DND;
mController.updateZenMode(pref, zenMode);
button.callOnClick();
@@ -204,7 +204,7 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = TestModeBuilder.MANUAL_DND_INACTIVE;
+ ZenMode zenMode = TestModeBuilder.MANUAL_DND;
mController.updateZenMode(pref, zenMode);
button.callOnClick();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
index 05486e0..bba24e5 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
@@ -68,7 +68,7 @@
@Test
public void updateState_dnd_enabled() {
Preference preference = mock(Preference.class);
- ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE;
+ ZenMode dnd = TestModeBuilder.MANUAL_DND;
mController.updateState(preference, dnd);
@@ -78,7 +78,11 @@
@Test
public void updateState_specialDnd_disabled() {
Preference preference = mock(Preference.class);
- ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true);
+ ZenMode specialDnd = new TestModeBuilder()
+ .makeManualDnd()
+ .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+ .setActive(true)
+ .build();
mController.updateState(preference, specialDnd);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
index 38790b2..f20d18a 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
@@ -66,7 +66,7 @@
@Test
public void updateState_dnd_enabled() {
CircularIconsPreference preference = mock(CircularIconsPreference.class);
- ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE;
+ ZenMode dnd = TestModeBuilder.MANUAL_DND;
mController.updateState(preference, dnd);
@@ -76,7 +76,11 @@
@Test
public void updateState_specialDnd_disabled() {
CircularIconsPreference preference = mock(CircularIconsPreference.class);
- ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true);
+ ZenMode specialDnd = new TestModeBuilder()
+ .makeManualDnd()
+ .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+ .setActive(true)
+ .build();
mController.updateState(preference, specialDnd);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
index 8a66253..72c8c6f 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
@@ -120,14 +120,18 @@
@Test
public void updateState_dnd_enabled() {
- ZenMode dnd = TestModeBuilder.MANUAL_DND_ACTIVE;
+ ZenMode dnd = TestModeBuilder.MANUAL_DND;
mController.updateState(mPreference, dnd);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void updateState_specialDnd_disabled() {
- ZenMode specialDnd = TestModeBuilder.manualDnd(INTERRUPTION_FILTER_NONE, true);
+ ZenMode specialDnd = new TestModeBuilder()
+ .makeManualDnd()
+ .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
+ .setActive(true)
+ .build();
mController.updateState(mPreference, specialDnd);
assertThat(mPreference.isEnabled()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java
index d222a8b..e2d1595 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java
@@ -529,7 +529,7 @@
@Test
public void getModesSummary_excludesImplicitModes() {
ImmutableList<ZenMode> modes = ImmutableList.of(
- TestModeBuilder.MANUAL_DND_INACTIVE,
+ TestModeBuilder.MANUAL_DND,
new TestModeBuilder().implicitForPackage("com.annoying.one").build(),
new TestModeBuilder().setName("Chirping").build()
);
@@ -541,7 +541,7 @@
@Test
public void getModesSummary_oneModeActive_listsActiveMode() {
ImmutableList<ZenMode> modes = ImmutableList.of(
- TestModeBuilder.MANUAL_DND_ACTIVE,
+ new TestModeBuilder().makeManualDnd().setActive(true).build(),
new TestModeBuilder().setName("Inactive").setActive(false).build());
String summary = mSummaryHelper.getModesSummary(modes);
@@ -551,7 +551,7 @@
@Test
public void getModesSummary_twoModesActive_listsActiveModes() {
ImmutableList<ZenMode> modes = ImmutableList.of(
- TestModeBuilder.MANUAL_DND_ACTIVE,
+ new TestModeBuilder().makeManualDnd().setActive(true).build(),
new TestModeBuilder().setName("Inactive").setActive(false).build(),
new TestModeBuilder().setName("Active #1").setActive(true).build());
@@ -562,7 +562,7 @@
@Test
public void getModesSummary_threeModesActive_listsActiveModes() {
ImmutableList<ZenMode> modes = ImmutableList.of(
- TestModeBuilder.MANUAL_DND_INACTIVE,
+ TestModeBuilder.MANUAL_DND,
new TestModeBuilder().setName("Inactive #1").setActive(false).build(),
new TestModeBuilder().setName("Active #1").setActive(true).build(),
new TestModeBuilder().setName("Active #2").setActive(true).build(),
@@ -576,7 +576,7 @@
@Test
public void getModesSummary_manyModesActive_listsSomeActiveModes() {
ImmutableList<ZenMode> modes = ImmutableList.of(
- TestModeBuilder.MANUAL_DND_ACTIVE,
+ new TestModeBuilder().makeManualDnd().setActive(true).build(),
new TestModeBuilder().setName("Inactive #1").setActive(false).build(),
new TestModeBuilder().setName("Active #1").setActive(true).build(),
new TestModeBuilder().setName("Active #2").setActive(true).build(),
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
index 0d20b19..0a8e400 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
@@ -123,7 +123,7 @@
@Test
public void isAvailable_manualDND_false() {
- mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
+ mController.setZenMode(TestModeBuilder.MANUAL_DND);
assertThat(mController.isAvailable()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
index bcafe47..64c7715 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerCategoryPreferenceControllerTest.java
@@ -113,7 +113,7 @@
@Test
public void isAvailable_manualDND_false() {
- mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
+ mController.setZenMode(TestModeBuilder.MANUAL_DND);
assertThat(mController.isAvailable()).isFalse();
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index d916dcf..6e6485e 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -148,7 +148,7 @@
@Test
public void isAvailable_manualDND_false() {
- mController.setZenMode(TestModeBuilder.MANUAL_DND_INACTIVE);
+ mController.setZenMode(TestModeBuilder.MANUAL_DND);
assertThat(mController.isAvailable()).isFalse();
}
@@ -310,6 +310,25 @@
}
@Test
+ public void updateState_scheduleTimeRuleWithNoDays_emptySummary() {
+ ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
+ scheduleInfo.days = new int[] {};
+ scheduleInfo.startHour = 1;
+ scheduleInfo.endHour = 15;
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setType(TYPE_SCHEDULE_TIME)
+ .setTriggerDescription("some schedule")
+ .build();
+
+ mController.updateState(mPreference, mode);
+
+ assertThat(mPreference.getTitle()).isEqualTo("1:00 AM - 3:00 PM");
+ assertThat(mPreference.getSummary()).isNull();
+ }
+
+ @Test
public void updateState_appWithConfigActivity_showsLinkToConfigActivity() {
ZenMode mode = new TestModeBuilder()
.setPackage("some.package")
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
index 69568ce..24ec8fb 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
@@ -18,7 +18,7 @@
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-import static com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND_INACTIVE;
+import static com.android.settingslib.notification.modes.TestModeBuilder.MANUAL_DND;
import static com.google.common.truth.Truth.assertThat;
@@ -150,7 +150,7 @@
@DisableFlags(Flags.FLAG_MODES_UI)
public void testModesUiOff_notAvailableAndNoSearchData() {
// There exist modes
- when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
+ when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND, TEST_MODE));
assertThat(mPrefController.isAvailable()).isFalse();
List<SearchIndexableRaw> data = new ArrayList<>();
@@ -185,20 +185,20 @@
// Changing mode data so there's a different one mode doesn't keep any previous data
// (and setting that state up in the caller)
- when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE));
+ when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND));
List<SearchIndexableRaw> newData = new ArrayList<>();
mPrefController.updateDynamicRawDataToIndex(newData);
assertThat(newData).hasSize(1);
SearchIndexableRaw newItem = newData.get(0);
- assertThat(newItem.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
+ assertThat(newItem.key).isEqualTo(MANUAL_DND.getId());
assertThat(newItem.title).isEqualTo("Do Not Disturb"); // set above
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void testUpdateDynamicRawDataToIndex_multipleModes() {
- when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND_INACTIVE, TEST_MODE));
+ when(mBackend.getModes()).thenReturn(List.of(MANUAL_DND, TEST_MODE));
List<SearchIndexableRaw> data = new ArrayList<>();
mPrefController.updateDynamicRawDataToIndex(data);
@@ -206,7 +206,7 @@
// Should keep the order presented by getModes()
SearchIndexableRaw item0 = data.get(0);
- assertThat(item0.key).isEqualTo(MANUAL_DND_INACTIVE.getId());
+ assertThat(item0.key).isEqualTo(MANUAL_DND.getId());
assertThat(item0.title).isEqualTo("Do Not Disturb"); // set above
SearchIndexableRaw item1 = data.get(1);
diff --git a/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt b/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
index 654b892..80cd2fd 100644
--- a/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
+++ b/tests/robotests/src/com/android/settings/service/PreferenceServiceRequestTransformerTest.kt
@@ -33,7 +33,6 @@
import com.android.settings.homepage.SettingsHomepageActivity
import com.android.settingslib.datastore.Permissions
import com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST
-import com.android.settingslib.graph.PreferenceCoordinate
import com.android.settingslib.graph.PreferenceGetterErrorCode
import com.android.settingslib.graph.PreferenceGetterFlags
import com.android.settingslib.graph.PreferenceGetterResponse
@@ -48,6 +47,7 @@
import com.android.settingslib.graph.rangeValueProto
import com.android.settingslib.graph.textProto
import com.android.settingslib.graph.toProto
+import com.android.settingslib.metadata.PreferenceCoordinate
import com.android.settingslib.metadata.SensitivityLevel
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
diff --git a/tests/screenshot/Android.bp b/tests/screenshot/Android.bp
index f79d00f..d3f4160 100644
--- a/tests/screenshot/Android.bp
+++ b/tests/screenshot/Android.bp
@@ -72,7 +72,6 @@
"truth",
],
- upstream: true,
instrumentation_for: "ScreenshotTestStub",
java_resource_dirs: ["config"],
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
index ebbd57a..5a29a7d 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppStoragePreferenceTest.kt
@@ -89,7 +89,7 @@
composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
.assertIsDisplayed()
- composeTestRule.waitUntilExists(hasText("120 B used in internal storage"))
+ composeTestRule.waitUntilExists(hasText("120 byte used in internal storage"))
}
@Test
@@ -104,7 +104,7 @@
composeTestRule.onNodeWithText(context.getString(R.string.storage_settings_for_app))
.assertIsDisplayed()
- composeTestRule.waitUntilExists(hasText("120 B used in external storage"))
+ composeTestRule.waitUntilExists(hasText("120 byte used in external storage"))
}
private fun setContent(app: ApplicationInfo) {
@@ -122,7 +122,6 @@
private val STATS = StorageStats().apply {
codeBytes = 100
dataBytes = 20
- cacheBytes = 3
}
}
}
diff --git a/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
index e1c0277..9cc118f 100644
--- a/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
@@ -24,20 +24,30 @@
import android.content.Context;
import android.content.res.Resources;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.R;
+import com.android.server.display.feature.flags.Flags;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+/** Tests for {@link ReduceBrightColorsPreferenceController} */
@RunWith(AndroidJUnit4.class)
public class ReduceBrightColorsPreferenceControllerTest {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final String PREF_KEY = "rbc_preference";
private Context mContext;
@@ -76,18 +86,123 @@
}
@Test
- public void isAvailable_configuredRbcAvailable_shouldReturnTrue() {
+ @DisableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOffAndDisabled_RbcOnAndAvailable_returnTrue() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
doReturn(true).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
+
assertThat(mController.isAvailable()).isTrue();
}
+
@Test
- public void isAvailable_configuredRbcUnAvailable_shouldReturnFalse() {
+ @DisableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOffAndDisabled_RbcOffAndAvailable_returnTrue() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOffAndDisabled_RbcOnAndUnavailable_returnFalse() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
doReturn(false).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
+
assertThat(mController.isAvailable()).isFalse();
}
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndDisabled_RbcOnAndAvailable_returnTrue() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndDisabled_RbcOffAndAvailable_returnTrue() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndDisabled_RbcOnAndUnavailable_returnFalse() {
+ doReturn(false).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
+ doReturn(false).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndEnabled_RbcOnAndAvailable_returnFalse() {
+ doReturn(true).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndEnabled_RbcOffAndAvailable_returnFalse() {
+ doReturn(true).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_EVEN_DIMMER)
+ public void isAvailable_whenEvenDimmerOnAndEnabled_RbcOnAndUnavailable_returnFalse() {
+ doReturn(true).when(mResources).getBoolean(
+ com.android.internal.R.bool.config_evenDimmerEnabled);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
+ doReturn(false).when(mResources).getBoolean(
+ R.bool.config_reduceBrightColorsAvailable);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+
private int resourceId(String type, String name) {
return mContext.getResources().getIdentifier(name, type, mContext.getPackageName());
}
diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
index 29e0c1c..776261a 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
@@ -17,6 +17,7 @@
package com.android.settings.deviceinfo.simstatus;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_DATA_NETWORK_TYPE_VALUE_ID;
+import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELLULAR_NETWORK_STATE;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_VOICE_NETWORK_TYPE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_VALUE_ID;
@@ -30,8 +31,10 @@
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SERVICE_STATE_VALUE_ID;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -42,6 +45,7 @@
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
import android.telephony.euicc.EuiccManager;
@@ -65,6 +69,7 @@
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Executor;
@RunWith(AndroidJUnit4.class)
public class SimStatusDialogControllerTest {
@@ -74,6 +79,10 @@
@Mock
private TelephonyManager mTelephonyManager;
@Mock
+ private TelephonyManager mTelephonyManagerForSub1;
+ @Mock
+ private TelephonyManager mTelephonyManagerForSub2;
+ @Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private ServiceState mServiceState;
@@ -94,6 +103,9 @@
private static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
+ private static final int TEST_SUB_ID_1 = 1;
+ private static final int TEST_SUB_ID_2 = 2;
+
@Before
@UiThreadTest
public void setup() {
@@ -106,6 +118,7 @@
mSubscriptionManager = spy(mContext.getSystemService(SubscriptionManager.class));
doReturn(mSubscriptionInfo).when(mSubscriptionManager)
.getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+ doReturn(TEST_SUB_ID_1).when(mSubscriptionInfo).getSubscriptionId();
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
@@ -113,8 +126,10 @@
when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
- doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
- anyInt());
+ doReturn(mTelephonyManagerForSub1).when(mTelephonyManager).createForSubscriptionId(
+ TEST_SUB_ID_1);
+ doReturn(mTelephonyManagerForSub2).when(mTelephonyManager).createForSubscriptionId(
+ TEST_SUB_ID_2);
doReturn(2).when(mTelephonyManager).getCardIdForDefaultEuicc();
doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mTelephonyManager).getVoiceNetworkType();
doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mTelephonyManager).getDataNetworkType();
@@ -341,4 +356,45 @@
verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_LABEL_ID, false);
verify(mDialog).setSettingVisibility(IMS_REGISTRATION_STATE_VALUE_ID, false);
}
+
+ @Test
+ public void onSubscriptionsChanged_updateSubInfoToNewSub_testTelephonyCallbackUnregRereg() {
+ // sub id changed from 1 to 2
+ SubscriptionInfo subInfo2 = mock(SubscriptionInfo.class);
+ doReturn(TEST_SUB_ID_2).when(subInfo2).getSubscriptionId();
+ doReturn(subInfo2).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+ mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+ verify(mTelephonyManagerForSub2).registerTelephonyCallback(any(Executor.class),
+ any(TelephonyCallback.class));
+
+ // sub id changed from 2 to 1
+ SubscriptionInfo subInfo1 = mock(SubscriptionInfo.class);
+ doReturn(TEST_SUB_ID_1).when(subInfo1).getSubscriptionId();
+ doReturn(subInfo1).when(mSubscriptionManager)
+ .getActiveSubscriptionInfoForSimSlotIndex(anyInt());
+ mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+ verify(mTelephonyManagerForSub2).unregisterTelephonyCallback(
+ mController.mTelephonyCallback);
+ verify(mTelephonyManagerForSub1).registerTelephonyCallback(any(Executor.class),
+ any(TelephonyCallback.class));
+ }
+
+ @Test
+ public void onSubscriptionsChanged_updateSubInfoToNull_testTelephonyCallbackUnreg() {
+ doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoForSimSlotIndex(
+ anyInt());
+ mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+ verify(mTelephonyManagerForSub1).unregisterTelephonyCallback(
+ mController.mTelephonyCallback);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_updateSubInfoToNull_shouldUpdateDataStatusToUnknown() {
+ doReturn(null).when(mSubscriptionManager).getActiveSubscriptionInfoForSimSlotIndex(
+ anyInt());
+ mController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+ final String unknownText = ResourcesUtils.getResourcesString(mContext, "radioInfo_unknown");
+ verify(mDialog).setText(CELLULAR_NETWORK_STATE, unknownText);
+ }
}
diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
index 82119f1..085a68d 100644
--- a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
@@ -16,13 +16,12 @@
package com.android.settings.network.telephony;
-import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA;
-import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS;
-
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertEquals;
+
import static org.mockito.Mockito.spy;
import android.content.Context;
@@ -35,8 +34,6 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.settings.R;
-
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -74,24 +71,6 @@
@Test
@Ignore("b/382664790")
- public void setPreferenceTitle_hasDataService_showConnectivity() {
- PreferenceManager preferenceManager = new PreferenceManager(mContext);
- PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
- PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
- preferenceCategory.setKey(KEY);
- preferenceCategory.addPreference(new Preference(mContext));
- preferenceScreen.addPreference(preferenceCategory);
- mController.displayPreference(preferenceScreen);
-
- mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
- new int[]{SERVICE_TYPE_DATA});
-
- assertThat(preferenceCategory.getTitle()).isEqualTo(
- mContext.getString(R.string.title_satellite_setting_connectivity));
- }
-
- @Test
- @Ignore("b/382664790")
public void setPreferenceTitle_hasSmsService_showMessaging() {
PreferenceManager preferenceManager = new PreferenceManager(mContext);
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
@@ -101,10 +80,6 @@
preferenceCategory.addPreference(new Preference(mContext));
mController.displayPreference(preferenceScreen);
- mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
- new int[]{SERVICE_TYPE_SMS});
-
- assertThat(preferenceCategory.getTitle()).isEqualTo(
- mContext.getString(R.string.satellite_setting_title));
+ assertEquals(preferenceCategory.getTitle(), "Satellite connectivity");
}
}
diff --git a/tests/unit/src/com/android/settings/notification/app/ChannelListPreferenceControllerTest.java b/tests/unit/src/com/android/settings/notification/app/ChannelListPreferenceControllerTest.java
index daa2afb..f68ba05 100644
--- a/tests/unit/src/com/android/settings/notification/app/ChannelListPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/notification/app/ChannelListPreferenceControllerTest.java
@@ -91,6 +91,14 @@
assertEquals("zeroCategories", mGroupList.getPreference(0).getKey());
}
+ // Test the case with no groups but hidden channels
+ inGroups = new ArrayList<>();
+ mController.mChannelCount = 1;
+ mController.updateFullList(mGroupList, inGroups);
+ {
+ assertEquals(0, mGroupList.getPreferenceCount());
+ }
+
// Test that adding a group clears the zero category and adds everything
NotificationChannelGroup inGroup1 = new NotificationChannelGroup("group1", "Group 1");
inGroup1.addChannel(new NotificationChannel("ch1a", "Channel 1A", IMPORTANCE_DEFAULT));
@@ -250,6 +258,7 @@
}
// Test that we go back to the empty state when clearing all groups and channels.
+ mController.mChannelCount = 0;
inGroups.clear();
mController.updateFullList(mGroupList, inGroups);
{
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index 71899fb..574b4a7 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -39,6 +39,9 @@
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceStatus;
@@ -50,6 +53,7 @@
import com.android.settings.Settings;
import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
+import com.android.settings.flags.Flags;
import com.android.settings.testutils.ActiveUnlockTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResourcesUtils;
@@ -57,6 +61,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -67,6 +72,7 @@
import java.util.Collections;
import java.util.List;
+@RequiresFlagsDisabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
@RunWith(AndroidJUnit4.class)
public class BiometricsSafetySourceTest {
@@ -75,6 +81,9 @@
private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private Context mApplicationContext;
@Mock private PackageManager mPackageManager;
@@ -196,7 +205,7 @@
@Test
public void setSafetySourceData_withFingerprintsEnrolled_whenDisabledByAdmin_setsData() {
- final int enrolledFingerprintsCount = 2;
+ int enrolledFingerprintsCount = 2;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
@@ -216,7 +225,7 @@
@Test
public void setSafetySourceData_withFingerprintsEnrolled_whenNotDisabledByAdmin_setsData() {
- final int enrolledFingerprintsCount = 2;
+ int enrolledFingerprintsCount = 2;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
@@ -364,7 +373,7 @@
@Test
public void setSafetySourceData_faceAndFingerprint_whenFaceEnrolled_withMpFingers_setsData() {
- final int enrolledFingerprintsCount = 2;
+ int enrolledFingerprintsCount = 2;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -382,7 +391,7 @@
@Test
public void setSafetySourceData_faceAndFingerprint_whenFaceEnrolled_withOneFinger_setsData() {
- final int enrolledFingerprintsCount = 1;
+ int enrolledFingerprintsCount = 1;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -417,7 +426,7 @@
@Test
public void setSafetySourceData_activeUnlockEnabled_withFingerprintOnly_setsData() {
- final int enrolledFingerprintsCount = 1;
+ int enrolledFingerprintsCount = 1;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
@@ -453,7 +462,7 @@
@Test
public void setSafetySourceData_activeUnlockEnabled_withFaceAndFingerprint_setsData() {
- final int enrolledFingerprintsCount = 1;
+ int enrolledFingerprintsCount = 1;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -472,7 +481,7 @@
@Test
public void setSafetySourceData_faceAndFingerprint_whenNoFaceEnrolled_withFingers_setsData() {
- final int enrolledFingerprintsCount = 1;
+ int enrolledFingerprintsCount = 1;
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -660,7 +669,7 @@
String expectedTitleResName,
String expectedSummaryResName,
int expectedSummaryQuantity) {
- final int stringResId =
+ int stringResId =
ResourcesUtils.getResourcesId(
ApplicationProvider.getApplicationContext(),
"string",
@@ -676,7 +685,7 @@
String expectedSummaryResName,
int expectedSummaryQuantity,
String expectedSettingsClassName) {
- final int stringResId =
+ int stringResId =
ResourcesUtils.getResourcesId(
ApplicationProvider.getApplicationContext(),
"string",
@@ -705,7 +714,7 @@
assertThat(safetySourceStatus.getSeverityLevel())
.isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
- final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
assertThat(clickIntent).isNotNull();
assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
}
@@ -725,14 +734,14 @@
assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
assertThat(safetySourceStatus.isEnabled()).isTrue();
- final Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ 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);
+ List<Fingerprint> fingerprintList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
fingerprintList.add(new Fingerprint("fingerprint" + i, 0, 0));
}
diff --git a/tests/unit/src/com/android/settings/safetycenter/FaceSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/FaceSafetySourceTest.java
new file mode 100644
index 0000000..e42a4d1
--- /dev/null
+++ b/tests/unit/src/com/android/settings/safetycenter/FaceSafetySourceTest.java
@@ -0,0 +1,302 @@
+/*
+ * 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.safetycenter;
+
+import static android.provider.Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS;
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+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.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.Settings;
+import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
+import com.android.settings.flags.Flags;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+@RunWith(AndroidJUnit4.class)
+public class FaceSafetySourceTest {
+
+ private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
+ private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+ private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
+ new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ private Context mApplicationContext;
+
+ @Mock private PackageManager mPackageManager;
+ @Mock private DevicePolicyManager mDevicePolicyManager;
+ @Mock private FaceManager mFaceManager;
+ @Mock private LockPatternUtils mLockPatternUtils;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ 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.DEVICE_POLICY_SERVICE))
+ .thenReturn(mDevicePolicyManager);
+ when(mApplicationContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
+ FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+ when(featureFactory.securityFeatureProvider.getLockPatternUtils(mApplicationContext))
+ .thenReturn(mLockPatternUtils);
+ doReturn(true).when(mLockPatternUtils).isSecure(anyInt());
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ }
+
+ @After
+ public void tearDown() {
+ SafetyCenterManagerWrapper.sInstance = null;
+ }
+
+ @Test
+ public void setSafetyData_whenSafetyCenterIsDisabled_doesNotSetData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper, never())
+ .setSafetySourceData(any(), any(), any(), any());
+ }
+
+ @Test
+ public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutFaceHardware_setsNullData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), eq(null), any());
+ }
+
+ @Test
+ public void setSafetySourceData_setsDataForFaceSource() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), any(), any());
+ }
+
+ @Test
+ public void setSafetySourceData_setsDataWithCorrectSafetyEvent() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), any(), eq(EVENT_SOURCE_STATE_CHANGED));
+ }
+
+ @Test
+ public void setSafetySourceData_withFaceNotEnrolled_whenDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceDisabledDataSetWithSingularSummary(
+ "security_settings_face_preference_title_new",
+ "security_settings_face_preference_summary_none");
+ }
+
+ @Test
+ public void setSafetySourceData_withFaceNotEnrolled_whenNotDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceEnabledDataSetWithSingularSummary(
+ "security_settings_face_preference_title_new",
+ "security_settings_face_preference_summary_none",
+ FaceEnrollIntroductionInternal.class.getName());
+ }
+
+ @Test
+ public void setSafetySourceData_withFaceEnrolled_whenDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceDisabledDataSetWithSingularSummary(
+ "security_settings_face_preference_title_new",
+ "security_settings_face_preference_summary");
+ }
+
+ @Test
+ public void setSafetySourceData_withFaceEnrolled_whenNotDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceEnabledDataSetWithSingularSummary(
+ "security_settings_face_preference_title_new",
+ "security_settings_face_preference_summary",
+ Settings.FaceSettingsInternalActivity.class.getName());
+ }
+
+ @Test
+ public void setSafetySourceData_face_whenEnrolled_setsInfoSeverity() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
+ }
+
+ @Test
+ public void setSafetySourceData_face_whenNotEnrolled_setsUnspSeverity() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+
+ FaceSafetySource.setSafetySourceData(mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
+ }
+
+ private void assertSafetySourceDisabledDataSetWithSingularSummary(
+ String expectedTitleResName, String expectedSummaryResName) {
+ assertSafetySourceDisabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName));
+ }
+
+ private void assertSafetySourceEnabledDataSetWithSingularSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ String expectedSettingsClassName) {
+ assertSafetySourceEnabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName),
+ expectedSettingsClassName);
+ }
+
+ private void assertSafetySourceDisabledDataSet(String expectedTitle, String expectedSummary) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isFalse();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
+
+ Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ assertThat(clickIntent).isNotNull();
+ assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ }
+
+ private void assertSafetySourceEnabledDataSet(
+ String expectedTitle, String expectedSummary, String expectedSettingsClassName) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), captor.capture(), any());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isTrue();
+ Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ assertThat(clickIntent).isNotNull();
+ assertThat(clickIntent.getComponent().getPackageName()).isEqualTo("com.android.settings");
+ assertThat(clickIntent.getComponent().getClassName()).isEqualTo(expectedSettingsClassName);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/safetycenter/FingerprintSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/FingerprintSafetySourceTest.java
new file mode 100644
index 0000000..8a34aaa
--- /dev/null
+++ b/tests/unit/src/com/android/settings/safetycenter/FingerprintSafetySourceTest.java
@@ -0,0 +1,381 @@
+/*
+ * 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.safetycenter;
+
+import static android.provider.Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS;
+import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+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.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.safetycenter.SafetyEvent;
+import android.safetycenter.SafetySourceData;
+import android.safetycenter.SafetySourceStatus;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.biometrics.fingerprint.FingerprintSettings;
+import com.android.settings.flags.Flags;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.ResourcesUtils;
+import com.android.settingslib.utils.StringUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+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.List;
+
+@RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+@RunWith(AndroidJUnit4.class)
+public class FingerprintSafetySourceTest {
+
+ private static final ComponentName COMPONENT_NAME = new ComponentName("package", "class");
+ private static final UserHandle USER_HANDLE = new UserHandle(UserHandle.myUserId());
+ private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
+ new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ private Context mApplicationContext;
+
+ @Mock private PackageManager mPackageManager;
+ @Mock private DevicePolicyManager mDevicePolicyManager;
+ @Mock private FingerprintManager mFingerprintManager;
+ @Mock private LockPatternUtils mLockPatternUtils;
+ @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ 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);
+ FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
+ when(featureFactory.securityFeatureProvider.getLockPatternUtils(mApplicationContext))
+ .thenReturn(mLockPatternUtils);
+ doReturn(true).when(mLockPatternUtils).isSecure(anyInt());
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ }
+
+ @After
+ public void tearDown() {
+ SafetyCenterManagerWrapper.sInstance = null;
+ }
+
+ @Test
+ public void setSafetyData_whenSafetyCenterIsDisabled_doesNotSetData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper, never())
+ .setSafetySourceData(any(), any(), any(), any());
+ }
+
+ @Test
+ public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutFingerprint_setsNullData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FingerprintSafetySource.SAFETY_SOURCE_ID), eq(null), any());
+ }
+
+ @Test
+ public void setSafetySourceData_setsDataForFingerprintSource() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FingerprintSafetySource.SAFETY_SOURCE_ID), any(), any());
+ }
+
+ @Test
+ public void setSafetySourceData_setsDataWithCorrectSafetyEvent() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), any(), any(), eq(EVENT_SOURCE_STATE_CHANGED));
+ }
+
+ @Test
+ public void setSafetySourceData_withFingerprintNotEnrolled_whenDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceDisabledDataSetWithSingularSummary(
+ "security_settings_fingerprint",
+ "security_settings_fingerprint_preference_summary_none");
+ }
+
+ @Test
+ public void setSafetySourceData_withFingerprintNotEnrolled_whenNotDisabledByAdmin_setsData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceEnabledDataSetWithSingularSummary(
+ "security_settings_fingerprint",
+ "security_settings_fingerprint_preference_summary_none",
+ FingerprintSettings.class.getName());
+ }
+
+ @Test
+ public void setSafetySourceData_withFingerprintsEnrolled_whenDisabledByAdmin_setsData() {
+ int enrolledFingerprintsCount = 2;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME))
+ .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceDisabledDataSetWithPluralSummary(
+ "security_settings_fingerprint",
+ "security_settings_fingerprint_preference_summary",
+ enrolledFingerprintsCount);
+ }
+
+ @Test
+ public void setSafetySourceData_withFingerprintsEnrolled_whenNotDisabledByAdmin_setsData() {
+ int enrolledFingerprintsCount = 2;
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+ when(mFingerprintManager.getEnrolledFingerprints(anyInt()))
+ .thenReturn(createFingerprintList(enrolledFingerprintsCount));
+ when(mDevicePolicyManager.getKeyguardDisabledFeatures(COMPONENT_NAME)).thenReturn(0);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ assertSafetySourceEnabledDataSetWithPluralSummary(
+ "security_settings_fingerprint",
+ "security_settings_fingerprint_preference_summary",
+ enrolledFingerprintsCount,
+ FingerprintSettings.class.getName());
+ }
+
+ @Test
+ public void setSafetySourceData_fingerprint_whenEnrolled_setsInfoSeverity() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(FingerprintSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
+ SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_INFORMATION);
+ }
+
+ @Test
+ public void setSafetySourceData_fingerprint_whenNotEnrolled_setsUnspSeverity() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
+
+ FingerprintSafetySource.setSafetySourceData(
+ mApplicationContext, EVENT_SOURCE_STATE_CHANGED);
+
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(FingerprintSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
+ SafetySourceStatus safetySourceStatus = captor.getValue().getStatus();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
+ }
+
+ private void assertSafetySourceDisabledDataSetWithSingularSummary(
+ String expectedTitleResName, String expectedSummaryResName) {
+ assertSafetySourceDisabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName));
+ }
+
+ private void assertSafetySourceEnabledDataSetWithSingularSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ String expectedSettingsClassName) {
+ assertSafetySourceEnabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedSummaryResName),
+ expectedSettingsClassName);
+ }
+
+ private void assertSafetySourceDisabledDataSetWithPluralSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ int expectedSummaryQuantity) {
+ int stringResId =
+ ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(),
+ "string",
+ expectedSummaryResName);
+ assertSafetySourceDisabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ StringUtil.getIcuPluralsString(
+ mApplicationContext, expectedSummaryQuantity, stringResId));
+ }
+
+ private void assertSafetySourceEnabledDataSetWithPluralSummary(
+ String expectedTitleResName,
+ String expectedSummaryResName,
+ int expectedSummaryQuantity,
+ String expectedSettingsClassName) {
+ int stringResId =
+ ResourcesUtils.getResourcesId(
+ ApplicationProvider.getApplicationContext(),
+ "string",
+ expectedSummaryResName);
+ assertSafetySourceEnabledDataSet(
+ ResourcesUtils.getResourcesString(mApplicationContext, expectedTitleResName),
+ StringUtil.getIcuPluralsString(
+ mApplicationContext, expectedSummaryQuantity, stringResId),
+ expectedSettingsClassName);
+ }
+
+ private void assertSafetySourceDisabledDataSet(String expectedTitle, String expectedSummary) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(FingerprintSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isFalse();
+ assertThat(safetySourceStatus.getSeverityLevel())
+ .isEqualTo(SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED);
+
+ Intent clickIntent = safetySourceStatus.getPendingIntent().getIntent();
+ assertThat(clickIntent).isNotNull();
+ assertThat(clickIntent.getAction()).isEqualTo(ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+ }
+
+ private void assertSafetySourceEnabledDataSet(
+ String expectedTitle, String expectedSummary, String expectedSettingsClassName) {
+ ArgumentCaptor<SafetySourceData> captor = ArgumentCaptor.forClass(SafetySourceData.class);
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(),
+ eq(FingerprintSafetySource.SAFETY_SOURCE_ID),
+ captor.capture(),
+ any());
+ SafetySourceData safetySourceData = captor.getValue();
+ SafetySourceStatus safetySourceStatus = safetySourceData.getStatus();
+
+ assertThat(safetySourceStatus.getTitle().toString()).isEqualTo(expectedTitle);
+ assertThat(safetySourceStatus.getSummary().toString()).isEqualTo(expectedSummary);
+ assertThat(safetySourceStatus.isEnabled()).isTrue();
+ 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) {
+ 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 e528c4e..f16113a 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -29,6 +29,10 @@
import android.content.Context;
import android.content.Intent;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceIssue;
@@ -39,12 +43,14 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.flags.Flags;
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -62,6 +68,9 @@
private static final SafetyEvent EVENT_SOURCE_STATE_CHANGED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private Context mApplicationContext;
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
@@ -486,7 +495,9 @@
}
@Test
- public void onLockScreenChange_whenSafetyCenterEnabled_setsLockscreenAndBiometricData() {
+ @RequiresFlagsDisabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void
+ onLockScreenChange_whenSafetyCenterEnabled_flagOff_setsLockscreenAndBiometricData() {
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
@@ -501,6 +512,24 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void onLockScreenChange_whenSafetyCenterEnabled_flagOn_setsLockscreenAndBiometricData() {
+ whenScreenLockIsEnabled();
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+
+ LockScreenSafetySource.onLockScreenChange(mApplicationContext);
+
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(LockScreenSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(any(), eq(FaceSafetySource.SAFETY_SOURCE_ID), any(), any());
+ verify(mSafetyCenterManagerWrapper)
+ .setSafetySourceData(
+ any(), eq(FingerprintSafetySource.SAFETY_SOURCE_ID), any(), any());
+ }
+
+ @Test
public void onLockScreenChange_whenSafetyCenterDisabled_doesNotSetData() {
whenScreenLockIsEnabled();
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
index cd4c3c6..a0a5327 100644
--- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java
@@ -21,8 +21,11 @@
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -30,7 +33,10 @@
import android.content.Context;
import android.content.Intent;
-import android.os.Flags;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
@@ -39,6 +45,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.flags.Flags;
import com.android.settings.privatespace.PrivateSpaceSafetySource;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -51,7 +58,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -61,6 +67,9 @@
private Context mApplicationContext;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
@Mock private LockPatternUtils mLockPatternUtils;
@@ -202,6 +211,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
public void onReceive_onRefresh_withBiometricsSourceId_setsBiometricData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
Intent intent =
@@ -220,9 +230,49 @@
assertThat(captor.getValue()).isEqualTo(BiometricsSafetySource.SAFETY_SOURCE_ID);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void onReceive_onRefresh_withFaceUnlockSourceId_setsFaceUnlockData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ Intent intent =
+ new Intent()
+ .setAction(ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(
+ EXTRA_REFRESH_SAFETY_SOURCE_IDS,
+ new String[] {FaceSafetySource.SAFETY_SOURCE_ID})
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
+
+ new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mSafetyCenterManagerWrapper, times(1))
+ .setSafetySourceData(any(), captor.capture(), any(), any());
+
+ assertThat(captor.getValue()).isEqualTo(FaceSafetySource.SAFETY_SOURCE_ID);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void onReceive_onRefresh_withFingerprintUnlockSourceId_setsFingerprintUnlockData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ Intent intent =
+ new Intent()
+ .setAction(ACTION_REFRESH_SAFETY_SOURCES)
+ .putExtra(
+ EXTRA_REFRESH_SAFETY_SOURCE_IDS,
+ new String[] {FingerprintSafetySource.SAFETY_SOURCE_ID})
+ .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
+
+ new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mSafetyCenterManagerWrapper, times(1))
+ .setSafetySourceData(any(), captor.capture(), any(), any());
+
+ assertThat(captor.getValue()).isEqualTo(FingerprintSafetySource.SAFETY_SOURCE_ID);
+ }
+
/**
- * Tests that on receiving the refresh broadcast request with the PS source id, the PS data
- * is set.
+ * Tests that on receiving the refresh broadcast request with the PS source id, the PS data is
+ * set.
*/
@Test
public void onReceive_onRefresh_withPrivateSpaceSourceId_setsPrivateSpaceData() {
@@ -247,7 +297,8 @@
@Test
public void onReceive_onRefresh_withPrivateSpaceFeatureDisabled_setsNullData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
- mSetFlagsRule.disableFlags(Flags.FLAG_ALLOW_PRIVATE_PROFILE,
+ mSetFlagsRule.disableFlags(
+ android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,
android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
Intent intent =
@@ -273,16 +324,48 @@
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
- verify(mSafetyCenterManagerWrapper, times(3))
+ verify(mSafetyCenterManagerWrapper, atLeastOnce())
.setSafetySourceData(any(), any(), any(), captor.capture());
SafetyEvent bootEvent = new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
- assertThat(captor.getAllValues())
- .containsExactlyElementsIn(Arrays.asList(bootEvent, bootEvent, bootEvent));
+ assertThat(captor.getAllValues()).contains(bootEvent);
}
@Test
- public void onReceive_onBootCompleted_sendsAllSafetySourcesData() {
+ @RequiresFlagsEnabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void onReceive_onBootCompleted_flagOn_sendsAllSafetySourcesData() {
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
+ Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED);
+
+ new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mSafetyCenterManagerWrapper, times(4))
+ .setSafetySourceData(any(), captor.capture(), any(), any());
+ List<String> safetySourceIdList = captor.getAllValues();
+
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(id -> id.equals(LockScreenSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(id -> id.equals(FaceSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(
+ id -> id.equals(FingerprintSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(
+ id -> id.equals(PrivateSpaceSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
+ public void onReceive_onBootCompleted_flagOff_sendsAllSafetySourcesData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED);
@@ -292,11 +375,18 @@
.setSafetySourceData(any(), captor.capture(), any(), any());
List<String> safetySourceIdList = captor.getAllValues();
- assertThat(safetySourceIdList.stream().anyMatch(
- id -> id.equals(LockScreenSafetySource.SAFETY_SOURCE_ID))).isTrue();
- assertThat(safetySourceIdList.stream().anyMatch(
- id -> id.equals(BiometricsSafetySource.SAFETY_SOURCE_ID))).isTrue();
- assertThat(safetySourceIdList.stream().anyMatch(
- id -> id.equals(PrivateSpaceSafetySource.SAFETY_SOURCE_ID))).isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(id -> id.equals(LockScreenSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(id -> id.equals(BiometricsSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
+ assertThat(
+ safetySourceIdList.stream()
+ .anyMatch(
+ id -> id.equals(PrivateSpaceSafetySource.SAFETY_SOURCE_ID)))
+ .isTrue();
}
}
diff --git a/tests/unit/src/com/android/settings/wifi/WifiSwitchPreferenceTest.kt b/tests/unit/src/com/android/settings/wifi/WifiSwitchPreferenceTest.kt
index ca2ae8e..eb437dd 100644
--- a/tests/unit/src/com/android/settings/wifi/WifiSwitchPreferenceTest.kt
+++ b/tests/unit/src/com/android/settings/wifi/WifiSwitchPreferenceTest.kt
@@ -16,11 +16,19 @@
package com.android.settings.wifi
+import android.app.settings.SettingsEnums.ACTION_WIFI_OFF
+import android.app.settings.SettingsEnums.ACTION_WIFI_ON
import android.content.ContextWrapper
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.wifi.WifiManager
import androidx.preference.SwitchPreferenceCompat
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.testutils.FakeFeatureFactory
import com.android.settingslib.preference.createAndBindWidget
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -28,11 +36,13 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class WifiSwitchPreferenceTest {
private val mockWifiManager = mock<WifiManager>()
+ private val mockConnectivityManager = mock<ConnectivityManager>()
private val context =
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
@@ -41,6 +51,7 @@
override fun getSystemService(name: String): Any? =
when (name) {
getSystemServiceName(WifiManager::class.java) -> mockWifiManager
+ getSystemServiceName(ConnectivityManager::class.java) -> mockConnectivityManager
else -> super.getSystemService(name)
}
}
@@ -66,6 +77,35 @@
}
@Test
+ fun setValue_valueTrue_metricsActionWifiOn() {
+ val metricsFeatureProvider = FakeFeatureFactory.setupForTest().metricsFeatureProvider
+
+ wifiSwitchPreference.storage(context).setBoolean(WifiSwitchPreference.KEY, true)
+
+ verify(metricsFeatureProvider).action(context, ACTION_WIFI_ON)
+ }
+
+ @Test
+ fun setValue_valueFalseWithoutDefaultWifi_metricsActionWifiOffWithFalse() {
+ val metricsFeatureProvider = FakeFeatureFactory.setupForTest().metricsFeatureProvider
+ mockDefaultNetwork(TRANSPORT_CELLULAR)
+
+ wifiSwitchPreference.storage(context).setBoolean(WifiSwitchPreference.KEY, false)
+
+ verify(metricsFeatureProvider).action(context, ACTION_WIFI_OFF, false)
+ }
+
+ @Test
+ fun setValue_valueFalseWithDefaultWifi_metricsActionWifiOffWithTrue() {
+ val metricsFeatureProvider = FakeFeatureFactory.setupForTest().metricsFeatureProvider
+ mockDefaultNetwork(TRANSPORT_WIFI)
+
+ wifiSwitchPreference.storage(context).setBoolean(WifiSwitchPreference.KEY, false)
+
+ verify(metricsFeatureProvider).action(context, ACTION_WIFI_OFF, true)
+ }
+
+ @Test
fun performClick_defaultOn_checkedIsFalse() {
mockWifiManager.stub { on { isWifiEnabled } doReturn true }
@@ -85,4 +125,16 @@
private fun getSwitchPreference(): SwitchPreferenceCompat =
wifiSwitchPreference.createAndBindWidget(context)
+
+ private fun mockDefaultNetwork(transportType: Int) {
+ val mockNetwork = mock<Network>()
+ val networkCapabilities =
+ NetworkCapabilities.Builder.withoutDefaultCapabilities()
+ .addTransportType(transportType)
+ .build()
+ mockConnectivityManager.stub {
+ on { activeNetwork } doReturn mockNetwork
+ on { getNetworkCapabilities(mockNetwork) } doReturn networkCapabilities
+ }
+ }
}
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
index 1ce05f8..80a98fc 100644
--- a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceControllerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -32,6 +33,10 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.factory.WifiFeatureProvider;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -70,6 +75,10 @@
.setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN).build();
when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mWifiManager.getSoftApConfiguration()).thenReturn(mConfig);
+ WifiHotspotRepository repository = mock(WifiHotspotRepository.class);
+ when(repository.isSpeedFeatureAvailable()).thenReturn(false);
+ WifiFeatureProvider provider = FakeFeatureFactory.setupForTest().getWifiFeatureProvider();
+ when(provider.getWifiHotspotRepository()).thenReturn(repository);
mController = new WifiTetherSecurityPreferenceController(context, mListener);
if (Looper.myLooper() == null) {