Snap for 13204655 from 67b21fb238
to 25Q2-release
Change-Id: I14e3b84b0d79c7a1aa38226e732171a517a0a95b
This commit is contained in:
@@ -139,6 +139,7 @@ android_library {
|
|||||||
"aconfig_settings_flags",
|
"aconfig_settings_flags",
|
||||||
"aconfig_settingslib_flags",
|
"aconfig_settingslib_flags",
|
||||||
"android.app.flags-aconfig",
|
"android.app.flags-aconfig",
|
||||||
|
"android.app.supervision.flags-aconfig",
|
||||||
"android.provider.flags-aconfig",
|
"android.provider.flags-aconfig",
|
||||||
"android.security.flags-aconfig",
|
"android.security.flags-aconfig",
|
||||||
"android.view.contentprotection.flags-aconfig",
|
"android.view.contentprotection.flags-aconfig",
|
||||||
|
@@ -2817,6 +2817,15 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".supervision.ConfirmSupervisionCredentialsActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:featureFlag="android.app.supervision.flags.supervision_manager_apis">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.app.supervision.action.CONFIRM_SUPERVISION_CREDENTIALS" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".SetupRedactionInterstitial"
|
<activity android:name=".SetupRedactionInterstitial"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
12
aconfig/settings_desktop_flag_declarations.aconfig
Normal file
12
aconfig/settings_desktop_flag_declarations.aconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package: "com.android.settings.flags"
|
||||||
|
container: "system_ext"
|
||||||
|
|
||||||
|
flag {
|
||||||
|
name: "settings_search_result_deep_link_in_same_task"
|
||||||
|
namespace: "desktop_personalization"
|
||||||
|
description: "Show the search result deep link in the same task (same window)"
|
||||||
|
bug: "381127948"
|
||||||
|
metadata {
|
||||||
|
purpose: PURPOSE_BUGFIX
|
||||||
|
}
|
||||||
|
}
|
@@ -122,20 +122,38 @@
|
|||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
<SeekBar
|
<LinearLayout
|
||||||
android:id="@+id/input_setting_keys_value_custom_slider"
|
android:id="@+id/input_setting_keys_custom_seekbar_layout"
|
||||||
android:paddingStart="8dp"
|
android:orientation="horizontal"
|
||||||
android:paddingEnd="36dp"
|
|
||||||
android:min="1"
|
|
||||||
android:max="50"
|
|
||||||
android:progressBackgroundTint="@color/input_dialog_slider_progress_background"
|
|
||||||
android:progressTint="@color/input_dialog_slider_progress"
|
|
||||||
android:thumbTint="@color/input_dialog_slider_progress"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginTop="8dp"
|
android:gravity="center_vertical"
|
||||||
android:visibility="gone"/>
|
android:paddingEnd="36dp">
|
||||||
|
<ImageView
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:tint="@androidprv:color/materialColorPrimary"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_remove_24dp" />
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/input_setting_keys_value_custom_slider"
|
||||||
|
style="@android:style/Widget.Material.SeekBar"
|
||||||
|
android:min="1"
|
||||||
|
android:max="50"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="16dp"
|
||||||
|
android:tint="@androidprv:color/materialColorPrimary"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_add_24dp" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
@@ -94,8 +94,5 @@
|
|||||||
<!-- Volume seekbar colors -->
|
<!-- Volume seekbar colors -->
|
||||||
<color name="seekbar_thumb_tint_color">@android:color/system_accent1_100</color>
|
<color name="seekbar_thumb_tint_color">@android:color/system_accent1_100</color>
|
||||||
<color name="seekbar_progress_tint_color">@android:color/system_accent1_100</color>
|
<color name="seekbar_progress_tint_color">@android:color/system_accent1_100</color>
|
||||||
|
|
||||||
<!-- Keyboard a11y input dialog -->
|
|
||||||
<color name="input_dialog_slider_progress">@android:color/system_on_primary_container_dark</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
@@ -1059,6 +1059,20 @@
|
|||||||
<item>either_charging_or_docked</item>
|
<item>either_charging_or_docked</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="when_to_start_hubmode_entries" translatable="false">
|
||||||
|
<item>@string/when_to_show_hubmode_never</item>
|
||||||
|
<item>@string/when_to_show_hubmode_charging</item>
|
||||||
|
<item>@string/when_to_show_hubmode_charging_and_upright</item>
|
||||||
|
<item>@string/when_to_show_hubmode_docked</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="when_to_start_hubmode_values" translatable="false">
|
||||||
|
<item>never</item>
|
||||||
|
<item>while_charging</item>
|
||||||
|
<item>while_charging_and_upright</item>
|
||||||
|
<item>while_docked</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="zen_mode_contacts_calls_entries" translatable="false">
|
<string-array name="zen_mode_contacts_calls_entries" translatable="false">
|
||||||
<item>@string/zen_mode_from_anyone</item>
|
<item>@string/zen_mode_from_anyone</item>
|
||||||
<item>@string/zen_mode_from_contacts</item>
|
<item>@string/zen_mode_from_contacts</item>
|
||||||
|
@@ -64,8 +64,8 @@
|
|||||||
<color name="homepage_sound_background">@color/homepage_pink_bg</color>
|
<color name="homepage_sound_background">@color/homepage_pink_bg</color>
|
||||||
<color name="homepage_modes_foreground">@color/homepage_pink_fg</color>
|
<color name="homepage_modes_foreground">@color/homepage_pink_fg</color>
|
||||||
<color name="homepage_modes_background">@color/homepage_pink_bg</color>
|
<color name="homepage_modes_background">@color/homepage_pink_bg</color>
|
||||||
<color name="homepage_hub_mode_foreground">@color/homepage_pink_fg</color>
|
<color name="homepage_hub_mode_foreground">@color/homepage_orange_fg</color>
|
||||||
<color name="homepage_hub_mode_background">@color/homepage_pink_bg</color>
|
<color name="homepage_hub_mode_background">@color/homepage_orange_bg</color>
|
||||||
<color name="homepage_display_foreground">@color/homepage_orange_fg</color>
|
<color name="homepage_display_foreground">@color/homepage_orange_fg</color>
|
||||||
<color name="homepage_display_background">@color/homepage_orange_bg</color>
|
<color name="homepage_display_background">@color/homepage_orange_bg</color>
|
||||||
<color name="homepage_wallpaper_foreground">@color/homepage_orange_fg</color>
|
<color name="homepage_wallpaper_foreground">@color/homepage_orange_fg</color>
|
||||||
@@ -275,8 +275,4 @@
|
|||||||
<color name="seekbar_thumb_tint_color">@android:color/system_accent1_800</color>
|
<color name="seekbar_thumb_tint_color">@android:color/system_accent1_800</color>
|
||||||
<color name="seekbar_progress_tint_color">@android:color/system_accent1_800</color>
|
<color name="seekbar_progress_tint_color">@android:color/system_accent1_800</color>
|
||||||
<color name="seekbar_progress_background_tint_color">@android:color/system_neutral2_50</color>
|
<color name="seekbar_progress_background_tint_color">@android:color/system_neutral2_50</color>
|
||||||
|
|
||||||
<!-- Keyboard a11y input dialog -->
|
|
||||||
<color name="input_dialog_slider_progress">@android:color/system_on_primary_dark</color>
|
|
||||||
<color name="input_dialog_slider_progress_background">@android:color/system_outline_light</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -810,13 +810,23 @@
|
|||||||
<!-- Allowed packages to show the confirmation dialog for a system locale suggestion -->
|
<!-- Allowed packages to show the confirmation dialog for a system locale suggestion -->
|
||||||
<string-array name="allowed_packages_for_locale_confirmation_diallog" translatable="false"/>
|
<string-array name="allowed_packages_for_locale_confirmation_diallog" translatable="false"/>
|
||||||
|
|
||||||
<!-- Array of text reading preview layouts. Must contain at least 1 layout -->
|
<!-- Array of text reading preview layouts. Must contain at least 1 layout.
|
||||||
|
Add content descriptions in the config_text_reading_preview_content_descriptions together
|
||||||
|
if adding more sample layouts here -->
|
||||||
<array name="config_text_reading_preview_samples">
|
<array name="config_text_reading_preview_samples">
|
||||||
<item>@layout/accessibility_text_reading_preview_app_grid</item>
|
<item>@layout/accessibility_text_reading_preview_app_grid</item>
|
||||||
<item>@layout/screen_zoom_preview_1</item>
|
<item>@layout/screen_zoom_preview_1</item>
|
||||||
<item>@layout/accessibility_text_reading_preview_mail_content</item>
|
<item>@layout/accessibility_text_reading_preview_mail_content</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<!-- Array of text reading preview layouts' content descriptions.
|
||||||
|
The order should be the same as the layouts in config_text_reading_preview_samples -->
|
||||||
|
<array name="config_text_reading_preview_content_descriptions">
|
||||||
|
<item>@string/preview_pager_home_content_description</item>
|
||||||
|
<item>@string/preview_pager_message_content_description</item>
|
||||||
|
<item>@string/preview_pager_email_content_description</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<!-- Package responsible for updating Mainline Modules -->
|
<!-- Package responsible for updating Mainline Modules -->
|
||||||
<string name="config_mainline_module_update_package" translatable="false">com.android.vending</string>
|
<string name="config_mainline_module_update_package" translatable="false">com.android.vending</string>
|
||||||
|
|
||||||
|
@@ -78,6 +78,12 @@
|
|||||||
|
|
||||||
<!-- Content description for preview pager. [CHAR LIMIT=NONE] -->
|
<!-- Content description for preview pager. [CHAR LIMIT=NONE] -->
|
||||||
<string name="preview_pager_content_description">Preview</string>
|
<string name="preview_pager_content_description">Preview</string>
|
||||||
|
<!-- Content description for home screen preview. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="preview_pager_home_content_description">Home screen preview</string>
|
||||||
|
<!-- Content description for message preview. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="preview_pager_message_content_description">Message preview</string>
|
||||||
|
<!-- Content description for email preview. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="preview_pager_email_content_description">Email preview</string>
|
||||||
<!-- Content description for qrcode image. [CHAR LIMIT=none]-->
|
<!-- Content description for qrcode image. [CHAR LIMIT=none]-->
|
||||||
<string name="qr_code_content_description">QR code</string>
|
<string name="qr_code_content_description">QR code</string>
|
||||||
<!-- Previous button for preview pager. [CHAR LIMIT=NONE] -->
|
<!-- Previous button for preview pager. [CHAR LIMIT=NONE] -->
|
||||||
@@ -497,7 +503,7 @@
|
|||||||
<string name="link_locale_picker_footer_learn_more" translatable="false">https://support.google.com/android?p=per_language_app_settings</string>
|
<string name="link_locale_picker_footer_learn_more" translatable="false">https://support.google.com/android?p=per_language_app_settings</string>
|
||||||
|
|
||||||
<!-- Title for asking to change system region or not. [CHAR LIMIT=50]-->
|
<!-- Title for asking to change system region or not. [CHAR LIMIT=50]-->
|
||||||
<string name="title_change_system_region">Change region to %s ?</string>
|
<string name="title_change_system_region">Change region to %s?</string>
|
||||||
|
|
||||||
<!-- The content of a confirmation dialog indicating the impact when the user change the system region. [CHAR LIMIT=NONE]-->
|
<!-- The content of a confirmation dialog indicating the impact when the user change the system region. [CHAR LIMIT=NONE]-->
|
||||||
<string name="desc_notice_device_region_change">Your device will keep %s as a system language</string>
|
<string name="desc_notice_device_region_change">Your device will keep %s as a system language</string>
|
||||||
@@ -506,7 +512,7 @@
|
|||||||
<string name="desc_notice_device_region_change_for_preferred_language">%1$s will replace %2$s in your preferred languages</string>
|
<string name="desc_notice_device_region_change_for_preferred_language">%1$s will replace %2$s in your preferred languages</string>
|
||||||
|
|
||||||
<!-- Title for asking to change system locale or not. [CHAR LIMIT=50]-->
|
<!-- Title for asking to change system locale or not. [CHAR LIMIT=50]-->
|
||||||
<string name="title_change_system_locale">Change system language to %s ?</string>
|
<string name="title_change_system_locale">Change system language to %s?</string>
|
||||||
|
|
||||||
<!-- The title of a confirmation dialog to indicate adding a system locale. [CHAR LIMIT=50]-->
|
<!-- The title of a confirmation dialog to indicate adding a system locale. [CHAR LIMIT=50]-->
|
||||||
<string name="title_system_locale_addition">Add %s to preferred languages?</string>
|
<string name="title_system_locale_addition">Add %s to preferred languages?</string>
|
||||||
@@ -547,7 +553,7 @@
|
|||||||
<!-- Category for more language settings. [CHAR LIMIT=NONE]-->
|
<!-- Category for more language settings. [CHAR LIMIT=NONE]-->
|
||||||
<string name="more_language_settings_category">More language settings</string>
|
<string name="more_language_settings_category">More language settings</string>
|
||||||
<!-- Title for asking to change system locale region or not. [CHAR LIMIT=50]-->
|
<!-- Title for asking to change system locale region or not. [CHAR LIMIT=50]-->
|
||||||
<string name="title_change_system_locale_region">Change region to <xliff:g id="system_language_region" example="Canada">%1$s</xliff:g> ?</string>
|
<string name="title_change_system_locale_region">Change region to <xliff:g id="system_language_region" example="Canada">%1$s</xliff:g>?</string>
|
||||||
<!-- Message for asking to change system locale region or not. [CHAR LIMIT=50]-->
|
<!-- Message for asking to change system locale region or not. [CHAR LIMIT=50]-->
|
||||||
<string name="body_change_system_locale_region">Your device will keep <xliff:g id="system_language" example="English">%1$s</xliff:g> as a system language</string>
|
<string name="body_change_system_locale_region">Your device will keep <xliff:g id="system_language" example="English">%1$s</xliff:g> as a system language</string>
|
||||||
<!-- Description for the numbering system language. [CHAR LIMIT=NONE]-->
|
<!-- Description for the numbering system language. [CHAR LIMIT=NONE]-->
|
||||||
@@ -833,6 +839,8 @@
|
|||||||
<string name="security_settings_face_preference_summary">Face added</string>
|
<string name="security_settings_face_preference_summary">Face added</string>
|
||||||
<!-- Message shown in summary field when Face Unlock is not set up. [CHAR LIMIT=54] -->
|
<!-- 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>
|
<string name="security_settings_face_preference_summary_none">Setup needed</string>
|
||||||
|
<!-- Message shown in summary field when Face Unlock is not set up. [CHAR LIMIT=54] -->
|
||||||
|
<string name="security_settings_face_preference_summary_none_new">Add face</string>
|
||||||
<!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
|
<!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
|
||||||
<string name="security_settings_face_preference_title_new">Face</string>
|
<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] -->
|
<!-- Title shown for menu item that launches face settings or enrollment, for work profile. [CHAR LIMIT=50] -->
|
||||||
@@ -1006,6 +1014,8 @@
|
|||||||
}</string>
|
}</string>
|
||||||
<!-- message shown in summary field when no fingerprints are registered -->
|
<!-- message shown in summary field when no fingerprints are registered -->
|
||||||
<string name="security_settings_fingerprint_preference_summary_none">Setup needed</string>
|
<string name="security_settings_fingerprint_preference_summary_none">Setup needed</string>
|
||||||
|
<!-- message shown in summary field when no fingerprints are registered -->
|
||||||
|
<string name="security_settings_fingerprint_preference_summary_none_new">Add fingerprint</string>
|
||||||
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature [CHAR LIMIT=29] -->
|
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature [CHAR LIMIT=29] -->
|
||||||
<string name="security_settings_fingerprint_enroll_introduction_title">Set up your fingerprint</string>
|
<string name="security_settings_fingerprint_enroll_introduction_title">Set up your fingerprint</string>
|
||||||
<!-- Introduction title shown in fingerprint enrollment when asking for parental consent for fingerprint unlock [CHAR LIMIT=29] -->
|
<!-- Introduction title shown in fingerprint enrollment when asking for parental consent for fingerprint unlock [CHAR LIMIT=29] -->
|
||||||
@@ -1771,6 +1781,8 @@
|
|||||||
|
|
||||||
<!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
|
<!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
|
||||||
<string name="unlock_set_unlock_mode_off">None</string>
|
<string name="unlock_set_unlock_mode_off">None</string>
|
||||||
|
<!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
|
||||||
|
<string name="unlock_set_unlock_mode_off_new">Add PIN, pattern, password, or swipe</string>
|
||||||
<!-- Summary for "Configure lockscreen" when security is disabled [CHAR LIMIT=45] -->
|
<!-- Summary for "Configure lockscreen" when security is disabled [CHAR LIMIT=45] -->
|
||||||
<string name="unlock_set_unlock_mode_none">Swipe</string>
|
<string name="unlock_set_unlock_mode_none">Swipe</string>
|
||||||
<!-- Summary for "Configure lockscreen" when security pattern is enabled [CHAR LIMIT=45] -->
|
<!-- Summary for "Configure lockscreen" when security pattern is enabled [CHAR LIMIT=45] -->
|
||||||
@@ -3655,6 +3667,21 @@
|
|||||||
<string name="communal_settings_title">Communal</string>
|
<string name="communal_settings_title">Communal</string>
|
||||||
<!-- Summary of the communal settings under Settings > Communal [CHAR LIMIT=50] -->
|
<!-- Summary of the communal settings under Settings > Communal [CHAR LIMIT=50] -->
|
||||||
<string name="communal_settings_summary">Communal settings</string>
|
<string name="communal_settings_summary">Communal settings</string>
|
||||||
|
<!-- Title of Hub mode category [CHAR LIMIT=30] -->
|
||||||
|
<string name="hub_mode_category_title">Hub mode</string>
|
||||||
|
<!-- Title of the "widgets on lockscreen" settings page. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="widgets_on_lockscreen_title">Widgets on lock screen</string>
|
||||||
|
|
||||||
|
<!-- Title of a setting to control when to automatically show widgets on the lockscren. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="when_to_auto_show_hubmode_title">When to automatically show</string>
|
||||||
|
<!-- Summary for when to automatically show hub mode (widgets on lockscreen): never [CHAR LIMIT=100] -->
|
||||||
|
<string name="when_to_show_hubmode_never">Never</string>
|
||||||
|
<!-- Summary for when to automatically show hub mode (widgets on lockscreen): charging [CHAR LIMIT=100] -->
|
||||||
|
<string name="when_to_show_hubmode_charging">While charging</string>
|
||||||
|
<!-- Summary for when to automatically show hub mode (widgets on lockscreen): charging and upright [CHAR LIMIT=100] -->
|
||||||
|
<string name="when_to_show_hubmode_charging_and_upright">While charging and upright</string>
|
||||||
|
<!-- Summary for when to automatically show hub mode (widgets on lockscreen): docked [CHAR LIMIT=100] -->
|
||||||
|
<string name="when_to_show_hubmode_docked">While docked</string>
|
||||||
|
|
||||||
<!-- _satellite_setting_preference_layout -->
|
<!-- _satellite_setting_preference_layout -->
|
||||||
<!-- _satellite_setting_preference_layout screen title-->
|
<!-- _satellite_setting_preference_layout screen title-->
|
||||||
@@ -3897,6 +3924,18 @@
|
|||||||
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
||||||
<string name="bluetooth_tether_checkbox_text">Bluetooth tethering</string>
|
<string name="bluetooth_tether_checkbox_text">Bluetooth tethering</string>
|
||||||
|
|
||||||
|
<!-- Ethernet settings-->
|
||||||
|
<!-- Label for ethernet IP address [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="ethernet_ip_address">IP address</string>
|
||||||
|
<!-- Label for ethernet MAC address [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="ethernet_mac_address_title">MAC address</string>
|
||||||
|
<!-- Label for ethernet transfer speed [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="tx_ethernet_speed">Transit link speed</string>
|
||||||
|
<!-- Label for ethernet receive speed [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="rx_ethernet_speed">Receive link speed</string>
|
||||||
|
<!-- Label for ethernet network usage [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="ethernet_network_usage">Network usage</string>
|
||||||
|
|
||||||
<!-- Ethernet Tethering settings-->
|
<!-- Ethernet Tethering settings-->
|
||||||
<!-- Label for ethernet tether checkbox [CHAR LIMIT=NONE]-->
|
<!-- Label for ethernet tether checkbox [CHAR LIMIT=NONE]-->
|
||||||
<string name="ethernet_tether_checkbox_text">Ethernet tethering</string>
|
<string name="ethernet_tether_checkbox_text">Ethernet tethering</string>
|
||||||
@@ -5691,6 +5730,9 @@
|
|||||||
<string name="accessibility_autoclick_longer_desc">Longer</string>
|
<string name="accessibility_autoclick_longer_desc">Longer</string>
|
||||||
<!-- Description for the seekbar that adjust auto click time. [CHAR_LIMIT=NONE] -->
|
<!-- Description for the seekbar that adjust auto click time. [CHAR_LIMIT=NONE] -->
|
||||||
<string name="accessibility_autoclick_seekbar_desc">Auto click time</string>
|
<string name="accessibility_autoclick_seekbar_desc">Auto click time</string>
|
||||||
|
<!-- Title for the toggle button that turns on/off the autoclick setting. [CHAR_LIMIT=NONE] -->
|
||||||
|
<!-- TODO(b/394683600): Update string to translatable once approved by UXW. -->
|
||||||
|
<string name="accessibility_autoclick_main_switch_title" translatable="false">Use autoclick</string>
|
||||||
<!-- Title for the toggle button that turns on/off the autoclick shortcut. [CHAR_LIMIT=NONE] -->
|
<!-- Title for the toggle button that turns on/off the autoclick shortcut. [CHAR_LIMIT=NONE] -->
|
||||||
<!-- TODO(b/394683600): Update string to translatable once approved by UXW. -->
|
<!-- TODO(b/394683600): Update string to translatable once approved by UXW. -->
|
||||||
<string name="accessibility_autoclick_shortcut_title" translatable="false">Autoclick shortcut</string>
|
<string name="accessibility_autoclick_shortcut_title" translatable="false">Autoclick shortcut</string>
|
||||||
@@ -14309,5 +14351,7 @@ Data usage charges may apply.</string>
|
|||||||
<!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] -->
|
<!-- Title for web content filters browser category allow all sites option [CHAR LIMIT=60] -->
|
||||||
<string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string>
|
<string name="supervision_web_content_filters_browser_allow_all_sites_title">Allow all sites</string>
|
||||||
<!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] -->
|
<!-- Generic content description that is attached to the preview illustration at the top of an Accessibility feature toggle page. [CHAR LIMIT=NONE] -->
|
||||||
|
<!-- Title for supervision PIN verification screen [CHAR LIMIT=60] -->
|
||||||
|
<string name="supervision_full_screen_pin_verification_title">Enter supervision PIN</string>
|
||||||
<string name="accessibility_illustration_content_description"><xliff:g id="feature" example="Select to Speak">%1$s</xliff:g> animation</string>
|
<string name="accessibility_illustration_content_description"><xliff:g id="feature" example="Select to Speak">%1$s</xliff:g> animation</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -30,6 +30,11 @@
|
|||||||
settings:searchable="false"
|
settings:searchable="false"
|
||||||
settings:lottie_rawRes="@drawable/accessibility_dwell"/>
|
settings:lottie_rawRes="@drawable/accessibility_dwell"/>
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.MainSwitchPreference
|
||||||
|
android:key="accessibility_autoclick_main_switch"
|
||||||
|
android:title="@string/accessibility_autoclick_main_switch_title"
|
||||||
|
settings:controller="com.android.settings.accessibility.ToggleAutoclickMainSwitchPreferenceController"/>
|
||||||
|
|
||||||
<com.android.settings.accessibility.ShortcutPreference
|
<com.android.settings.accessibility.ShortcutPreference
|
||||||
android:key="autoclick_shortcut_preference"
|
android:key="autoclick_shortcut_preference"
|
||||||
android:title="@string/accessibility_autoclick_shortcut_title"
|
android:title="@string/accessibility_autoclick_shortcut_title"
|
||||||
|
@@ -88,6 +88,12 @@
|
|||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:title="@string/accessibility_text_reading_options_title"
|
android:title="@string/accessibility_text_reading_options_title"
|
||||||
settings:controller="com.android.settings.accessibility.TextReadingFragmentForDisplaySettingsController"/>
|
settings:controller="com.android.settings.accessibility.TextReadingFragmentForDisplaySettingsController"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="widgets_on_lockscreen"
|
||||||
|
android:title="@string/widgets_on_lockscreen_title"
|
||||||
|
android:fragment="com.android.settings.communal.WidgetsOnLockscreenFragment"
|
||||||
|
settings:controller="com.android.settings.display.WidgetsOnLockscreenPreferenceController"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
@@ -24,4 +24,36 @@
|
|||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
android:order="-10000"/>
|
android:order="-10000"/>
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="metered"
|
||||||
|
android:icon="@drawable/ic_attach_money_black_24dp"
|
||||||
|
android:title="@string/wifi_metered_title"
|
||||||
|
android:entries="@array/wifi_metered_entries"
|
||||||
|
android:entryValues="@array/wifi_metered_values"/>
|
||||||
|
|
||||||
|
<!-- Network Details -->
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="ip_details_category">
|
||||||
|
<Preference
|
||||||
|
android:key="ethernet_ip_address"
|
||||||
|
android:title="@string/ethernet_ip_address"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:enableCopying="true"/>
|
||||||
|
<Preference
|
||||||
|
android:key="ethernet_mac_address"
|
||||||
|
android:title="@string/ethernet_mac_address_title"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:enableCopying="true"/>
|
||||||
|
<Preference
|
||||||
|
android:key="ethernet_tx_link_speed"
|
||||||
|
android:title="@string/tx_ethernet_speed"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:enableCopying="true"/>
|
||||||
|
<Preference
|
||||||
|
android:key="ethernet_rx_link_speed"
|
||||||
|
android:title="@string/rx_ethernet_speed"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:enableCopying="true"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
android:order="10"
|
android:order="10"
|
||||||
settings:controller="com.android.settings.inputmethod.MousePointerAccelerationPreferenceController" />
|
settings:controller="com.android.settings.inputmethod.MousePointerAccelerationPreferenceController" />
|
||||||
|
|
||||||
<com.android.settings.widget.SeekBarPreference
|
<com.android.settings.widget.LabeledSeekBarPreference
|
||||||
android:key="pointer_speed"
|
android:key="pointer_speed"
|
||||||
android:title="@string/pointer_speed"
|
android:title="@string/pointer_speed"
|
||||||
android:order="20"
|
android:order="20"
|
||||||
@@ -50,32 +50,24 @@
|
|||||||
android:summary="@string/accessibility_pointer_and_touchpad_summary"
|
android:summary="@string/accessibility_pointer_and_touchpad_summary"
|
||||||
settings:searchable="true"/>
|
settings:searchable="true"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<SwitchPreferenceCompat
|
||||||
android:key="pointer_category"
|
android:key="mouse_reverse_vertical_scrolling"
|
||||||
android:persistent="false"
|
android:order="52"
|
||||||
android:order="51"
|
android:title="@string/mouse_reverse_vertical_scrolling"
|
||||||
android:title="@string/mouse_scrolling_category_title">
|
android:summary="@string/mouse_reverse_vertical_scrolling_summary"
|
||||||
|
settings:controller="com.android.settings.inputmethod.MouseReverseVerticalScrollingPreferenceController" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="mouse_reverse_vertical_scrolling"
|
android:order="55"
|
||||||
android:order="52"
|
android:key="mouse_scrolling_acceleration"
|
||||||
android:title="@string/mouse_reverse_vertical_scrolling"
|
android:title="@string/mouse_scrolling_acceleration"
|
||||||
android:summary="@string/mouse_reverse_vertical_scrolling_summary"
|
settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
|
||||||
settings:controller="com.android.settings.inputmethod.MouseReverseVerticalScrollingPreferenceController" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<com.android.settings.widget.LabeledSeekBarPreference
|
||||||
android:order="55"
|
android:key="mouse_scrolling_speed"
|
||||||
android:key="mouse_scrolling_acceleration"
|
android:title="@string/mouse_scrolling_speed"
|
||||||
android:title="@string/mouse_scrolling_acceleration"
|
android:order="60"
|
||||||
settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
|
android:selectable="false"
|
||||||
|
settings:controller="com.android.settings.inputmethod.MouseScrollingSpeedPreferenceController"/>
|
||||||
<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"/>
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@@ -61,7 +61,7 @@
|
|||||||
settings:controller="com.android.settings.inputmethod.TouchpadAccelerationPreferenceController"
|
settings:controller="com.android.settings.inputmethod.TouchpadAccelerationPreferenceController"
|
||||||
android:order="38"/>
|
android:order="38"/>
|
||||||
|
|
||||||
<com.android.settings.widget.SeekBarPreference
|
<com.android.settings.widget.LabeledSeekBarPreference
|
||||||
android:key="touchpad_pointer_speed"
|
android:key="touchpad_pointer_speed"
|
||||||
android:title="@string/trackpad_pointer_speed"
|
android:title="@string/trackpad_pointer_speed"
|
||||||
android:order="40"
|
android:order="40"
|
||||||
|
19
res/xml/when_to_start_hubmode_settings.xml
Normal file
19
res/xml/when_to_start_hubmode_settings.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:title="@string/when_to_auto_show_hubmode_title" />
|
29
res/xml/widgets_on_lockscreen_settings.xml
Normal file
29
res/xml/widgets_on_lockscreen_settings.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:key="widgets_on_lockscreen"
|
||||||
|
android:title="@string/widgets_on_lockscreen_title">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="when_to_start"
|
||||||
|
android:title="@string/when_to_auto_show_hubmode_title"
|
||||||
|
android:fragment="com.android.settings.communal.WhenToStartHubPicker"
|
||||||
|
settings:controller="com.android.settings.communal.WhenToStartHubPreferenceController" />
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
@@ -104,11 +104,13 @@ class TextReadingPreviewController extends BasePreferenceController implements
|
|||||||
final boolean isLayoutRtl =
|
final boolean isLayoutRtl =
|
||||||
origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
||||||
final int[] previewSamples = getPreviewSampleLayouts(mContext);
|
final int[] previewSamples = getPreviewSampleLayouts(mContext);
|
||||||
|
final int[] previewContentDescriptions = getPreviewSampleContentDescriptions(mContext);
|
||||||
final PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(mContext, isLayoutRtl,
|
final PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(mContext, isLayoutRtl,
|
||||||
previewSamples, createConfig(origConfig));
|
previewSamples, createConfig(origConfig));
|
||||||
mPreviewPreference.setPreviewAdapter(pagerAdapter);
|
mPreviewPreference.setPreviewAdapter(pagerAdapter);
|
||||||
mPreviewPreference.setCurrentItem(
|
mPreviewPreference.setCurrentItem(
|
||||||
isLayoutRtl ? previewSamples.length - 1 : FRAME_INITIAL_INDEX);
|
isLayoutRtl ? previewSamples.length - 1 : FRAME_INITIAL_INDEX);
|
||||||
|
mPreviewPreference.setContentDescription(previewContentDescriptions);
|
||||||
|
|
||||||
final int initialPagerIndex =
|
final int initialPagerIndex =
|
||||||
mLastFontProgress * mDisplaySizeData.getValues().size() + mLastDisplayProgress;
|
mLastFontProgress * mDisplaySizeData.getValues().size() + mLastDisplayProgress;
|
||||||
@@ -188,6 +190,20 @@ class TextReadingPreviewController extends BasePreferenceController implements
|
|||||||
return previewSamples;
|
return previewSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
|
static int[] getPreviewSampleContentDescriptions(Context context) {
|
||||||
|
TypedArray typedArray = context.getResources().obtainTypedArray(
|
||||||
|
R.array.config_text_reading_preview_content_descriptions);
|
||||||
|
int previewCount = typedArray.length();
|
||||||
|
int[] previewContentDescriptions = new int[previewCount];
|
||||||
|
for (int i = 0; i < previewCount; i++) {
|
||||||
|
previewContentDescriptions[i] =
|
||||||
|
typedArray.getResourceId(i, R.string.preview_pager_content_description);
|
||||||
|
}
|
||||||
|
typedArray.recycle();
|
||||||
|
return previewContentDescriptions;
|
||||||
|
}
|
||||||
|
|
||||||
private int getPagerIndex() {
|
private int getPagerIndex() {
|
||||||
final int displayDataSize = mDisplaySizeData.getValues().size();
|
final int displayDataSize = mDisplaySizeData.getValues().size();
|
||||||
final int fontSizeProgress = mFontSizePreference.getProgress();
|
final int fontSizeProgress = mFontSizePreference.getProgress();
|
||||||
|
@@ -43,28 +43,11 @@ public class TextReadingPreviewPreference extends Preference {
|
|||||||
private int mCurrentItem;
|
private int mCurrentItem;
|
||||||
private int mLastLayerIndex;
|
private int mLastLayerIndex;
|
||||||
private PreviewPagerAdapter mPreviewAdapter;
|
private PreviewPagerAdapter mPreviewAdapter;
|
||||||
|
private int[] mContentDescriptions;
|
||||||
|
|
||||||
private int mLayoutMinHorizontalPadding = 0;
|
private int mLayoutMinHorizontalPadding = 0;
|
||||||
private int mBackgroundMinHorizontalPadding = 0;
|
private int mBackgroundMinHorizontalPadding = 0;
|
||||||
|
|
||||||
private final ViewPager.OnPageChangeListener mPageChangeListener =
|
|
||||||
new ViewPager.OnPageChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onPageScrolled(int i, float v, int i1) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageSelected(int i) {
|
|
||||||
mCurrentItem = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageScrollStateChanged(int i) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TextReadingPreviewPreference(Context context) {
|
TextReadingPreviewPreference(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
init();
|
init();
|
||||||
@@ -95,7 +78,23 @@ public class TextReadingPreviewPreference extends Preference {
|
|||||||
adjustPaddings(previewLayout, backgroundView);
|
adjustPaddings(previewLayout, backgroundView);
|
||||||
|
|
||||||
final ViewPager viewPager = (ViewPager) holder.findViewById(R.id.preview_pager);
|
final ViewPager viewPager = (ViewPager) holder.findViewById(R.id.preview_pager);
|
||||||
viewPager.addOnPageChangeListener(mPageChangeListener);
|
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int i, float v, int i1) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int i) {
|
||||||
|
mCurrentItem = i;
|
||||||
|
viewPager.setContentDescription(getContext().getString(mContentDescriptions[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int i) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
final DotsPageIndicator pageIndicator =
|
final DotsPageIndicator pageIndicator =
|
||||||
(DotsPageIndicator) holder.findViewById(R.id.page_indicator);
|
(DotsPageIndicator) holder.findViewById(R.id.page_indicator);
|
||||||
updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
|
updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
|
||||||
@@ -122,6 +121,10 @@ public class TextReadingPreviewPreference extends Preference {
|
|||||||
viewPager.setCurrentItem(getCurrentItem() + 1));
|
viewPager.setCurrentItem(getCurrentItem() + 1));
|
||||||
nextButton.setContentDescription(getContext().getString(
|
nextButton.setContentDescription(getContext().getString(
|
||||||
R.string.preview_pager_next_button));
|
R.string.preview_pager_next_button));
|
||||||
|
|
||||||
|
// Initialize the content description since the OnPageChangeListener#onPageSelected won't
|
||||||
|
// be called during setup.
|
||||||
|
viewPager.setContentDescription(getContext().getString(mContentDescriptions[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -170,6 +173,10 @@ public class TextReadingPreviewPreference extends Preference {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setContentDescription(int[] stringIds) {
|
||||||
|
mContentDescriptions = stringIds;
|
||||||
|
}
|
||||||
|
|
||||||
void setPreviewAdapter(PreviewPagerAdapter previewAdapter) {
|
void setPreviewAdapter(PreviewPagerAdapter previewAdapter) {
|
||||||
if (previewAdapter != mPreviewAdapter) {
|
if (previewAdapter != mPreviewAdapter) {
|
||||||
mPreviewAdapter = previewAdapter;
|
mPreviewAdapter = previewAdapter;
|
||||||
|
@@ -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.accessibility;
|
||||||
|
|
||||||
|
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||||
|
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.server.accessibility.Flags;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.TogglePreferenceController;
|
||||||
|
|
||||||
|
/** The controller to handle main switch to turn on or turn off accessibility autoclick. */
|
||||||
|
public class ToggleAutoclickMainSwitchPreferenceController
|
||||||
|
extends TogglePreferenceController {
|
||||||
|
|
||||||
|
private final ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
public ToggleAutoclickMainSwitchPreferenceController(
|
||||||
|
@NonNull Context context, @NonNull String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
mContentResolver = context.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return Flags.enableAutoclickIndicator() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
return Settings.Secure.getInt(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, OFF) == ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setChecked(boolean isChecked) {
|
||||||
|
Settings.Secure.putInt(mContentResolver,
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
|
||||||
|
isChecked ? ON : OFF);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSliceHighlightMenuRes() {
|
||||||
|
return R.string.menu_key_system;
|
||||||
|
}
|
||||||
|
}
|
5
src/com/android/settings/applications/appcompat/OWNERS
Normal file
5
src/com/android/settings/applications/appcompat/OWNERS
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Bug component: 970984
|
||||||
|
# Large Screen Experiences App Compat
|
||||||
|
gracielawputri@google.com
|
||||||
|
mcarli@google.com
|
||||||
|
mariiasand@google.com
|
@@ -30,7 +30,7 @@ class BiometricSettingsProvider : ContentProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||||
throw UnsupportedOperationException("query operation not supported currently.")
|
throw UnsupportedOperationException("delete operation not supported currently.")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(uri: Uri): String? {
|
override fun getType(uri: Uri): String? {
|
||||||
|
@@ -31,6 +31,7 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
|
import com.android.settingslib.supervision.SupervisionRestrictionsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for things at the cross-section of biometrics and parental controls. For example,
|
* Utilities for things at the cross-section of biometrics and parental controls. For example,
|
||||||
@@ -59,12 +60,7 @@ public class ParentalControlsUtils {
|
|||||||
UserManager.DISALLOW_BIOMETRIC, userHandle);
|
UserManager.DISALLOW_BIOMETRIC, userHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
|
return parentConsentRequiredInternal(context, modality, userHandle);
|
||||||
final SupervisionManager sm =
|
|
||||||
android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()
|
|
||||||
? context.getSystemService(SupervisionManager.class)
|
|
||||||
: null;
|
|
||||||
return parentConsentRequiredInternal(dpm, sm, modality, userHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,18 +70,22 @@ public class ParentalControlsUtils {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static RestrictedLockUtils.EnforcedAdmin parentConsentRequiredInternal(
|
static RestrictedLockUtils.EnforcedAdmin parentConsentRequiredInternal(
|
||||||
@NonNull DevicePolicyManager dpm,
|
@NonNull Context context,
|
||||||
@Nullable SupervisionManager sm,
|
|
||||||
@BiometricAuthenticator.Modality int modality,
|
@BiometricAuthenticator.Modality int modality,
|
||||||
@NonNull UserHandle userHandle) {
|
@NonNull UserHandle userHandle) {
|
||||||
|
final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
|
||||||
|
final SupervisionManager sm =
|
||||||
|
android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()
|
||||||
|
? context.getSystemService(SupervisionManager.class)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!ParentalControlsUtilsInternal.parentConsentRequired(
|
if (!ParentalControlsUtilsInternal.parentConsentRequired(
|
||||||
dpm, sm, modality, userHandle)) {
|
dpm, sm, modality, userHandle)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()) {
|
if (android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()) {
|
||||||
// Supervision doesn't necessarily have have an admin component.
|
return SupervisionRestrictionsHelper.createEnforcedAdmin(
|
||||||
return new RestrictedLockUtils.EnforcedAdmin(
|
context, UserManager.DISALLOW_BIOMETRIC, userHandle);
|
||||||
/* component= */ null, UserManager.DISALLOW_BIOMETRIC, userHandle);
|
|
||||||
} else {
|
} else {
|
||||||
final ComponentName cn =
|
final ComponentName cn =
|
||||||
ParentalControlsUtilsInternal.getSupervisionComponentName(dpm, userHandle);
|
ParentalControlsUtilsInternal.getSupervisionComponentName(dpm, userHandle);
|
||||||
|
@@ -70,6 +70,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
|
|
||||||
private static final String TAG = "FaceSettings";
|
private static final String TAG = "FaceSettings";
|
||||||
private static final String KEY_TOKEN = "hw_auth_token";
|
private static final String KEY_TOKEN = "hw_auth_token";
|
||||||
|
private static final String KEY_CONFIRMING_PASSWORD = "confirming_password";
|
||||||
private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
|
private static final String KEY_RE_ENROLL_FACE = "re_enroll_face_unlock";
|
||||||
private static final String KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED =
|
private static final String KEY_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED =
|
||||||
"biometrics_successfully_authenticated";
|
"biometrics_successfully_authenticated";
|
||||||
@@ -163,6 +164,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putByteArray(KEY_TOKEN, mToken);
|
outState.putByteArray(KEY_TOKEN, mToken);
|
||||||
|
outState.putBoolean(KEY_CONFIRMING_PASSWORD, mConfirmingPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -273,6 +275,7 @@ public class FaceSettings extends DashboardFragment {
|
|||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mToken = savedInstanceState.getByteArray(KEY_TOKEN);
|
mToken = savedInstanceState.getByteArray(KEY_TOKEN);
|
||||||
|
mConfirmingPassword = savedInstanceState.getBoolean(KEY_CONFIRMING_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Flags.biometricsOnboardingEducation()) {
|
if (Flags.biometricsOnboardingEducation()) {
|
||||||
|
@@ -98,11 +98,14 @@ public class FaceStatusUtils {
|
|||||||
return mContext.getString(
|
return mContext.getString(
|
||||||
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||||
} else {
|
} else {
|
||||||
|
int summaryNoneResId = Flags.biometricsOnboardingEducation()
|
||||||
|
? R.string.security_settings_face_preference_summary_none_new
|
||||||
|
: R.string.security_settings_face_preference_summary_none;
|
||||||
return mContext.getResources()
|
return mContext.getResources()
|
||||||
.getString(
|
.getString(
|
||||||
hasEnrolled()
|
hasEnrolled()
|
||||||
? R.string.security_settings_face_preference_summary
|
? R.string.security_settings_face_preference_summary
|
||||||
: R.string.security_settings_face_preference_summary_none);
|
: summaryNoneResId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -108,7 +108,9 @@ public class FingerprintStatusUtils {
|
|||||||
R.string.security_settings_fingerprint_preference_summary);
|
R.string.security_settings_fingerprint_preference_summary);
|
||||||
} else {
|
} else {
|
||||||
return mContext.getString(
|
return mContext.getString(
|
||||||
R.string.security_settings_fingerprint_preference_summary_none);
|
Flags.biometricsOnboardingEducation()
|
||||||
|
? R.string.security_settings_fingerprint_preference_summary_none_new
|
||||||
|
: R.string.security_settings_fingerprint_preference_summary_none);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,15 +39,14 @@ public class CommunalPreferenceController extends BasePreferenceController {
|
|||||||
* Returns whether communal preferences are available.
|
* Returns whether communal preferences are available.
|
||||||
*/
|
*/
|
||||||
public static boolean isAvailable(Context context) {
|
public static boolean isAvailable(Context context) {
|
||||||
|
if (com.android.systemui.Flags.glanceableHubV2()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Utils.canCurrentUserDream(context)) {
|
if (!Utils.canCurrentUserDream(context)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.getResources().getBoolean(R.bool.config_show_communal_settings)) {
|
return context.getResources().getBoolean(R.bool.config_show_communal_settings);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return com.android.systemui.Flags.glanceableHubV2()
|
|
||||||
&& context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
179
src/com/android/settings/communal/WhenToStartHubPicker.java
Normal file
179
src/com/android/settings/communal/WhenToStartHubPicker.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* 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.communal;
|
||||||
|
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_DOCKED;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_NEVER;
|
||||||
|
import static android.provider.Settings.Secure.WHEN_TO_START_GLANCEABLE_HUB;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.widget.RadioButtonPickerFragment;
|
||||||
|
import com.android.settingslib.widget.CandidateInfo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment that provides radio buttons to allow the user to choose when the hub should auto-start.
|
||||||
|
*/
|
||||||
|
public class WhenToStartHubPicker extends RadioButtonPickerFragment {
|
||||||
|
private static final String TAG = "WhenToStartHubPicker";
|
||||||
|
private static final String SHOW_WHILE_CHARGING = "while_charging";
|
||||||
|
private static final String SHOW_WHILE_DOCKED = "while_docked";
|
||||||
|
private static final String SHOW_WHILE_CHARGING_AND_UPRIGHT = "while_charging_and_upright";
|
||||||
|
private static final String SHOW_NEVER = "never";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(@NonNull Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.when_to_start_hubmode_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.WHEN_TO_SHOW_WIDGETS_ON_LOCKSCREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<? extends CandidateInfo> getCandidates() {
|
||||||
|
final List<WhenToStartHubCandidateInfo> candidates = new ArrayList<>();
|
||||||
|
|
||||||
|
final String[] entries = entries();
|
||||||
|
final String[] values = keys();
|
||||||
|
|
||||||
|
if (entries == null || entries.length <= 0) return candidates;
|
||||||
|
if (values == null || values.length != entries.length) {
|
||||||
|
throw new IllegalArgumentException("Entries and values must be of the same length.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.length; i++) {
|
||||||
|
candidates.add(new WhenToStartHubCandidateInfo(entries[i], values[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] entries() {
|
||||||
|
return getResources().getStringArray(R.array.when_to_start_hubmode_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] keys() {
|
||||||
|
return getResources().getStringArray(R.array.when_to_start_hubmode_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDefaultKey() {
|
||||||
|
final int defaultValue = mContext.getResources().getInteger(
|
||||||
|
com.android.internal.R.integer.config_whenToStartHubModeDefault);
|
||||||
|
final int setting = Settings.Secure.getInt(
|
||||||
|
mContext.getContentResolver(), WHEN_TO_START_GLANCEABLE_HUB, defaultValue);
|
||||||
|
return getKeyFromSetting(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean setDefaultKey(String key) {
|
||||||
|
Settings.Secure.putInt(
|
||||||
|
mContext.getContentResolver(),
|
||||||
|
WHEN_TO_START_GLANCEABLE_HUB,
|
||||||
|
getSettingFromPrefKey(key));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSelectionPerformed(boolean success) {
|
||||||
|
super.onSelectionPerformed(success);
|
||||||
|
|
||||||
|
getActivity().finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Settings.Secure.WhenToStartGlanceableHub
|
||||||
|
private static int getSettingFromPrefKey(String key) {
|
||||||
|
switch (key) {
|
||||||
|
case SHOW_WHILE_CHARGING:
|
||||||
|
return GLANCEABLE_HUB_START_CHARGING;
|
||||||
|
case SHOW_WHILE_DOCKED:
|
||||||
|
return GLANCEABLE_HUB_START_DOCKED;
|
||||||
|
case SHOW_WHILE_CHARGING_AND_UPRIGHT:
|
||||||
|
return GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
|
||||||
|
case SHOW_NEVER:
|
||||||
|
default:
|
||||||
|
return GLANCEABLE_HUB_START_NEVER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getKeyFromSetting(@Settings.Secure.WhenToStartGlanceableHub int setting) {
|
||||||
|
switch (setting) {
|
||||||
|
case GLANCEABLE_HUB_START_CHARGING:
|
||||||
|
return SHOW_WHILE_CHARGING;
|
||||||
|
case GLANCEABLE_HUB_START_DOCKED:
|
||||||
|
return SHOW_WHILE_DOCKED;
|
||||||
|
case GLANCEABLE_HUB_START_CHARGING_UPRIGHT:
|
||||||
|
return SHOW_WHILE_CHARGING_AND_UPRIGHT;
|
||||||
|
case GLANCEABLE_HUB_START_NEVER:
|
||||||
|
default:
|
||||||
|
return SHOW_NEVER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class WhenToStartHubCandidateInfo extends CandidateInfo {
|
||||||
|
private final String mName;
|
||||||
|
private final String mKey;
|
||||||
|
|
||||||
|
WhenToStartHubCandidateInfo(String title, String value) {
|
||||||
|
super(true);
|
||||||
|
|
||||||
|
mName = title;
|
||||||
|
mKey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence loadLabel() {
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Drawable loadIcon() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return mKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.communal;
|
||||||
|
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_DOCKED;
|
||||||
|
import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_NEVER;
|
||||||
|
import static android.provider.Settings.Secure.WHEN_TO_START_GLANCEABLE_HUB;
|
||||||
|
|
||||||
|
import android.annotation.StringRes;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.core.PreferenceControllerMixin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A preference controller that is responsible for showing the "when to auto start hub" setting in
|
||||||
|
* hub settings.
|
||||||
|
*/
|
||||||
|
public class WhenToStartHubPreferenceController extends BasePreferenceController implements
|
||||||
|
PreferenceControllerMixin {
|
||||||
|
public WhenToStartHubPreferenceController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
|
||||||
|
preference.setSummary(getSummaryResId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence getSummary() {
|
||||||
|
return mContext.getString(getSummaryResId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@StringRes
|
||||||
|
private int getSummaryResId() {
|
||||||
|
final int setting = Settings.Secure.getInt(
|
||||||
|
mContext.getContentResolver(),
|
||||||
|
WHEN_TO_START_GLANCEABLE_HUB,
|
||||||
|
GLANCEABLE_HUB_START_NEVER);
|
||||||
|
|
||||||
|
switch (setting) {
|
||||||
|
case GLANCEABLE_HUB_START_CHARGING:
|
||||||
|
return R.string.when_to_show_hubmode_charging;
|
||||||
|
case GLANCEABLE_HUB_START_DOCKED:
|
||||||
|
return R.string.when_to_show_hubmode_docked;
|
||||||
|
case GLANCEABLE_HUB_START_CHARGING_UPRIGHT:
|
||||||
|
return R.string.when_to_show_hubmode_charging_and_upright;
|
||||||
|
case GLANCEABLE_HUB_START_NEVER:
|
||||||
|
default:
|
||||||
|
return R.string.when_to_show_hubmode_never;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.communal;
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment that contains settings related to communal hub.
|
||||||
|
*/
|
||||||
|
@SearchIndexable
|
||||||
|
public class WidgetsOnLockscreenFragment extends DashboardFragment {
|
||||||
|
private static final String TAG = "WidgetsOnLockscreenFragment";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.WIDGETS_ON_LOCK_SCREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return R.xml.widgets_on_lockscreen_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getLogTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
|
new BaseSearchIndexProvider(R.xml.widgets_on_lockscreen_settings);
|
||||||
|
}
|
@@ -26,9 +26,14 @@ import android.bluetooth.BluetoothLeBroadcastAssistant;
|
|||||||
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.ContentObserver;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -87,6 +92,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
||||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||||
|
@Nullable private final ContentResolver mContentResolver;
|
||||||
private final Executor mExecutor;
|
private final Executor mExecutor;
|
||||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
@Nullable private PreferenceGroup mPreferenceGroup;
|
@Nullable private PreferenceGroup mPreferenceGroup;
|
||||||
@@ -187,6 +193,17 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
@NonNull BluetoothLeBroadcastReceiveState state) {}
|
@NonNull BluetoothLeBroadcastReceiveState state) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
ContentObserver mSettingsObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
Log.d(TAG, "onChange, primary group id has been changed, refresh list");
|
||||||
|
if (mBluetoothDeviceUpdater != null) {
|
||||||
|
mBluetoothDeviceUpdater.refreshPreference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public AudioSharingDevicePreferenceController(Context context) {
|
public AudioSharingDevicePreferenceController(Context context) {
|
||||||
super(context, KEY);
|
super(context, KEY);
|
||||||
mBtManager = Utils.getLocalBtManager(mContext);
|
mBtManager = Utils.getLocalBtManager(mContext);
|
||||||
@@ -198,6 +215,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
mProfileManager == null
|
mProfileManager == null
|
||||||
? null
|
? null
|
||||||
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
||||||
|
mContentResolver = context.getContentResolver();
|
||||||
mExecutor = Executors.newSingleThreadExecutor();
|
mExecutor = Executors.newSingleThreadExecutor();
|
||||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||||
}
|
}
|
||||||
@@ -217,6 +235,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
if (mEventManager == null
|
if (mEventManager == null
|
||||||
|| mAssistant == null
|
|| mAssistant == null
|
||||||
|| mDialogHandler == null
|
|| mDialogHandler == null
|
||||||
|
|| mContentResolver == null
|
||||||
|| mBluetoothDeviceUpdater == null) {
|
|| mBluetoothDeviceUpdater == null) {
|
||||||
Log.d(TAG, "Skip onStart(), profile is not ready.");
|
Log.d(TAG, "Skip onStart(), profile is not ready.");
|
||||||
return;
|
return;
|
||||||
@@ -225,6 +244,10 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
mEventManager.registerCallback(this);
|
mEventManager.registerCallback(this);
|
||||||
mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
||||||
mDialogHandler.registerCallbacks(mExecutor);
|
mDialogHandler.registerCallbacks(mExecutor);
|
||||||
|
mContentResolver.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(BluetoothUtils.getPrimaryGroupIdUriForBroadcast()),
|
||||||
|
false,
|
||||||
|
mSettingsObserver);
|
||||||
mBluetoothDeviceUpdater.registerCallback();
|
mBluetoothDeviceUpdater.registerCallback();
|
||||||
mBluetoothDeviceUpdater.refreshPreference();
|
mBluetoothDeviceUpdater.refreshPreference();
|
||||||
mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext));
|
mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext));
|
||||||
@@ -245,6 +268,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
if (mEventManager == null
|
if (mEventManager == null
|
||||||
|| mAssistant == null
|
|| mAssistant == null
|
||||||
|| mDialogHandler == null
|
|| mDialogHandler == null
|
||||||
|
|| mContentResolver == null
|
||||||
|| mBluetoothDeviceUpdater == null) {
|
|| mBluetoothDeviceUpdater == null) {
|
||||||
Log.d(TAG, "Skip onStop(), profile is not ready.");
|
Log.d(TAG, "Skip onStop(), profile is not ready.");
|
||||||
return;
|
return;
|
||||||
@@ -253,6 +277,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
mEventManager.unregisterCallback(this);
|
mEventManager.unregisterCallback(this);
|
||||||
mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
|
mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
|
||||||
mDialogHandler.unregisterCallbacks();
|
mDialogHandler.unregisterCallbacks();
|
||||||
|
mContentResolver.unregisterContentObserver(mSettingsObserver);
|
||||||
mBluetoothDeviceUpdater.unregisterCallback();
|
mBluetoothDeviceUpdater.unregisterCallback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,7 @@ import com.android.settings.dashboard.DashboardFragment;
|
|||||||
import com.android.settings.widget.EntityHeaderController;
|
import com.android.settings.widget.EntityHeaderController;
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
@@ -88,8 +89,10 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
|||||||
var localSourceState = getLocalSourceState(state);
|
var localSourceState = getLocalSourceState(state);
|
||||||
if (localSourceState == STREAMING) {
|
if (localSourceState == STREAMING) {
|
||||||
updateSummary();
|
updateSummary();
|
||||||
mAudioStreamsHelper.startMediaService(
|
if (!Flags.audioStreamMediaServiceByReceiveState()) {
|
||||||
mContext, mBroadcastId, mBroadcastName);
|
mAudioStreamsHelper.startMediaService(
|
||||||
|
mContext, mBroadcastId, mBroadcastName);
|
||||||
|
}
|
||||||
} else if (mHysteresisModeFixAvailable && localSourceState == PAUSED) {
|
} else if (mHysteresisModeFixAvailable && localSourceState == PAUSED) {
|
||||||
// if source paused, only update the summary
|
// if source paused, only update the summary
|
||||||
updateSummary();
|
updateSummary();
|
||||||
|
@@ -16,9 +16,13 @@
|
|||||||
|
|
||||||
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
||||||
|
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PRIVATE_BROADCAST_RECEIVE_DATA;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.DECRYPTION_FAILED;
|
||||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
@@ -56,11 +60,14 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
|||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.PrivateBroadcastReceiveData;
|
||||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AudioStreamMediaService extends Service {
|
public class AudioStreamMediaService extends Service {
|
||||||
@@ -103,7 +110,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
private final PlaybackState.Builder mPlayStateHysteresisBuilder =
|
private final PlaybackState.Builder mPlayStateHysteresisBuilder =
|
||||||
new PlaybackState.Builder()
|
new PlaybackState.Builder()
|
||||||
.setState(
|
.setState(
|
||||||
PlaybackState.STATE_STOPPED,
|
PlaybackState.STATE_PAUSED,
|
||||||
STATIC_PLAYBACK_POSITION,
|
STATIC_PLAYBACK_POSITION,
|
||||||
ZERO_PLAYBACK_SPEED)
|
ZERO_PLAYBACK_SPEED)
|
||||||
.addCustomAction(
|
.addCustomAction(
|
||||||
@@ -122,7 +129,9 @@ public class AudioStreamMediaService extends Service {
|
|||||||
private int mLatestPositiveVolume = 25;
|
private int mLatestPositiveVolume = 25;
|
||||||
private boolean mHysteresisModeFixAvailable;
|
private boolean mHysteresisModeFixAvailable;
|
||||||
private int mBroadcastId;
|
private int mBroadcastId;
|
||||||
@Nullable private Map<BluetoothDevice, LocalBluetoothLeBroadcastSourceState> mStateByDevice;
|
@VisibleForTesting
|
||||||
|
@Nullable
|
||||||
|
Map<BluetoothDevice, LocalBluetoothLeBroadcastSourceState> mStateByDevice;
|
||||||
@Nullable private LocalBluetoothManager mLocalBtManager;
|
@Nullable private LocalBluetoothManager mLocalBtManager;
|
||||||
@Nullable private AudioStreamsHelper mAudioStreamsHelper;
|
@Nullable private AudioStreamsHelper mAudioStreamsHelper;
|
||||||
@Nullable private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
@Nullable private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||||
@@ -236,6 +245,19 @@ public class AudioStreamMediaService extends Service {
|
|||||||
stopSelf();
|
stopSelf();
|
||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
// TODO(b/398700619): Remove hasExtra check when feasible.
|
||||||
|
if (Flags.audioStreamMediaServiceByReceiveState() && intent.hasExtra(
|
||||||
|
EXTRA_PRIVATE_BROADCAST_RECEIVE_DATA)) {
|
||||||
|
PrivateBroadcastReceiveData data = intent.getParcelableExtra(
|
||||||
|
EXTRA_PRIVATE_BROADCAST_RECEIVE_DATA, PrivateBroadcastReceiveData.class);
|
||||||
|
if (data == null || !PrivateBroadcastReceiveData.Companion.isValid(data)) {
|
||||||
|
Log.w(TAG, "Data is null or invalid. Service will not start.");
|
||||||
|
stopSelf();
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
getHandler().post(() -> handleIntentData(data));
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
getHandler().post(() -> {
|
getHandler().post(() -> {
|
||||||
mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
|
mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
|
||||||
if (mBroadcastId == -1) {
|
if (mBroadcastId == -1) {
|
||||||
@@ -258,6 +280,78 @@ public class AudioStreamMediaService extends Service {
|
|||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleIntentData(PrivateBroadcastReceiveData data) {
|
||||||
|
int broadcastId = data.getBroadcastId();
|
||||||
|
BluetoothDevice device = data.getSink();
|
||||||
|
int sourceId = data.getSourceId();
|
||||||
|
var state = data.getState();
|
||||||
|
String programInfo = data.getProgramInfo();
|
||||||
|
|
||||||
|
// Service not running yet.
|
||||||
|
if (mBroadcastId == 0) {
|
||||||
|
Log.d(TAG, "handleIntentData(): sending " + data + " to handleInitialSetup()");
|
||||||
|
handleInitialSetup(broadcastId, device, state, sourceId, programInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service running with a different broadcast id, most likely staled. We have a new
|
||||||
|
// broadcast Id to handle.
|
||||||
|
if (mBroadcastId != broadcastId) {
|
||||||
|
Log.d(TAG, "handleIntentData(): sending " + data + " to handleNewBroadcastId()");
|
||||||
|
handleNewBroadcastId(broadcastId, device, state, sourceId, programInfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service running with the same broadcast Id, we have new device joining or a state update.
|
||||||
|
if (mStateByDevice != null && (!mStateByDevice.containsKey(device) || mStateByDevice.get(
|
||||||
|
device) != state)) {
|
||||||
|
Log.d(TAG, "handleIntentData(): sending " + data + " to handleNewDeviceOrState()");
|
||||||
|
handleNewDeviceOrState(device, state, sourceId, programInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "handleIntentData(): nothing to update.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleInitialSetup(int broadcastId, BluetoothDevice device,
|
||||||
|
LocalBluetoothLeBroadcastSourceState state, int sourceId, String programInfo) {
|
||||||
|
if (state == DECRYPTION_FAILED) {
|
||||||
|
Log.d(TAG, "handleInitialSetup() : decryption failed. Service will not start.");
|
||||||
|
stopSelf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mBroadcastId = broadcastId;
|
||||||
|
mStateByDevice = new HashMap<>();
|
||||||
|
mStateByDevice.put(device, state);
|
||||||
|
MediaSession.Token token = getOrCreateLocalMediaSession(
|
||||||
|
getBroadcastName(device, sourceId, programInfo));
|
||||||
|
startForeground(NOTIFICATION_ID, buildNotification(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNewBroadcastId(int broadcastId, BluetoothDevice device,
|
||||||
|
LocalBluetoothLeBroadcastSourceState state, int sourceId, String programInfo) {
|
||||||
|
if (state == DECRYPTION_FAILED) {
|
||||||
|
Log.d(TAG, "handleNewBroadcastId() : decryption failed. Ignore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mBroadcastId = broadcastId;
|
||||||
|
mStateByDevice = new HashMap<>();
|
||||||
|
mStateByDevice.put(device, state);
|
||||||
|
updateMediaSessionAndNotify(device, sourceId, programInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNewDeviceOrState(BluetoothDevice device,
|
||||||
|
LocalBluetoothLeBroadcastSourceState state, int sourceId, String programInfo) {
|
||||||
|
if (mStateByDevice != null) {
|
||||||
|
mStateByDevice.put(device, state);
|
||||||
|
}
|
||||||
|
if (getDeviceInValidState().isEmpty()) {
|
||||||
|
Log.d(TAG, "handleNewDeviceOrState() : no device is in valid state. Stop service.");
|
||||||
|
stopSelf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateMediaSessionAndNotify(device, sourceId, programInfo);
|
||||||
|
}
|
||||||
|
|
||||||
private MediaSession.Token getOrCreateLocalMediaSession(String title) {
|
private MediaSession.Token getOrCreateLocalMediaSession(String title) {
|
||||||
if (mLocalSession != null) {
|
if (mLocalSession != null) {
|
||||||
return mLocalSession.getSessionToken();
|
return mLocalSession.getSessionToken();
|
||||||
@@ -288,7 +382,8 @@ public class AudioStreamMediaService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getDeviceName() {
|
private String getDeviceName() {
|
||||||
if (mStateByDevice == null || mStateByDevice.isEmpty() || mLocalBtManager == null) {
|
List<BluetoothDevice> validDevices = getDeviceInValidState();
|
||||||
|
if (validDevices.isEmpty() || mLocalBtManager == null) {
|
||||||
return DEFAULT_DEVICE_NAME;
|
return DEFAULT_DEVICE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,8 +392,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
return DEFAULT_DEVICE_NAME;
|
return DEFAULT_DEVICE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedBluetoothDevice device = manager.findDevice(
|
CachedBluetoothDevice device = manager.findDevice(validDevices.getFirst());
|
||||||
mStateByDevice.keySet().iterator().next());
|
|
||||||
return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
|
return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,6 +414,47 @@ public class AudioStreamMediaService extends Service {
|
|||||||
return notificationBuilder.build();
|
return notificationBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateMediaSessionAndNotify(BluetoothDevice device, int sourceId,
|
||||||
|
String programInfo) {
|
||||||
|
if (mNotificationManager == null || mLocalSession == null) {
|
||||||
|
Log.w(TAG, "mNotificationManager or mLocalSession is null, ignore update.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLocalSession.setMetadata(new MediaMetadata.Builder().putString(
|
||||||
|
MediaMetadata.METADATA_KEY_TITLE,
|
||||||
|
getBroadcastName(device, sourceId, programInfo)).putLong(
|
||||||
|
MediaMetadata.METADATA_KEY_DURATION, STATIC_PLAYBACK_DURATION).build());
|
||||||
|
mLocalSession.setPlaybackState(getPlaybackState());
|
||||||
|
mNotificationManager.notify(NOTIFICATION_ID,
|
||||||
|
buildNotification(mLocalSession.getSessionToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBroadcastName(BluetoothDevice sink, int sourceId, String programInfo) {
|
||||||
|
if (mLeBroadcastAssistant == null || sink == null) {
|
||||||
|
return programInfo;
|
||||||
|
}
|
||||||
|
var metadata = mLeBroadcastAssistant.getSourceMetadata(sink, sourceId);
|
||||||
|
if (metadata == null || metadata.getBroadcastId() != mBroadcastId
|
||||||
|
|| metadata.getBroadcastName() == null || metadata.getBroadcastName().isEmpty()) {
|
||||||
|
Log.d(TAG, "getBroadcastName(): source metadata not found, using programInfo: "
|
||||||
|
+ programInfo);
|
||||||
|
return programInfo;
|
||||||
|
}
|
||||||
|
return metadata.getBroadcastName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BluetoothDevice> getDeviceInValidState() {
|
||||||
|
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||||
|
Log.w(TAG, "getDeviceInValidState() : mStateByDevice is null or empty!");
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
if (Flags.audioStreamMediaServiceByReceiveState()) {
|
||||||
|
return mStateByDevice.entrySet().stream().filter(
|
||||||
|
entry -> entry.getValue() != DECRYPTION_FAILED).map(Map.Entry::getKey).toList();
|
||||||
|
}
|
||||||
|
return mStateByDevice.keySet().stream().toList();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
@@ -342,6 +477,9 @@ public class AudioStreamMediaService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceiveStateChanged(
|
public void onReceiveStateChanged(
|
||||||
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
||||||
|
if (Flags.audioStreamMediaServiceByReceiveState()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
super.onReceiveStateChanged(sink, sourceId, state);
|
super.onReceiveStateChanged(sink, sourceId, state);
|
||||||
if (!mHysteresisModeFixAvailable || mStateByDevice == null
|
if (!mHysteresisModeFixAvailable || mStateByDevice == null
|
||||||
|| !mStateByDevice.containsKey(sink)) {
|
|| !mStateByDevice.containsKey(sink)) {
|
||||||
@@ -383,23 +521,21 @@ public class AudioStreamMediaService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onDeviceVolumeChanged(
|
public void onDeviceVolumeChanged(
|
||||||
@NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volume) {
|
@NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volume) {
|
||||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
if (!getDeviceInValidState().contains(device)) {
|
||||||
Log.w(TAG, "active device or device has source is null!");
|
Log.w(TAG, "onDeviceVolumeChanged() : device not in valid state list");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"onDeviceVolumeChanged() bluetoothDevice : " + device + " volume: " + volume);
|
"onDeviceVolumeChanged() bluetoothDevice : " + device + " volume: " + volume);
|
||||||
if (mStateByDevice.containsKey(device)) {
|
if (volume == 0) {
|
||||||
if (volume == 0) {
|
mIsMuted = true;
|
||||||
mIsMuted = true;
|
} else {
|
||||||
} else {
|
mIsMuted = false;
|
||||||
mIsMuted = false;
|
mLatestPositiveVolume = volume;
|
||||||
mLatestPositiveVolume = volume;
|
}
|
||||||
}
|
if (mLocalSession != null) {
|
||||||
if (mLocalSession != null) {
|
mLocalSession.setPlaybackState(getPlaybackState());
|
||||||
mLocalSession.setPlaybackState(getPlaybackState());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,7 +562,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
&& mStateByDevice != null) {
|
&& mStateByDevice != null) {
|
||||||
mStateByDevice.remove(cachedDevice.getDevice());
|
mStateByDevice.remove(cachedDevice.getDevice());
|
||||||
}
|
}
|
||||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
if (getDeviceInValidState().isEmpty()) {
|
||||||
Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
|
Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
@@ -484,11 +620,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnPlay() {
|
private void handleOnPlay() {
|
||||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
getDeviceInValidState().forEach(device -> {
|
||||||
Log.w(TAG, "active device or device has source is null!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mStateByDevice.keySet().forEach(device -> {
|
|
||||||
Log.d(TAG, "onPlay() setting volume for device : " + device + " volume: "
|
Log.d(TAG, "onPlay() setting volume for device : " + device + " volume: "
|
||||||
+ mLatestPositiveVolume);
|
+ mLatestPositiveVolume);
|
||||||
setDeviceVolume(device, mLatestPositiveVolume);
|
setDeviceVolume(device, mLatestPositiveVolume);
|
||||||
@@ -496,11 +628,7 @@ public class AudioStreamMediaService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleOnPause() {
|
private void handleOnPause() {
|
||||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
getDeviceInValidState().forEach(device -> {
|
||||||
Log.w(TAG, "active device or device has source is null!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mStateByDevice.keySet().forEach(device -> {
|
|
||||||
Log.d(TAG, "onPause() setting volume for device : " + device + " volume: " + 0);
|
Log.d(TAG, "onPause() setting volume for device : " + device + " volume: " + 0);
|
||||||
setDeviceVolume(device, /* volume= */ 0);
|
setDeviceVolume(device, /* volume= */ 0);
|
||||||
});
|
});
|
||||||
|
@@ -26,6 +26,7 @@ import androidx.preference.Preference;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
class SourceAddedState extends AudioStreamStateHandler {
|
class SourceAddedState extends AudioStreamStateHandler {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -55,10 +56,12 @@ class SourceAddedState extends AudioStreamStateHandler {
|
|||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
mAudioStreamsRepository.saveMetadata(context, cached);
|
mAudioStreamsRepository.saveMetadata(context, cached);
|
||||||
}
|
}
|
||||||
helper.startMediaService(
|
if (!Flags.audioStreamMediaServiceByReceiveState()) {
|
||||||
context,
|
helper.startMediaService(
|
||||||
preference.getAudioStreamBroadcastId(),
|
context,
|
||||||
String.valueOf(preference.getTitle()));
|
preference.getAudioStreamBroadcastId(),
|
||||||
|
String.valueOf(preference.getTitle()));
|
||||||
|
}
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
preference.getContext(),
|
preference.getContext(),
|
||||||
SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
|
SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
|
||||||
|
@@ -81,9 +81,11 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
|||||||
implements SeekBar.OnSeekBarChangeListener {
|
implements SeekBar.OnSeekBarChangeListener {
|
||||||
private static final long MIN_COMMIT_INTERVAL_MS = 800;
|
private static final long MIN_COMMIT_INTERVAL_MS = 800;
|
||||||
private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
|
private static final long CHANGE_BY_BUTTON_DELAY_MS = 300;
|
||||||
|
private static final long CHANGE_BY_SEEKBAR_DELAY_MS = 100;
|
||||||
private final DisplaySizeData mDisplaySizeData;
|
private final DisplaySizeData mDisplaySizeData;
|
||||||
private int mLastDisplayProgress;
|
private int mLastDisplayProgress;
|
||||||
private long mLastCommitTime;
|
private long mLastCommitTime;
|
||||||
|
private boolean mSeekByTouch;
|
||||||
ExternalDisplaySizePreferenceStateHandler(DisplaySizeData displaySizeData) {
|
ExternalDisplaySizePreferenceStateHandler(DisplaySizeData displaySizeData) {
|
||||||
mDisplaySizeData = displaySizeData;
|
mDisplaySizeData = displaySizeData;
|
||||||
}
|
}
|
||||||
@@ -99,8 +101,7 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
|||||||
mLastCommitTime = SystemClock.elapsedRealtime();
|
mLastCommitTime = SystemClock.elapsedRealtime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postCommitDelayed() {
|
private void postCommitDelayed(long commitDelayMs) {
|
||||||
var commitDelayMs = CHANGE_BY_BUTTON_DELAY_MS;
|
|
||||||
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
|
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
|
||||||
commitDelayMs += MIN_COMMIT_INTERVAL_MS;
|
commitDelayMs += MIN_COMMIT_INTERVAL_MS;
|
||||||
}
|
}
|
||||||
@@ -112,13 +113,18 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(@NonNull SeekBar seekBar, int i, boolean b) {
|
public void onProgressChanged(@NonNull SeekBar seekBar, int i, boolean b) {
|
||||||
postCommitDelayed();
|
if (!mSeekByTouch) postCommitDelayed(CHANGE_BY_BUTTON_DELAY_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartTrackingTouch(@NonNull SeekBar seekBar) {}
|
public void onStartTrackingTouch(@NonNull SeekBar seekBar) {
|
||||||
|
mSeekByTouch = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(@NonNull SeekBar seekBar) {}
|
public void onStopTrackingTouch(@NonNull SeekBar seekBar) {
|
||||||
|
mSeekByTouch = false;
|
||||||
|
postCommitDelayed(CHANGE_BY_SEEKBAR_DELAY_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -104,3 +104,9 @@ const val KEY_RING_VOLUME = "separate_ring_volume"
|
|||||||
|
|
||||||
/** Contract key for the "Remove animation" setting. */
|
/** Contract key for the "Remove animation" setting. */
|
||||||
const val KEY_REMOVE_ANIMATION = "remove_animation"
|
const val KEY_REMOVE_ANIMATION = "remove_animation"
|
||||||
|
|
||||||
|
/** Contract key for the "Pin media player. */
|
||||||
|
const val KEY_PIN_MEDIA_PLAYER = "pin_media_player"
|
||||||
|
|
||||||
|
/** Contract key for the "Show media on lock screen. */
|
||||||
|
const val KEY_SHOW_MEDIA_ON_LOCK_SCREEN = "show_media_on_lock_screen"
|
||||||
|
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.display;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
|
||||||
|
/** Controls the "widgets on lock screen" preferences (under "Display & touch"). */
|
||||||
|
public class WidgetsOnLockscreenPreferenceController extends BasePreferenceController {
|
||||||
|
public WidgetsOnLockscreenPreferenceController(Context context, String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return isAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether "widgets on lock screen" preferences are available.
|
||||||
|
*/
|
||||||
|
public static boolean isAvailable(Context context) {
|
||||||
|
if (!isMainUser(context)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return com.android.systemui.Flags.glanceableHubV2()
|
||||||
|
&& (context.getResources().getBoolean(R.bool.config_show_communal_settings)
|
||||||
|
|| context.getResources().getBoolean(
|
||||||
|
R.bool.config_show_communal_settings_mobile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMainUser(Context context) {
|
||||||
|
final UserManager userManager = context.getSystemService(UserManager.class);
|
||||||
|
return userManager.getUserInfo(UserHandle.myUserId()).isMain();
|
||||||
|
}
|
||||||
|
}
|
@@ -122,6 +122,8 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
|||||||
R.id.input_setting_keys_value_custom);
|
R.id.input_setting_keys_value_custom);
|
||||||
TextView customValueTextView = accessibilityKeyDialog.findViewById(
|
TextView customValueTextView = accessibilityKeyDialog.findViewById(
|
||||||
R.id.input_setting_keys_value_custom_value);
|
R.id.input_setting_keys_value_custom_value);
|
||||||
|
View seekbarView = accessibilityKeyDialog.findViewById(
|
||||||
|
R.id.input_setting_keys_custom_seekbar_layout);
|
||||||
SeekBar customProgressBar = accessibilityKeyDialog.findViewById(
|
SeekBar customProgressBar = accessibilityKeyDialog.findViewById(
|
||||||
R.id.input_setting_keys_value_custom_slider);
|
R.id.input_setting_keys_value_custom_slider);
|
||||||
TextView titleTextView = accessibilityKeyDialog.findViewById(
|
TextView titleTextView = accessibilityKeyDialog.findViewById(
|
||||||
@@ -147,7 +149,7 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
|||||||
customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||||
customValueTextView.setText(
|
customValueTextView.setText(
|
||||||
progressToThresholdInSecond(customProgressBar.getProgress()));
|
progressToThresholdInSecond(customProgressBar.getProgress()));
|
||||||
customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
seekbarView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||||
buttonView.setChecked(isChecked);
|
buttonView.setChecked(isChecked);
|
||||||
});
|
});
|
||||||
cannedValueRadioGroup.setOnCheckedChangeListener(
|
cannedValueRadioGroup.setOnCheckedChangeListener(
|
||||||
@@ -174,14 +176,14 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
|||||||
// setting
|
// setting
|
||||||
initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton,
|
initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton,
|
||||||
customValueTextView,
|
customValueTextView,
|
||||||
customProgressBar);
|
customProgressBar, seekbarView);
|
||||||
} else if (customRadioButton.isChecked()) {
|
} else if (customRadioButton.isChecked()) {
|
||||||
cannedValueRadioGroup.clearCheck();
|
cannedValueRadioGroup.clearCheck();
|
||||||
customRadioButton.setChecked(true);
|
customRadioButton.setChecked(true);
|
||||||
customValueTextView.setVisibility(View.VISIBLE);
|
customValueTextView.setVisibility(View.VISIBLE);
|
||||||
customValueTextView.setText(
|
customValueTextView.setText(
|
||||||
progressToThresholdInSecond(customProgressBar.getProgress()));
|
progressToThresholdInSecond(customProgressBar.getProgress()));
|
||||||
customProgressBar.setVisibility(View.VISIBLE);
|
seekbarView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -199,7 +201,7 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
|||||||
|
|
||||||
private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup,
|
private void initStateBasedOnThreshold(RadioGroup cannedValueRadioGroup,
|
||||||
RadioButton customRadioButton, TextView customValueTextView,
|
RadioButton customRadioButton, TextView customValueTextView,
|
||||||
SeekBar customProgressBar) {
|
SeekBar customProgressBar, View seekbarView) {
|
||||||
int inputSettingKeysThreshold = getInputSettingKeysValue();
|
int inputSettingKeysThreshold = getInputSettingKeysValue();
|
||||||
switch (inputSettingKeysThreshold) {
|
switch (inputSettingKeysThreshold) {
|
||||||
case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600);
|
case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600);
|
||||||
@@ -213,5 +215,6 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
|||||||
customRadioButton.setChecked(true);
|
customRadioButton.setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
seekbarView.setVisibility(customRadioButton.isChecked() ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,34 +18,68 @@ package com.android.settings.network.ethernet
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback
|
||||||
import android.net.EthernetManager
|
import android.net.EthernetManager
|
||||||
import android.net.EthernetManager.STATE_ABSENT
|
import android.net.EthernetManager.STATE_ABSENT
|
||||||
import android.net.EthernetNetworkManagementException
|
import android.net.EthernetNetworkManagementException
|
||||||
import android.net.EthernetNetworkUpdateRequest
|
import android.net.EthernetNetworkUpdateRequest
|
||||||
import android.net.IpConfiguration
|
import android.net.IpConfiguration
|
||||||
|
import android.net.LinkProperties
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.NetworkRequest
|
||||||
import android.os.OutcomeReceiver
|
import android.os.OutcomeReceiver
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import com.google.common.annotations.VisibleForTesting
|
||||||
|
|
||||||
class EthernetInterface(private val context: Context, private val id: String) :
|
class EthernetInterface(private val context: Context, private val id: String) :
|
||||||
EthernetManager.InterfaceStateListener {
|
EthernetManager.InterfaceStateListener {
|
||||||
|
interface EthernetInterfaceStateListener {
|
||||||
|
fun interfaceUpdated()
|
||||||
|
}
|
||||||
|
|
||||||
private val ethernetManager: EthernetManager? =
|
private val ethernetManager: EthernetManager? =
|
||||||
context.getSystemService(EthernetManager::class.java)
|
context.getSystemService(EthernetManager::class.java)
|
||||||
private val connectivityManager: ConnectivityManager? =
|
private val connectivityManager: ConnectivityManager? =
|
||||||
context.getSystemService(ConnectivityManager::class.java)
|
context.getSystemService(ConnectivityManager::class.java)
|
||||||
private val executor = ContextCompat.getMainExecutor(context)
|
private val executor = ContextCompat.getMainExecutor(context)
|
||||||
|
private val interfaceListeners = mutableListOf<EthernetInterfaceStateListener>()
|
||||||
|
|
||||||
private val TAG = "EthernetInterface"
|
private val TAG = "EthernetInterface"
|
||||||
|
|
||||||
|
private val networkRequest: NetworkRequest =
|
||||||
|
NetworkRequest.Builder()
|
||||||
|
.clearCapabilities()
|
||||||
|
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||||
|
.build()
|
||||||
|
|
||||||
private var interfaceState = STATE_ABSENT
|
private var interfaceState = STATE_ABSENT
|
||||||
private var ipConfiguration = IpConfiguration()
|
private var ipConfiguration = IpConfiguration()
|
||||||
|
private var linkProperties = LinkProperties()
|
||||||
|
|
||||||
fun getInterfaceState() = interfaceState
|
fun getInterfaceState() = interfaceState
|
||||||
|
|
||||||
fun getId() = id
|
fun getId() = id
|
||||||
|
|
||||||
fun getConfiguration(): IpConfiguration {
|
fun getConfiguration() = ipConfiguration
|
||||||
return ipConfiguration
|
|
||||||
|
fun getLinkProperties() = linkProperties
|
||||||
|
|
||||||
|
fun registerListener(listener: EthernetInterfaceStateListener) {
|
||||||
|
if (interfaceListeners.isEmpty()) {
|
||||||
|
ethernetManager?.addInterfaceStateListener(ContextCompat.getMainExecutor(context), this)
|
||||||
|
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
|
||||||
|
}
|
||||||
|
interfaceListeners.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unregisterListener(listener: EthernetInterfaceStateListener) {
|
||||||
|
interfaceListeners.remove(listener)
|
||||||
|
if (interfaceListeners.isEmpty()) {
|
||||||
|
connectivityManager?.unregisterNetworkCallback(networkCallback)
|
||||||
|
ethernetManager?.removeInterfaceStateListener(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setConfiguration(ipConfiguration: IpConfiguration) {
|
fun setConfiguration(ipConfiguration: IpConfiguration) {
|
||||||
@@ -67,10 +101,28 @@ class EthernetInterface(private val context: Context, private val id: String) :
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun notifyListeners() {
|
||||||
|
for (listener in interfaceListeners) {
|
||||||
|
listener.interfaceUpdated()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) {
|
override fun onInterfaceStateChanged(id: String, state: Int, role: Int, cfg: IpConfiguration?) {
|
||||||
if (id == this.id) {
|
if (id == this.id) {
|
||||||
ipConfiguration = cfg ?: IpConfiguration()
|
ipConfiguration = cfg ?: IpConfiguration()
|
||||||
interfaceState = state
|
interfaceState = state
|
||||||
|
notifyListeners()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
val networkCallback =
|
||||||
|
object : NetworkCallback() {
|
||||||
|
override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) {
|
||||||
|
if (lp.getInterfaceName().equals(id)) {
|
||||||
|
linkProperties = lp
|
||||||
|
notifyListeners()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,14 @@ package com.android.settings.network.ethernet
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.EthernetManager
|
import android.net.EthernetManager
|
||||||
|
import android.net.IpConfiguration
|
||||||
|
import android.net.LinkProperties
|
||||||
|
import android.net.StaticIpConfiguration
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
@@ -30,13 +37,25 @@ class EthernetInterfaceDetailsController(
|
|||||||
context: Context,
|
context: Context,
|
||||||
private val fragment: PreferenceFragmentCompat,
|
private val fragment: PreferenceFragmentCompat,
|
||||||
private val preferenceId: String,
|
private val preferenceId: String,
|
||||||
) : AbstractPreferenceController(context) {
|
private val lifecycle: Lifecycle,
|
||||||
|
) :
|
||||||
|
AbstractPreferenceController(context),
|
||||||
|
EthernetInterface.EthernetInterfaceStateListener,
|
||||||
|
LifecycleEventObserver {
|
||||||
private val KEY_HEADER = "ethernet_details"
|
private val KEY_HEADER = "ethernet_details"
|
||||||
|
|
||||||
private val ethernetManager = context.getSystemService(EthernetManager::class.java)
|
private val ethernetManager = context.getSystemService(EthernetManager::class.java)
|
||||||
private val ethernetInterface =
|
private val ethernetInterface =
|
||||||
EthernetTrackerImpl.getInstance(context).getInterface(preferenceId)
|
EthernetTrackerImpl.getInstance(context).getInterface(preferenceId)
|
||||||
|
|
||||||
|
private lateinit var entityHeaderController: EntityHeaderController
|
||||||
|
|
||||||
|
private var ipAddressPref: Preference? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
lifecycle.addObserver(this)
|
||||||
|
}
|
||||||
|
|
||||||
override fun isAvailable(): Boolean {
|
override fun isAvailable(): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -45,10 +64,24 @@ class EthernetInterfaceDetailsController(
|
|||||||
return KEY_HEADER
|
return KEY_HEADER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||||
|
when (event) {
|
||||||
|
Lifecycle.Event.ON_START -> {
|
||||||
|
ethernetInterface?.registerListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
Lifecycle.Event.ON_STOP -> {
|
||||||
|
ethernetInterface?.unregisterListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun displayPreference(screen: PreferenceScreen) {
|
override fun displayPreference(screen: PreferenceScreen) {
|
||||||
val headerPref: LayoutPreference? = screen.findPreference(KEY_HEADER)
|
val headerPref: LayoutPreference? = screen.findPreference(KEY_HEADER)
|
||||||
|
|
||||||
val mEntityHeaderController =
|
entityHeaderController =
|
||||||
EntityHeaderController.newInstance(
|
EntityHeaderController.newInstance(
|
||||||
fragment.getActivity(),
|
fragment.getActivity(),
|
||||||
fragment,
|
fragment,
|
||||||
@@ -59,17 +92,49 @@ class EthernetInterfaceDetailsController(
|
|||||||
|
|
||||||
iconView?.setScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
iconView?.setScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
||||||
|
|
||||||
mEntityHeaderController
|
if (entityHeaderController != null) {
|
||||||
.setLabel("Ethernet")
|
entityHeaderController
|
||||||
.setSummary(
|
.setLabel("Ethernet")
|
||||||
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
.setSummary(
|
||||||
mContext.getString(R.string.network_connected)
|
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||||
} else {
|
mContext.getString(R.string.network_connected)
|
||||||
mContext.getString(R.string.network_disconnected)
|
} else {
|
||||||
}
|
mContext.getString(R.string.network_disconnected)
|
||||||
)
|
}
|
||||||
.setSecondSummary("")
|
)
|
||||||
.setIcon(mContext.getDrawable(R.drawable.ic_settings_ethernet))
|
.setSecondSummary("")
|
||||||
.done(true /* rebind */)
|
.setIcon(mContext.getDrawable(R.drawable.ic_settings_ethernet))
|
||||||
|
.done(true /* rebind */)
|
||||||
|
}
|
||||||
|
|
||||||
|
ipAddressPref = screen.findPreference<Preference>("ethernet_ip_address")
|
||||||
|
|
||||||
|
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||||
|
initializeIpDetails()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interfaceUpdated() {
|
||||||
|
entityHeaderController?.setSummary(
|
||||||
|
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||||
|
mContext.getString(R.string.network_connected)
|
||||||
|
} else {
|
||||||
|
mContext.getString(R.string.network_disconnected)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
initializeIpDetails()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeIpDetails() {
|
||||||
|
val ipConfiguration: IpConfiguration? = ethernetInterface?.getConfiguration()
|
||||||
|
val linkProperties: LinkProperties? = ethernetInterface?.getLinkProperties()
|
||||||
|
|
||||||
|
if (ipConfiguration?.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) {
|
||||||
|
val staticIp: StaticIpConfiguration? = ipConfiguration?.getStaticIpConfiguration()
|
||||||
|
ipAddressPref?.setSummary(staticIp?.getIpAddress().toString())
|
||||||
|
} else {
|
||||||
|
val addresses = linkProperties?.getAddresses()
|
||||||
|
ipAddressPref?.setSummary(addresses?.first().toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,13 @@ class EthernetInterfaceDetailsFragment : DashboardFragment() {
|
|||||||
override public fun createPreferenceControllers(
|
override public fun createPreferenceControllers(
|
||||||
context: Context
|
context: Context
|
||||||
): List<AbstractPreferenceController> {
|
): List<AbstractPreferenceController> {
|
||||||
return listOf(EthernetInterfaceDetailsController(context, this, preferenceId ?: ""))
|
return listOf(
|
||||||
|
EthernetInterfaceDetailsController(
|
||||||
|
context,
|
||||||
|
this,
|
||||||
|
preferenceId ?: "",
|
||||||
|
getSettingsLifecycle(),
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
src/com/android/settings/safetycenter/OWNERS
Normal file
4
src/com/android/settings/safetycenter/OWNERS
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
jtomljanovic@google.com
|
||||||
|
elliotsisteron@google.com
|
||||||
|
deweytyl@google.com
|
||||||
|
simonjw@google.com
|
@@ -22,6 +22,7 @@ import android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPO
|
|||||||
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G
|
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES
|
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP
|
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_ENABLE_MTE
|
import android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_ENABLE_MTE
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION
|
import android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING
|
import android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING
|
||||||
@@ -37,13 +38,17 @@ import com.android.settingslib.spa.SpaDialogWindowTypeActivity
|
|||||||
import com.android.settingslib.spa.widget.dialog.AlertDialogButton
|
import com.android.settingslib.spa.widget.dialog.AlertDialogButton
|
||||||
import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogContent
|
import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogContent
|
||||||
import com.android.settingslib.wifi.WifiUtils.Companion.DIALOG_WINDOW_TYPE
|
import com.android.settingslib.wifi.WifiUtils.Companion.DIALOG_WINDOW_TYPE
|
||||||
|
import android.security.advancedprotection.AdvancedProtectionManager
|
||||||
|
|
||||||
class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
SettingsAlertDialogContent(
|
SettingsAlertDialogContent(
|
||||||
confirmButton = AlertDialogButton(getString(R.string.okay)) { finish() },
|
confirmButton = AlertDialogButton(getString(R.string.okay)) {
|
||||||
|
finish()
|
||||||
|
logDialogShown(learnMoreClicked = false)
|
||||||
|
},
|
||||||
dismissButton = getSupportButtonIfExists(),
|
dismissButton = getSupportButtonIfExists(),
|
||||||
title = getString(R.string.disabled_by_advanced_protection_title),
|
title = getString(R.string.disabled_by_advanced_protection_title),
|
||||||
icon = {
|
icon = {
|
||||||
@@ -56,8 +61,8 @@ class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getDialogMessage(): String {
|
private fun getDialogMessage(): String {
|
||||||
val featureId = intent.getIntExtra(EXTRA_SUPPORT_DIALOG_FEATURE, -1)
|
val featureId = getIntentFeatureId()
|
||||||
val type = intent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_UNKNOWN)
|
val type = getIntentDialogueType()
|
||||||
val messageId = when (type) {
|
val messageId = when (type) {
|
||||||
SUPPORT_DIALOG_TYPE_DISABLED_SETTING -> {
|
SUPPORT_DIALOG_TYPE_DISABLED_SETTING -> {
|
||||||
if (featureIdsWithSettingOn.contains(featureId)) {
|
if (featureIdsWithSettingOn.contains(featureId)) {
|
||||||
@@ -93,6 +98,7 @@ class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
|||||||
) {
|
) {
|
||||||
startActivity(helpIntent)
|
startActivity(helpIntent)
|
||||||
finish()
|
finish()
|
||||||
|
logDialogShown(learnMoreClicked = true)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Tried to set up help button, but this exception was thrown: ${e.message}")
|
Log.w(TAG, "Tried to set up help button, but this exception was thrown: ${e.message}")
|
||||||
@@ -100,10 +106,29 @@ class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun logDialogShown(learnMoreClicked: Boolean) {
|
||||||
|
// We should always have this permission, but just in case we don't, we should not log.
|
||||||
|
if (checkSelfPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getSystemService(AdvancedProtectionManager::class.java)
|
||||||
|
.logDialogShown(getIntentFeatureId(), getIntentDialogueType(), learnMoreClicked)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDialogWindowType(): Int? = if (intent.hasExtra(DIALOG_WINDOW_TYPE)) {
|
override fun getDialogWindowType(): Int? = if (intent.hasExtra(DIALOG_WINDOW_TYPE)) {
|
||||||
intent.getIntExtra(DIALOG_WINDOW_TYPE, WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW)
|
intent.getIntExtra(DIALOG_WINDOW_TYPE, WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW)
|
||||||
} else null
|
} else null
|
||||||
|
|
||||||
|
private fun getIntentFeatureId(): Int {
|
||||||
|
return intent.getIntExtra(EXTRA_SUPPORT_DIALOG_FEATURE, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getIntentDialogueType(): Int {
|
||||||
|
return intent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_UNKNOWN)
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val TAG = "AdvancedProtectionDlg"
|
const val TAG = "AdvancedProtectionDlg"
|
||||||
val defaultMessageId = R.string.disabled_by_advanced_protection_action_message
|
val defaultMessageId = R.string.disabled_by_advanced_protection_action_message
|
||||||
|
@@ -178,7 +178,9 @@ public class ScreenLockPreferenceDetailsUtils {
|
|||||||
if (!mLockPatternUtils.isSecure(userId)) {
|
if (!mLockPatternUtils.isSecure(userId)) {
|
||||||
if (userId == mProfileChallengeUserId
|
if (userId == mProfileChallengeUserId
|
||||||
|| mLockPatternUtils.isLockScreenDisabled(userId)) {
|
|| mLockPatternUtils.isLockScreenDisabled(userId)) {
|
||||||
return R.string.unlock_set_unlock_mode_off;
|
return com.android.settings.flags.Flags.biometricsOnboardingEducation()
|
||||||
|
? R.string.unlock_set_unlock_mode_off_new
|
||||||
|
: R.string.unlock_set_unlock_mode_off;
|
||||||
} else {
|
} else {
|
||||||
return R.string.unlock_set_unlock_mode_none;
|
return R.string.unlock_set_unlock_mode_none;
|
||||||
}
|
}
|
||||||
|
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package com.android.settings.sound
|
package com.android.settings.sound
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums.ACTION_SHOW_MEDIA_ON_LOCK_SCREEN
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN
|
import android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
|
import com.android.settings.contract.KEY_SHOW_MEDIA_ON_LOCK_SCREEN
|
||||||
|
import com.android.settings.metrics.PreferenceActionMetricsProvider
|
||||||
import com.android.settingslib.datastore.KeyValueStore
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
import com.android.settingslib.datastore.KeyValueStoreDelegate
|
import com.android.settingslib.datastore.KeyValueStoreDelegate
|
||||||
import com.android.settingslib.datastore.SettingsSecureStore
|
import com.android.settingslib.datastore.SettingsSecureStore
|
||||||
@@ -32,7 +35,13 @@ class MediaControlsLockscreenSwitchPreference :
|
|||||||
KEY,
|
KEY,
|
||||||
R.string.media_controls_lockscreen_title,
|
R.string.media_controls_lockscreen_title,
|
||||||
R.string.media_controls_lockscreen_description,
|
R.string.media_controls_lockscreen_description,
|
||||||
) {
|
),
|
||||||
|
PreferenceActionMetricsProvider {
|
||||||
|
|
||||||
|
override val preferenceActionMetrics: Int
|
||||||
|
get() = ACTION_SHOW_MEDIA_ON_LOCK_SCREEN
|
||||||
|
|
||||||
|
override fun tags(context: Context) = arrayOf(KEY_SHOW_MEDIA_ON_LOCK_SCREEN)
|
||||||
|
|
||||||
override val sensitivityLevel
|
override val sensitivityLevel
|
||||||
get() = SensitivityLevel.NO_SENSITIVITY
|
get() = SensitivityLevel.NO_SENSITIVITY
|
||||||
|
@@ -16,30 +16,39 @@
|
|||||||
|
|
||||||
package com.android.settings.sound
|
package com.android.settings.sound
|
||||||
|
|
||||||
|
import android.app.settings.SettingsEnums.ACTION_PIN_MEDIA_PLAYER
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.provider.Settings.Secure.MEDIA_CONTROLS_RESUME
|
import android.provider.Settings.Secure.MEDIA_CONTROLS_RESUME
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.contract.KEY_PIN_MEDIA_PLAYER
|
||||||
|
import com.android.settings.metrics.PreferenceActionMetricsProvider
|
||||||
import com.android.settingslib.datastore.KeyValueStore
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
import com.android.settingslib.datastore.SettingsSecureStore
|
import com.android.settingslib.datastore.SettingsSecureStore
|
||||||
import com.android.settingslib.metadata.ReadWritePermit
|
import com.android.settingslib.metadata.ReadWritePermit
|
||||||
import com.android.settingslib.metadata.SensitivityLevel
|
import com.android.settingslib.metadata.SensitivityLevel
|
||||||
import com.android.settingslib.metadata.SwitchPreference
|
import com.android.settingslib.metadata.SwitchPreference
|
||||||
import com.android.settings.R
|
|
||||||
|
|
||||||
// LINT.IfChange
|
// LINT.IfChange
|
||||||
class MediaControlsSwitchPreference(
|
class MediaControlsSwitchPreference(
|
||||||
private val mediaControlsStore: MediaControlsScreen.MediaControlsStore,
|
private val mediaControlsStore: MediaControlsScreen.MediaControlsStore
|
||||||
) : SwitchPreference(
|
) :
|
||||||
KEY,
|
SwitchPreference(
|
||||||
R.string.media_controls_resume_title,
|
KEY,
|
||||||
R.string.media_controls_resume_description,
|
R.string.media_controls_resume_title,
|
||||||
) {
|
R.string.media_controls_resume_description,
|
||||||
|
),
|
||||||
|
PreferenceActionMetricsProvider {
|
||||||
override val sensitivityLevel
|
override val sensitivityLevel
|
||||||
get() = SensitivityLevel.NO_SENSITIVITY
|
get() = SensitivityLevel.NO_SENSITIVITY
|
||||||
|
|
||||||
override val keywords: Int
|
override val keywords: Int
|
||||||
get() = R.string.keywords_media_controls
|
get() = R.string.keywords_media_controls
|
||||||
|
|
||||||
|
override val preferenceActionMetrics: Int
|
||||||
|
get() = ACTION_PIN_MEDIA_PLAYER
|
||||||
|
|
||||||
|
override fun tags(context: Context) = arrayOf(KEY_PIN_MEDIA_PLAYER)
|
||||||
|
|
||||||
override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions()
|
override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions()
|
||||||
|
|
||||||
override fun getWritePermissions(context: Context) = SettingsSecureStore.getWritePermissions()
|
override fun getWritePermissions(context: Context) = SettingsSecureStore.getWritePermissions()
|
||||||
|
5
src/com/android/settings/spa/app/appcompat/OWNERS
Normal file
5
src/com/android/settings/spa/app/appcompat/OWNERS
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Bug component: 970984
|
||||||
|
# Large Screen Experiences App Compat
|
||||||
|
gracielawputri@google.com
|
||||||
|
mcarli@google.com
|
||||||
|
mariiasand@google.com
|
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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.supervision
|
||||||
|
|
||||||
|
import android.Manifest.permission.USE_BIOMETRIC
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.hardware.biometrics.BiometricManager
|
||||||
|
import android.hardware.biometrics.BiometricPrompt
|
||||||
|
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.CancellationSignal
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import com.android.settings.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity for confirming supervision credentials using device credential authentication.
|
||||||
|
*
|
||||||
|
* This activity displays an authentication prompt to the user, requiring them to authenticate using
|
||||||
|
* their device credentials (PIN, pattern, or password). It is specifically designed for verifying
|
||||||
|
* credentials for supervision purposes.
|
||||||
|
*
|
||||||
|
* It returns `Activity.RESULT_OK` if authentication succeeds, and `Activity.RESULT_CANCELED` if
|
||||||
|
* authentication fails or is canceled by the user.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* 1. Start this activity using `startActivityForResult()`.
|
||||||
|
* 2. Handle the result in `onActivityResult()`.
|
||||||
|
*
|
||||||
|
* Permissions:
|
||||||
|
* - Requires `android.permission.USE_BIOMETRIC`.
|
||||||
|
*/
|
||||||
|
class ConfirmSupervisionCredentialsActivity : FragmentActivity() {
|
||||||
|
private val mAuthenticationCallback =
|
||||||
|
object : AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
Log.w(TAG, "onAuthenticationError(errorCode=$errorCode, errString=$errString)")
|
||||||
|
setResult(Activity.RESULT_CANCELED)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult?) {
|
||||||
|
setResult(Activity.RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
setResult(Activity.RESULT_CANCELED)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(USE_BIOMETRIC)
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
// TODO(b/392961554): Check if caller is the SYSTEM_SUPERVISION role holder. Call
|
||||||
|
// RoleManager#getRoleHolders(SYSTEM_SUPERVISION) and check if getCallingPackage() is in the
|
||||||
|
// list.
|
||||||
|
if (checkCallingOrSelfPermission(USE_BIOMETRIC) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
showBiometricPrompt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(USE_BIOMETRIC)
|
||||||
|
fun showBiometricPrompt() {
|
||||||
|
// TODO(b/392961554): adapts to new user profile type to trigger PIN verification dialog.
|
||||||
|
val biometricPrompt =
|
||||||
|
BiometricPrompt.Builder(this)
|
||||||
|
.setTitle(getString(R.string.supervision_full_screen_pin_verification_title))
|
||||||
|
.setConfirmationRequired(true)
|
||||||
|
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
|
||||||
|
.build()
|
||||||
|
biometricPrompt.authenticate(
|
||||||
|
CancellationSignal(),
|
||||||
|
ContextCompat.getMainExecutor(this),
|
||||||
|
mAuthenticationCallback,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// TODO(b/392961554): remove this tag and use shared tag after http://ag/31997167 is
|
||||||
|
// submitted.
|
||||||
|
const val TAG = "SupervisionSettings"
|
||||||
|
}
|
||||||
|
}
|
@@ -56,7 +56,7 @@ class SupervisionDashboardScreen : PreferenceScreenCreator {
|
|||||||
|
|
||||||
override fun getPreferenceHierarchy(context: Context) =
|
override fun getPreferenceHierarchy(context: Context) =
|
||||||
preferenceHierarchy(context, this) {
|
preferenceHierarchy(context, this) {
|
||||||
+SupervisionMainSwitchPreference()
|
+SupervisionMainSwitchPreference(context)
|
||||||
+TitlelessPreferenceGroup(SUPERVISION_DYNAMIC_GROUP_1) += {
|
+TitlelessPreferenceGroup(SUPERVISION_DYNAMIC_GROUP_1) += {
|
||||||
+SupervisionWebContentFiltersScreen.KEY
|
+SupervisionWebContentFiltersScreen.KEY
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.SupervisionManager
|
import android.app.supervision.SupervisionManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settingslib.datastore.KeyValueStore
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
@@ -32,19 +34,22 @@ import com.android.settingslib.preference.MainSwitchPreferenceBinding
|
|||||||
import com.android.settingslib.preference.forEachRecursively
|
import com.android.settingslib.preference.forEachRecursively
|
||||||
|
|
||||||
/** Main toggle to enable or disable device supervision. */
|
/** Main toggle to enable or disable device supervision. */
|
||||||
class SupervisionMainSwitchPreference :
|
class SupervisionMainSwitchPreference(context: Context) :
|
||||||
MainSwitchPreference(KEY, R.string.device_supervision_switch_title),
|
MainSwitchPreference(KEY, R.string.device_supervision_switch_title),
|
||||||
PreferenceSummaryProvider,
|
PreferenceSummaryProvider,
|
||||||
MainSwitchPreferenceBinding,
|
MainSwitchPreferenceBinding,
|
||||||
Preference.OnPreferenceChangeListener,
|
Preference.OnPreferenceChangeListener,
|
||||||
PreferenceLifecycleProvider {
|
PreferenceLifecycleProvider {
|
||||||
|
|
||||||
|
private val supervisionMainSwitchStorage = SupervisionMainSwitchStorage(context)
|
||||||
|
private lateinit var lifeCycleContext: PreferenceLifecycleContext
|
||||||
|
|
||||||
// TODO(b/383568136): Make presence of summary conditional on whether PIN
|
// TODO(b/383568136): Make presence of summary conditional on whether PIN
|
||||||
// has been set up before or not.
|
// has been set up before or not.
|
||||||
override fun getSummary(context: Context): CharSequence? =
|
override fun getSummary(context: Context): CharSequence? =
|
||||||
context.getString(R.string.device_supervision_switch_no_pin_summary)
|
context.getString(R.string.device_supervision_switch_no_pin_summary)
|
||||||
|
|
||||||
override fun storage(context: Context): KeyValueStore = SupervisionMainSwitchStorage(context)
|
override fun storage(context: Context): KeyValueStore = supervisionMainSwitchStorage
|
||||||
|
|
||||||
override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
|
override fun getReadPermit(context: Context, callingPid: Int, callingUid: Int) =
|
||||||
ReadWritePermit.DISALLOW
|
ReadWritePermit.DISALLOW
|
||||||
@@ -55,26 +60,49 @@ class SupervisionMainSwitchPreference :
|
|||||||
override val sensitivityLevel: Int
|
override val sensitivityLevel: Int
|
||||||
get() = SensitivityLevel.HIGH_SENSITIVITY
|
get() = SensitivityLevel.HIGH_SENSITIVITY
|
||||||
|
|
||||||
|
override fun onCreate(context: PreferenceLifecycleContext) {
|
||||||
|
lifeCycleContext = context
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume(context: PreferenceLifecycleContext) {
|
||||||
|
updateDependentPreferencesEnabledState(
|
||||||
|
context.findPreference<Preference>(KEY),
|
||||||
|
supervisionMainSwitchStorage.getBoolean(KEY)!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(
|
||||||
|
context: PreferenceLifecycleContext,
|
||||||
|
requestCode: Int,
|
||||||
|
resultCode: Int,
|
||||||
|
data: Intent?,
|
||||||
|
): Boolean {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
val mainSwitchPreference =
|
||||||
|
context.requirePreference<com.android.settingslib.widget.MainSwitchPreference>(KEY)
|
||||||
|
val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!!
|
||||||
|
mainSwitchPreference.setChecked(newValue)
|
||||||
|
updateDependentPreferencesEnabledState(mainSwitchPreference, newValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
|
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
|
||||||
super.bind(preference, metadata)
|
super.bind(preference, metadata)
|
||||||
preference.onPreferenceChangeListener = this
|
preference.onPreferenceChangeListener = this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume(context: PreferenceLifecycleContext) {
|
|
||||||
val currentValue = storage(context.applicationContext)?.getBoolean(key) ?: false
|
|
||||||
|
|
||||||
updateDependentPreferencesEnabledState(
|
|
||||||
context.findPreference<Preference>(KEY),
|
|
||||||
currentValue,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
|
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
|
||||||
if (newValue !is Boolean) return true
|
if (newValue !is Boolean) return true
|
||||||
|
|
||||||
updateDependentPreferencesEnabledState(preference, newValue)
|
val intent = Intent(lifeCycleContext, ConfirmSupervisionCredentialsActivity::class.java)
|
||||||
|
lifeCycleContext.startActivityForResult(
|
||||||
return true
|
intent,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDependentPreferencesEnabledState(
|
private fun updateDependentPreferencesEnabledState(
|
||||||
@@ -83,9 +111,8 @@ class SupervisionMainSwitchPreference :
|
|||||||
) {
|
) {
|
||||||
preference?.parent?.forEachRecursively {
|
preference?.parent?.forEachRecursively {
|
||||||
if (
|
if (
|
||||||
it.parent?.key?.toString() ==
|
it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
||||||
SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
it.key == SupervisionPinManagementScreen.KEY
|
||||||
it.key?.toString() == SupervisionPinManagementScreen.KEY
|
|
||||||
) {
|
) {
|
||||||
it.isEnabled = isChecked
|
it.isEnabled = isChecked
|
||||||
}
|
}
|
||||||
@@ -103,7 +130,6 @@ class SupervisionMainSwitchPreference :
|
|||||||
as T
|
as T
|
||||||
|
|
||||||
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||||
// TODO(b/392694561): add PIN protection to main toggle.
|
|
||||||
if (key == KEY && value is Boolean) {
|
if (key == KEY && value is Boolean) {
|
||||||
val supervisionManager = context.getSystemService(SupervisionManager::class.java)
|
val supervisionManager = context.getSystemService(SupervisionManager::class.java)
|
||||||
supervisionManager?.setSupervisionEnabled(value)
|
supervisionManager?.setSupervisionEnabled(value)
|
||||||
@@ -113,5 +139,6 @@ class SupervisionMainSwitchPreference :
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY = "device_supervision_switch"
|
const val KEY = "device_supervision_switch"
|
||||||
|
const val REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -76,6 +78,15 @@ public class TextReadingPreviewControllerTest {
|
|||||||
mDisplaySizePreference = new AccessibilitySeekBarPreference(mContext, /* attr= */ null);
|
mDisplaySizePreference = new AccessibilitySeekBarPreference(mContext, /* attr= */ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void numberOfPreviewSamples_numberOfPreviewContentDescription_isEqual() {
|
||||||
|
int[] previewSamples = TextReadingPreviewController.getPreviewSampleLayouts(mContext);
|
||||||
|
int[] previewContentDescriptions =
|
||||||
|
TextReadingPreviewController.getPreviewSampleContentDescriptions(mContext);
|
||||||
|
|
||||||
|
assertThat(previewSamples.length).isEqualTo(previewContentDescriptions.length);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initPreviewerAdapter_verifyAction() {
|
public void initPreviewerAdapter_verifyAction() {
|
||||||
when(mPreferenceScreen.findPreference(PREVIEW_KEY)).thenReturn(mPreviewPreference);
|
when(mPreferenceScreen.findPreference(PREVIEW_KEY)).thenReturn(mPreviewPreference);
|
||||||
|
@@ -49,29 +49,48 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
*/
|
*/
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class TextReadingPreviewPreferenceTest {
|
public class TextReadingPreviewPreferenceTest {
|
||||||
|
private Context mContext;
|
||||||
private TextReadingPreviewPreference mTextReadingPreviewPreference;
|
private TextReadingPreviewPreference mTextReadingPreviewPreference;
|
||||||
private PreferenceViewHolder mHolder;
|
private PreferenceViewHolder mHolder;
|
||||||
private ViewPager mViewPager;
|
private ViewPager mViewPager;
|
||||||
private PreviewPagerAdapter mPreviewPagerAdapter;
|
private PreviewPagerAdapter mPreviewPagerAdapter;
|
||||||
private int mPreviewSampleCount;
|
private int mPreviewSampleCount;
|
||||||
|
private int[] mPreviewContentDescriptions;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
final Context context = ApplicationProvider.getApplicationContext();
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
final int[] previewSamples = TextReadingPreviewController.getPreviewSampleLayouts(context);
|
mPreviewContentDescriptions =
|
||||||
|
TextReadingPreviewController.getPreviewSampleContentDescriptions(mContext);
|
||||||
|
final int[] previewSamples = TextReadingPreviewController.getPreviewSampleLayouts(mContext);
|
||||||
mPreviewSampleCount = previewSamples.length;
|
mPreviewSampleCount = previewSamples.length;
|
||||||
final Configuration[] configurations = createConfigurations(mPreviewSampleCount);
|
final Configuration[] configurations = createConfigurations(mPreviewSampleCount);
|
||||||
mTextReadingPreviewPreference = new TextReadingPreviewPreference(context);
|
mTextReadingPreviewPreference = new TextReadingPreviewPreference(mContext);
|
||||||
mPreviewPagerAdapter =
|
mPreviewPagerAdapter =
|
||||||
spy(new PreviewPagerAdapter(context, /* isLayoutRtl= */ false,
|
spy(new PreviewPagerAdapter(mContext, /* isLayoutRtl= */ false,
|
||||||
previewSamples, configurations));
|
previewSamples, configurations));
|
||||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
final View view =
|
final View view =
|
||||||
inflater.inflate(mTextReadingPreviewPreference.getLayoutResource(),
|
inflater.inflate(mTextReadingPreviewPreference.getLayoutResource(),
|
||||||
new LinearLayout(context), false);
|
new LinearLayout(mContext), false);
|
||||||
mHolder = PreferenceViewHolder.createInstanceForTests(view);
|
mHolder = PreferenceViewHolder.createInstanceForTests(view);
|
||||||
mViewPager = view.findViewById(R.id.preview_pager);
|
mViewPager = view.findViewById(R.id.preview_pager);
|
||||||
|
mTextReadingPreviewPreference.setContentDescription(mPreviewContentDescriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void changePreviewPage_getExpectedContentDescription() {
|
||||||
|
mTextReadingPreviewPreference.setPreviewAdapter(mPreviewPagerAdapter);
|
||||||
|
mTextReadingPreviewPreference.onBindViewHolder(mHolder);
|
||||||
|
|
||||||
|
// Verify the initial content description
|
||||||
|
assertThat(mViewPager.getContentDescription().toString())
|
||||||
|
.isEqualTo(mContext.getString(mPreviewContentDescriptions[0]));
|
||||||
|
|
||||||
|
// Change the preview page
|
||||||
|
mViewPager.setCurrentItem(1);
|
||||||
|
assertThat(mViewPager.getContentDescription().toString())
|
||||||
|
.isEqualTo(mContext.getString(mPreviewContentDescriptions[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.android.settings.accessibility.AccessibilityUtil.State.OFF;
|
||||||
|
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
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.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class ToggleAutoclickMainSwitchPreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String PREFERENCE_KEY = "accessibility_autoclick_main_switch";
|
||||||
|
|
||||||
|
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
|
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
private ToggleAutoclickMainSwitchPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mController = new ToggleAutoclickMainSwitchPreferenceController(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
|
||||||
|
public void setChecked_withTrue_shouldUpdateSetting() {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, OFF);
|
||||||
|
|
||||||
|
mController.setChecked(true);
|
||||||
|
|
||||||
|
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, OFF))
|
||||||
|
.isEqualTo(ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setChecked_withFalse_shouldUpdateSetting() {
|
||||||
|
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, ON);
|
||||||
|
|
||||||
|
mController.setChecked(false);
|
||||||
|
|
||||||
|
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, OFF))
|
||||||
|
.isEqualTo(OFF);
|
||||||
|
}
|
||||||
|
}
|
@@ -36,6 +36,9 @@ import android.content.pm.PackageManager;
|
|||||||
import android.hardware.face.Face;
|
import android.hardware.face.Face;
|
||||||
import android.hardware.face.FaceManager;
|
import android.hardware.face.FaceManager;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -50,6 +53,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
|||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -67,6 +71,8 @@ public class FaceStatusPreferenceControllerTest {
|
|||||||
|
|
||||||
private static final String TEST_PREF_KEY = "baz";
|
private static final String TEST_PREF_KEY = "baz";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
@Mock
|
@Mock
|
||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -125,7 +131,8 @@ public class FaceStatusPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateState_noFace_shouldShowDefaultSummary() {
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void updateState_noFace_flagOff_shouldShowDefaultSummary() {
|
||||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
|
||||||
mController.updateState(mPreference);
|
mController.updateState(mPreference);
|
||||||
@@ -135,6 +142,18 @@ public class FaceStatusPreferenceControllerTest {
|
|||||||
assertThat(mPreference.isVisible()).isTrue();
|
assertThat(mPreference.isVisible()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void updateState_noFace_flagOn_shouldShowDefaultSummary() {
|
||||||
|
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertThat(mPreference.getSummary()).isEqualTo(
|
||||||
|
mContext.getString(R.string.security_settings_face_preference_summary_none_new));
|
||||||
|
assertThat(mPreference.isVisible()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateState_hasFace_shouldShowSummary() {
|
public void updateState_hasFace_shouldShowSummary() {
|
||||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
@@ -36,6 +36,9 @@ import android.content.pm.PackageManager;
|
|||||||
import android.hardware.fingerprint.Fingerprint;
|
import android.hardware.fingerprint.Fingerprint;
|
||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -51,6 +54,7 @@ import com.android.settingslib.utils.StringUtil;
|
|||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -66,6 +70,8 @@ import java.util.Collections;
|
|||||||
@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
|
@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
|
||||||
public class FingerprintStatusPreferenceControllerTest {
|
public class FingerprintStatusPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
@Mock
|
@Mock
|
||||||
private LockPatternUtils mLockPatternUtils;
|
private LockPatternUtils mLockPatternUtils;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -125,7 +131,8 @@ public class FingerprintStatusPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateState_noFingerprint_shouldShowDefaultSummary() {
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void updateState_noFingerprint_flagOff_shouldShowDefaultSummary() {
|
||||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
|
||||||
mController.updateState(mPreference);
|
mController.updateState(mPreference);
|
||||||
@@ -135,6 +142,19 @@ public class FingerprintStatusPreferenceControllerTest {
|
|||||||
assertThat(mPreference.isVisible()).isTrue();
|
assertThat(mPreference.isVisible()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void updateState_noFingerprint_flagOn_shouldShowDefaultSummary() {
|
||||||
|
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
assertThat(mPreference.getSummary()).isEqualTo(
|
||||||
|
mContext.getString(
|
||||||
|
R.string.security_settings_fingerprint_preference_summary_none_new));
|
||||||
|
assertThat(mPreference.isVisible()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateState_hasFingerprint_shouldShowSummary() {
|
public void updateState_hasFingerprint_shouldShowSummary() {
|
||||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||||
|
@@ -16,11 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.communal;
|
package com.android.settings.communal;
|
||||||
|
|
||||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
|
||||||
import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2;
|
import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -66,6 +63,7 @@ public class CommunalPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||||
public void isAvailable_communalEnabled_shouldBeTrueForPrimaryUser() {
|
public void isAvailable_communalEnabled_shouldBeTrueForPrimaryUser() {
|
||||||
setCommunalEnabled(true);
|
setCommunalEnabled(true);
|
||||||
mShadowUserManager.setUserForeground(true);
|
mShadowUserManager.setUserForeground(true);
|
||||||
@@ -73,6 +71,7 @@ public class CommunalPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||||
public void isAvailable_communalEnabled_shouldBeFalseForSecondaryUser() {
|
public void isAvailable_communalEnabled_shouldBeFalseForSecondaryUser() {
|
||||||
setCommunalEnabled(true);
|
setCommunalEnabled(true);
|
||||||
mShadowUserManager.setUserForeground(false);
|
mShadowUserManager.setUserForeground(false);
|
||||||
@@ -80,6 +79,7 @@ public class CommunalPreferenceControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||||
public void isAvailable_communalDisabled_shouldBeFalseForPrimaryUser() {
|
public void isAvailable_communalDisabled_shouldBeFalseForPrimaryUser() {
|
||||||
setCommunalEnabled(false);
|
setCommunalEnabled(false);
|
||||||
mShadowUserManager.setUserForeground(true);
|
mShadowUserManager.setUserForeground(true);
|
||||||
@@ -88,36 +88,8 @@ public class CommunalPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
|
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||||
public void isAvailable_communalOnMobileEnabled_shouldBeTrueForPrimaryUser() {
|
public void isAvailable_glanceableHubV2Enabled_shouldBeFalseForPrimaryUser() {
|
||||||
setCommunalEnabled(false);
|
setCommunalEnabled(true);
|
||||||
setCommunalOnMobileEnabled(true);
|
|
||||||
mShadowUserManager.setUserForeground(true);
|
|
||||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
|
|
||||||
public void isAvailable_communalOnMobileEnabled_shouldBeFalseForSecondaryUser() {
|
|
||||||
setCommunalEnabled(false);
|
|
||||||
setCommunalOnMobileEnabled(true);
|
|
||||||
mShadowUserManager.setUserForeground(false);
|
|
||||||
assertFalse(mController.isAvailable());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
|
|
||||||
public void isAvailable_communalOnMobileDisabled_shouldBeFalseForPrimaryUser() {
|
|
||||||
setCommunalEnabled(false);
|
|
||||||
setCommunalOnMobileEnabled(false);
|
|
||||||
mShadowUserManager.setUserForeground(true);
|
|
||||||
assertFalse(mController.isAvailable());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
|
||||||
public void isAvailable_glanceableHubV2FlagDisabled_shouldBeFalseForPrimaryUser() {
|
|
||||||
setCommunalEnabled(false);
|
|
||||||
setCommunalOnMobileEnabled(true);
|
|
||||||
mShadowUserManager.setUserForeground(true);
|
mShadowUserManager.setUserForeground(true);
|
||||||
assertFalse(mController.isAvailable());
|
assertFalse(mController.isAvailable());
|
||||||
}
|
}
|
||||||
@@ -125,9 +97,4 @@ public class CommunalPreferenceControllerTest {
|
|||||||
private void setCommunalEnabled(boolean enabled) {
|
private void setCommunalEnabled(boolean enabled) {
|
||||||
SettingsShadowResources.overrideResource(R.bool.config_show_communal_settings, enabled);
|
SettingsShadowResources.overrideResource(R.bool.config_show_communal_settings, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCommunalOnMobileEnabled(boolean enabled) {
|
|
||||||
SettingsShadowResources.overrideResource(
|
|
||||||
R.bool.config_show_communal_settings_mobile, enabled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -45,6 +45,7 @@ import android.bluetooth.BluetoothLeBroadcastMetadata;
|
|||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -79,6 +80,7 @@ import com.android.settings.testutils.shadow.ShadowFragment;
|
|||||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
import com.android.settingslib.bluetooth.BluetoothCallback;
|
||||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
import com.android.settingslib.bluetooth.HeadsetProfile;
|
import com.android.settingslib.bluetooth.HeadsetProfile;
|
||||||
@@ -144,6 +146,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
@Mock private LeAudioProfile mLeAudioProfile;
|
@Mock private LeAudioProfile mLeAudioProfile;
|
||||||
@Mock private A2dpProfile mA2dpProfile;
|
@Mock private A2dpProfile mA2dpProfile;
|
||||||
@Mock private HeadsetProfile mHeadsetProfile;
|
@Mock private HeadsetProfile mHeadsetProfile;
|
||||||
|
@Mock private ContentResolver mContentResolver;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private AudioSharingDevicePreferenceController mController;
|
private AudioSharingDevicePreferenceController mController;
|
||||||
@@ -156,7 +159,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = ApplicationProvider.getApplicationContext();
|
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||||
mShadowBluetoothAdapter.setEnabled(true);
|
mShadowBluetoothAdapter.setEnabled(true);
|
||||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||||
@@ -185,6 +188,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP);
|
when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP);
|
||||||
when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
|
when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
|
||||||
when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
|
when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
|
||||||
|
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||||
when(mScreen.getContext()).thenReturn(mContext);
|
when(mScreen.getContext()).thenReturn(mContext);
|
||||||
mPreferenceGroup = spy(new PreferenceCategory(mContext));
|
mPreferenceGroup = spy(new PreferenceCategory(mContext));
|
||||||
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
|
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
|
||||||
@@ -211,6 +215,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
verify(mAssistant, never())
|
verify(mAssistant, never())
|
||||||
.registerServiceCallBack(
|
.registerServiceCallBack(
|
||||||
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
|
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||||
|
verify(mContentResolver, never())
|
||||||
|
.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(
|
||||||
|
BluetoothUtils.getPrimaryGroupIdUriForBroadcast()),
|
||||||
|
false,
|
||||||
|
mController.mSettingsObserver);
|
||||||
verify(mBluetoothDeviceUpdater, never()).registerCallback();
|
verify(mBluetoothDeviceUpdater, never()).registerCallback();
|
||||||
verify(mBluetoothDeviceUpdater, never()).refreshPreference();
|
verify(mBluetoothDeviceUpdater, never()).refreshPreference();
|
||||||
}
|
}
|
||||||
@@ -224,6 +234,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
verify(mAssistant)
|
verify(mAssistant)
|
||||||
.registerServiceCallBack(
|
.registerServiceCallBack(
|
||||||
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
|
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||||
|
verify(mContentResolver)
|
||||||
|
.registerContentObserver(
|
||||||
|
Settings.Secure.getUriFor(
|
||||||
|
BluetoothUtils.getPrimaryGroupIdUriForBroadcast()),
|
||||||
|
false,
|
||||||
|
mController.mSettingsObserver);
|
||||||
verify(mBluetoothDeviceUpdater).registerCallback();
|
verify(mBluetoothDeviceUpdater).registerCallback();
|
||||||
verify(mBluetoothDeviceUpdater).refreshPreference();
|
verify(mBluetoothDeviceUpdater).refreshPreference();
|
||||||
}
|
}
|
||||||
@@ -236,6 +252,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
verify(mDialogHandler, never()).unregisterCallbacks();
|
verify(mDialogHandler, never()).unregisterCallbacks();
|
||||||
verify(mAssistant, never())
|
verify(mAssistant, never())
|
||||||
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||||
|
verify(mContentResolver, never()).unregisterContentObserver(mController.mSettingsObserver);
|
||||||
verify(mBluetoothDeviceUpdater, never()).unregisterCallback();
|
verify(mBluetoothDeviceUpdater, never()).unregisterCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +264,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
verify(mDialogHandler).unregisterCallbacks();
|
verify(mDialogHandler).unregisterCallbacks();
|
||||||
verify(mAssistant)
|
verify(mAssistant)
|
||||||
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||||
|
verify(mContentResolver).unregisterContentObserver(mController.mSettingsObserver);
|
||||||
verify(mBluetoothDeviceUpdater).unregisterCallback();
|
verify(mBluetoothDeviceUpdater).unregisterCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,6 +503,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
|||||||
verifyNoInteractions(mDialogHandler);
|
verifyNoInteractions(mDialogHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onFallbackDeviceChanged_updateSummary() {
|
||||||
|
mController.mSettingsObserver.onChange(true);
|
||||||
|
verify(mBluetoothDeviceUpdater).refreshPreference();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||||
public void handleDeviceClickFromIntent_noDevice_doNothing() {
|
public void handleDeviceClickFromIntent_noDevice_doNothing() {
|
||||||
|
@@ -26,6 +26,9 @@ import static com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING;
|
|||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
@@ -39,6 +42,7 @@ import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
|||||||
import android.bluetooth.BluetoothStatusCodes;
|
import android.bluetooth.BluetoothStatusCodes;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
@@ -52,6 +56,7 @@ import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
|||||||
import com.android.settings.widget.EntityHeaderController;
|
import com.android.settings.widget.EntityHeaderController;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -254,6 +259,7 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE)
|
||||||
public void testCallback_onReceiveStateChanged_updateButton() {
|
public void testCallback_onReceiveStateChanged_updateButton() {
|
||||||
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||||
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||||
@@ -271,6 +277,7 @@ public class AudioStreamHeaderControllerTest {
|
|||||||
verify(mHeaderController, times(2))
|
verify(mHeaderController, times(2))
|
||||||
.setSummary(mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY));
|
.setSummary(mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY));
|
||||||
verify(mHeaderController, times(2)).done(true);
|
verify(mHeaderController, times(2)).done(true);
|
||||||
|
verify(mAudioStreamsHelper, never()).startMediaService(any(), anyInt(), anyString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -19,6 +19,10 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams;
|
|||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.BROADCAST_ID;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.DEVICES;
|
||||||
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.LEAVE_BROADCAST_ACTION;
|
import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamMediaService.LEAVE_BROADCAST_ACTION;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PRIVATE_BROADCAST_RECEIVE_DATA;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.DECRYPTION_FAILED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.PAUSED;
|
||||||
|
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState.STREAMING;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -57,6 +61,7 @@ import android.os.Looper;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.flag.junit.SetFlagsRule;
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
|
import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
@@ -69,6 +74,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
|||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
|
import com.android.settingslib.bluetooth.PrivateBroadcastReceiveData;
|
||||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
import com.android.settingslib.flags.Flags;
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
@@ -116,6 +122,8 @@ public class AudioStreamMediaServiceTest {
|
|||||||
@Mock private VolumeControlProfile mVolumeControlProfile;
|
@Mock private VolumeControlProfile mVolumeControlProfile;
|
||||||
@Mock private CachedBluetoothDevice mCachedBluetoothDevice;
|
@Mock private CachedBluetoothDevice mCachedBluetoothDevice;
|
||||||
@Mock private BluetoothDevice mDevice;
|
@Mock private BluetoothDevice mDevice;
|
||||||
|
@Mock
|
||||||
|
private BluetoothDevice mDevice2;
|
||||||
@Mock private ISession mISession;
|
@Mock private ISession mISession;
|
||||||
@Mock private ISessionController mISessionController;
|
@Mock private ISessionController mISessionController;
|
||||||
@Mock private PackageManager mPackageManager;
|
@Mock private PackageManager mPackageManager;
|
||||||
@@ -240,6 +248,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onDestroy_flagOn_cleanup() {
|
public void onDestroy_flagOn_cleanup() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
var devices = new ArrayList<BluetoothDevice>();
|
var devices = new ArrayList<BluetoothDevice>();
|
||||||
devices.add(mDevice);
|
devices.add(mDevice);
|
||||||
|
|
||||||
@@ -256,8 +265,33 @@ public class AudioStreamMediaServiceTest {
|
|||||||
verify(mVolumeControlProfile).unregisterCallback(any());
|
verify(mVolumeControlProfile).unregisterCallback(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onDestroy_flagOn_cleanup() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
mAudioStreamMediaService.onDestroy();
|
||||||
|
|
||||||
|
verify(mBluetoothEventManager).unregisterCallback(any());
|
||||||
|
verify(mLeBroadcastAssistant).unregisterServiceCallBack(any());
|
||||||
|
verify(mVolumeControlProfile).unregisterCallback(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_invalidData_stopSelf() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
Intent intent = setupReceiveDataIntent(-1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartCommand_noBroadcastId_stopSelf() {
|
public void onStartCommand_noBroadcastId_stopSelf() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
mAudioStreamMediaService.onStartCommand(new Intent(), /* flags= */ 0, /* startId= */ 0);
|
mAudioStreamMediaService.onStartCommand(new Intent(), /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
verify(mAudioStreamMediaService).stopSelf();
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
@@ -265,6 +299,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartCommand_noDevice_stopSelf() {
|
public void onStartCommand_noDevice_stopSelf() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.putExtra(BROADCAST_ID, 1);
|
intent.putExtra(BROADCAST_ID, 1);
|
||||||
|
|
||||||
@@ -273,8 +308,110 @@ public class AudioStreamMediaServiceTest {
|
|||||||
verify(mAudioStreamMediaService).stopSelf();
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_createSessionAndStartForeground() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
ArgumentCaptor<Notification> notificationCapture = ArgumentCaptor.forClass(
|
||||||
|
Notification.class);
|
||||||
|
verify(mAudioStreamMediaService).startForeground(anyInt(), notificationCapture.capture());
|
||||||
|
var notification = notificationCapture.getValue();
|
||||||
|
assertThat(notification.getSmallIcon()).isNotNull();
|
||||||
|
assertThat(notification.isStyle(Notification.MediaStyle.class)).isTrue();
|
||||||
|
|
||||||
|
verify(mAudioStreamMediaService, never()).stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_decryptionFailed_stopSelf() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, DECRYPTION_FAILED);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_addDevice() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent1 = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent1, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
Intent intent2 = setupReceiveDataIntent(1, mDevice2, PAUSED);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent2, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
ArgumentCaptor<Notification> notificationCapture = ArgumentCaptor.forClass(
|
||||||
|
Notification.class);
|
||||||
|
verify(mAudioStreamMediaService).startForeground(anyInt(), notificationCapture.capture());
|
||||||
|
var notification = notificationCapture.getValue();
|
||||||
|
assertThat(notification.getSmallIcon()).isNotNull();
|
||||||
|
assertThat(notification.isStyle(Notification.MediaStyle.class)).isTrue();
|
||||||
|
|
||||||
|
assertThat(mAudioStreamMediaService.mStateByDevice).isNotNull();
|
||||||
|
var deviceState = mAudioStreamMediaService.mStateByDevice.get(mDevice);
|
||||||
|
assertThat(deviceState).isNotNull();
|
||||||
|
assertThat(deviceState).isEqualTo(STREAMING);
|
||||||
|
var device2State = mAudioStreamMediaService.mStateByDevice.get(mDevice2);
|
||||||
|
assertThat(device2State).isNotNull();
|
||||||
|
assertThat(device2State).isEqualTo(PAUSED);
|
||||||
|
verify(mAudioStreamMediaService, never()).stopSelf();
|
||||||
|
verify(mNotificationManager).notify(anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_updateState() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent1 = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent1, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
Intent intent2 = setupReceiveDataIntent(1, mDevice, PAUSED);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent2, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
ArgumentCaptor<Notification> notificationCapture = ArgumentCaptor.forClass(
|
||||||
|
Notification.class);
|
||||||
|
verify(mAudioStreamMediaService).startForeground(anyInt(), notificationCapture.capture());
|
||||||
|
var notification = notificationCapture.getValue();
|
||||||
|
assertThat(notification.getSmallIcon()).isNotNull();
|
||||||
|
assertThat(notification.isStyle(Notification.MediaStyle.class)).isTrue();
|
||||||
|
|
||||||
|
assertThat(mAudioStreamMediaService.mStateByDevice).isNotNull();
|
||||||
|
var deviceState = mAudioStreamMediaService.mStateByDevice.get(mDevice);
|
||||||
|
assertThat(deviceState).isNotNull();
|
||||||
|
assertThat(deviceState).isEqualTo(PAUSED);
|
||||||
|
verify(mAudioStreamMediaService, never()).stopSelf();
|
||||||
|
verify(mNotificationManager).notify(anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_onStartCommand_newBroadcastId() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent1 = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent1, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
Intent intent2 = setupReceiveDataIntent(2, mDevice2, PAUSED);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent2, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
ArgumentCaptor<Notification> notificationCapture = ArgumentCaptor.forClass(
|
||||||
|
Notification.class);
|
||||||
|
verify(mAudioStreamMediaService).startForeground(anyInt(), notificationCapture.capture());
|
||||||
|
var notification = notificationCapture.getValue();
|
||||||
|
assertThat(notification.getSmallIcon()).isNotNull();
|
||||||
|
assertThat(notification.isStyle(Notification.MediaStyle.class)).isTrue();
|
||||||
|
|
||||||
|
assertThat(mAudioStreamMediaService.mStateByDevice).isNotNull();
|
||||||
|
var oldDeviceState = mAudioStreamMediaService.mStateByDevice.get(mDevice);
|
||||||
|
assertThat(oldDeviceState).isNull();
|
||||||
|
var newDeviceState = mAudioStreamMediaService.mStateByDevice.get(mDevice2);
|
||||||
|
assertThat(newDeviceState).isEqualTo(PAUSED);
|
||||||
|
verify(mAudioStreamMediaService, never()).stopSelf();
|
||||||
|
verify(mNotificationManager).notify(anyInt(), any());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartCommand_createSessionAndStartForeground() {
|
public void onStartCommand_createSessionAndStartForeground() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
var devices = new ArrayList<BluetoothDevice>();
|
var devices = new ArrayList<BluetoothDevice>();
|
||||||
devices.add(mDevice);
|
devices.add(mDevice);
|
||||||
|
|
||||||
@@ -317,6 +454,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assistantCallback_onReceiveStateChanged_connected_doNothing() {
|
public void assistantCallback_onReceiveStateChanged_connected_doNothing() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
|
||||||
@@ -338,6 +476,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assistantCallback_onReceiveStateChanged_hysteresis_updateNotification() {
|
public void assistantCallback_onReceiveStateChanged_hysteresis_updateNotification() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
|
||||||
@@ -357,6 +496,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assistantCallback_onReceiveStateChanged_hysteresis_flagOff_doNothing() {
|
public void assistantCallback_onReceiveStateChanged_hysteresis_flagOff_doNothing() {
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX);
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
|
||||||
@@ -386,6 +526,7 @@ public class AudioStreamMediaServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void bluetoothCallback_onDeviceDisconnect_stopSelf() {
|
public void bluetoothCallback_onDeviceDisconnect_stopSelf() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
mAudioStreamMediaService.onCreate();
|
mAudioStreamMediaService.onCreate();
|
||||||
assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
|
assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
|
||||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||||
@@ -398,9 +539,26 @@ public class AudioStreamMediaServiceTest {
|
|||||||
verify(mAudioStreamMediaService).stopSelf();
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_bluetoothCallback_onDeviceDisconnect_stopSelf() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.mBluetoothCallback.onProfileConnectionStateChanged(
|
||||||
|
mCachedBluetoothDevice, BluetoothAdapter.STATE_DISCONNECTED,
|
||||||
|
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
|
||||||
|
|
||||||
|
verify(mAudioStreamMediaService).stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mediaSessionCallback_onPause_setVolume() {
|
public void mediaSessionCallback_onPause_setVolume() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
mAudioStreamMediaService.onCreate();
|
mAudioStreamMediaService.onCreate();
|
||||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||||
@@ -415,9 +573,26 @@ public class AudioStreamMediaServiceTest {
|
|||||||
eq(1));
|
eq(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_mediaSessionCallback_onPause_setVolume() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
|
||||||
|
mAudioStreamMediaService.mMediaSessionCallback.onPause();
|
||||||
|
|
||||||
|
verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK), eq(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mediaSessionCallback_onPlay_setVolume() {
|
public void mediaSessionCallback_onPlay_setVolume() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
mAudioStreamMediaService.onCreate();
|
mAudioStreamMediaService.onCreate();
|
||||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||||
@@ -432,9 +607,66 @@ public class AudioStreamMediaServiceTest {
|
|||||||
eq(0));
|
eq(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_mediaSessionCallback_onPlay_setVolume() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
|
||||||
|
mAudioStreamMediaService.mMediaSessionCallback.onPlay();
|
||||||
|
|
||||||
|
verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK), eq(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_mediaSessionCallback_onButtonEventPlay_setVolume() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
|
||||||
|
|
||||||
|
Intent buttonEvent = new Intent();
|
||||||
|
buttonEvent.putExtra(Intent.EXTRA_KEY_EVENT,
|
||||||
|
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY));
|
||||||
|
mAudioStreamMediaService.mMediaSessionCallback.onMediaButtonEvent(buttonEvent);
|
||||||
|
|
||||||
|
verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK), eq(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_mediaSessionCallback_onButtonEventPause_setVolume() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
|
||||||
|
|
||||||
|
Intent buttonEvent = new Intent();
|
||||||
|
buttonEvent.putExtra(Intent.EXTRA_KEY_EVENT,
|
||||||
|
new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PAUSE));
|
||||||
|
mAudioStreamMediaService.mMediaSessionCallback.onMediaButtonEvent(buttonEvent);
|
||||||
|
|
||||||
|
verify(mVolumeControlProfile).setDeviceVolume(any(), anyInt(), anyBoolean());
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_MUTE_BUTTON_CLICK), eq(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mediaSessionCallback_onCustomAction_leaveBroadcast() {
|
public void mediaSessionCallback_onCustomAction_leaveBroadcast() {
|
||||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
mAudioStreamMediaService.onCreate();
|
mAudioStreamMediaService.onCreate();
|
||||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||||
@@ -449,6 +681,23 @@ public class AudioStreamMediaServiceTest {
|
|||||||
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK));
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void byReceiveStateFlagOn_mediaSessionCallback_onCustomAction_leaveBroadcast() {
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||||
|
mSetFlagsRule.enableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||||
|
|
||||||
|
mAudioStreamMediaService.onCreate();
|
||||||
|
Intent intent = setupReceiveDataIntent(1, mDevice, STREAMING);
|
||||||
|
mAudioStreamMediaService.onStartCommand(intent, /* flags= */ 0, /* startId= */ 0);
|
||||||
|
assertThat(mAudioStreamMediaService.mMediaSessionCallback).isNotNull();
|
||||||
|
mAudioStreamMediaService.mMediaSessionCallback.onCustomAction(LEAVE_BROADCAST_ACTION,
|
||||||
|
Bundle.EMPTY);
|
||||||
|
|
||||||
|
verify(mAudioStreamsHelper).removeSource(anyInt());
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_NOTIFICATION_LEAVE_BUTTON_CLICK));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onBind_returnNull() {
|
public void onBind_returnNull() {
|
||||||
IBinder binder = mAudioStreamMediaService.onBind(new Intent());
|
IBinder binder = mAudioStreamMediaService.onBind(new Intent());
|
||||||
@@ -466,4 +715,13 @@ public class AudioStreamMediaServiceTest {
|
|||||||
intent.putParcelableArrayListExtra(DEVICES, devices);
|
intent.putParcelableArrayListExtra(DEVICES, devices);
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Intent setupReceiveDataIntent(int broadcastId, BluetoothDevice device,
|
||||||
|
LocalBluetoothLeBroadcastAssistant.LocalBluetoothLeBroadcastSourceState state) {
|
||||||
|
when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice);
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_PRIVATE_BROADCAST_RECEIVE_DATA,
|
||||||
|
new PrivateBroadcastReceiveData(device, 1, broadcastId, "programInfo", state));
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,9 +22,12 @@ import static com.android.settings.connecteddevice.audiosharing.audiostreams.Sou
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
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.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -33,6 +36,9 @@ import android.bluetooth.BluetoothLeBroadcastMetadata;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -43,6 +49,7 @@ import com.android.settings.SettingsActivity;
|
|||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
import com.android.settings.testutils.shadow.ShadowFragment;
|
import com.android.settings.testutils.shadow.ShadowFragment;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
import com.android.settingslib.flags.Flags;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -62,6 +69,7 @@ import org.robolectric.annotation.Config;
|
|||||||
})
|
})
|
||||||
public class SourceAddedStateTest {
|
public class SourceAddedStateTest {
|
||||||
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
|
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
private static final int BROADCAST_ID = 1;
|
private static final int BROADCAST_ID = 1;
|
||||||
private static final String BROADCAST_TITLE = "title";
|
private static final String BROADCAST_TITLE = "title";
|
||||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
@@ -105,7 +113,8 @@ public class SourceAddedStateTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPerformAction() {
|
@DisableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE)
|
||||||
|
public void testPerformAction_startService() {
|
||||||
mInstance.setAudioStreamsRepositoryForTesting(mRepository);
|
mInstance.setAudioStreamsRepositoryForTesting(mRepository);
|
||||||
BluetoothLeBroadcastMetadata mockMetadata = mock(BluetoothLeBroadcastMetadata.class);
|
BluetoothLeBroadcastMetadata mockMetadata = mock(BluetoothLeBroadcastMetadata.class);
|
||||||
when(mRepository.getCachedMetadata(anyInt())).thenReturn(mockMetadata);
|
when(mRepository.getCachedMetadata(anyInt())).thenReturn(mockMetadata);
|
||||||
@@ -124,6 +133,27 @@ public class SourceAddedStateTest {
|
|||||||
verify(mHelper).startMediaService(eq(mContext), eq(BROADCAST_ID), eq(BROADCAST_TITLE));
|
verify(mHelper).startMediaService(eq(mContext), eq(BROADCAST_ID), eq(BROADCAST_TITLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE)
|
||||||
|
public void testPerformAction_skipStartService() {
|
||||||
|
mInstance.setAudioStreamsRepositoryForTesting(mRepository);
|
||||||
|
BluetoothLeBroadcastMetadata mockMetadata = mock(BluetoothLeBroadcastMetadata.class);
|
||||||
|
when(mRepository.getCachedMetadata(anyInt())).thenReturn(mockMetadata);
|
||||||
|
when(mPreference.getContext()).thenReturn(mContext);
|
||||||
|
when(mPreference.getSourceOriginForLogging())
|
||||||
|
.thenReturn(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS);
|
||||||
|
|
||||||
|
mInstance.performAction(mPreference, mController, mHelper);
|
||||||
|
|
||||||
|
verify(mRepository).saveMetadata(eq(mContext), eq(mockMetadata));
|
||||||
|
verify(mFeatureFactory.metricsFeatureProvider)
|
||||||
|
.action(
|
||||||
|
eq(mContext),
|
||||||
|
eq(SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED),
|
||||||
|
eq(SourceOriginForLogging.QR_CODE_SCAN_SETTINGS.ordinal()));
|
||||||
|
verify(mHelper, never()).startMediaService(any(), anyInt(), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOnClickListener_startSubSettings() {
|
public void testGetOnClickListener_startSubSettings() {
|
||||||
when(mController.getFragment()).thenReturn(mFragment);
|
when(mController.getFragment()).thenReturn(mFragment);
|
||||||
|
@@ -18,22 +18,30 @@ package com.android.settings.network.ethernet
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class EthernetInterfaceDetailsControllerTest {
|
class EthernetInterfaceDetailsControllerTest {
|
||||||
private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment()
|
private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment()
|
||||||
|
private val lifecycle = mock<Lifecycle>()
|
||||||
|
|
||||||
private val context: Context =
|
private val context: Context =
|
||||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {}
|
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {}
|
||||||
|
|
||||||
private val ethernetInterfaceDetailsController =
|
private val ethernetInterfaceDetailsController =
|
||||||
EthernetInterfaceDetailsController(context, ethernetInterfaceDetailsFragment, "eth0")
|
EthernetInterfaceDetailsController(
|
||||||
|
context,
|
||||||
|
ethernetInterfaceDetailsFragment,
|
||||||
|
"eth0",
|
||||||
|
lifecycle,
|
||||||
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isAvailable_ShouldReturnTrue() {
|
fun isAvailable_ShouldReturnTrue() {
|
||||||
|
@@ -18,14 +18,19 @@ package com.android.settings.network.ethernet
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
|
import android.net.ConnectivityManager
|
||||||
import android.net.EthernetManager
|
import android.net.EthernetManager
|
||||||
import android.net.EthernetManager.STATE_ABSENT
|
import android.net.EthernetManager.STATE_ABSENT
|
||||||
import android.net.EthernetManager.STATE_LINK_DOWN
|
import android.net.EthernetManager.STATE_LINK_DOWN
|
||||||
import android.net.EthernetManager.STATE_LINK_UP
|
import android.net.EthernetManager.STATE_LINK_UP
|
||||||
import android.net.IpConfiguration
|
import android.net.IpConfiguration
|
||||||
|
import android.net.LinkProperties
|
||||||
|
import android.net.Network
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
@@ -34,12 +39,15 @@ import org.mockito.kotlin.mock
|
|||||||
class EthernetInterfaceTest {
|
class EthernetInterfaceTest {
|
||||||
|
|
||||||
private val mockEthernetManager = mock<EthernetManager>()
|
private val mockEthernetManager = mock<EthernetManager>()
|
||||||
|
private val mockConnectivityManager = mock<ConnectivityManager>()
|
||||||
|
private val mockNetwork = mock<Network>()
|
||||||
|
|
||||||
private val context: Context =
|
private val context: Context =
|
||||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
|
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
|
||||||
override fun getSystemService(name: String): Any? =
|
override fun getSystemService(name: String): Any? =
|
||||||
when (name) {
|
when (name) {
|
||||||
Context.ETHERNET_SERVICE -> mockEthernetManager
|
Context.ETHERNET_SERVICE -> mockEthernetManager
|
||||||
|
Context.CONNECTIVITY_SERVICE -> mockConnectivityManager
|
||||||
else -> super.getSystemService(name)
|
else -> super.getSystemService(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,4 +93,27 @@ class EthernetInterfaceTest {
|
|||||||
IpConfiguration.IpAssignment.UNASSIGNED,
|
IpConfiguration.IpAssignment.UNASSIGNED,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun linkPropertiesChanged_shouldUpdate() {
|
||||||
|
val linkProperties = LinkProperties()
|
||||||
|
linkProperties.setInterfaceName("eth0")
|
||||||
|
linkProperties.setUsePrivateDns(true)
|
||||||
|
|
||||||
|
ethernetInterface.networkCallback.onLinkPropertiesChanged(mockNetwork, linkProperties)
|
||||||
|
|
||||||
|
assertEquals(ethernetInterface.getLinkProperties().getInterfaceName(), "eth0")
|
||||||
|
assertTrue(ethernetInterface.getLinkProperties().isPrivateDnsActive())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun linkPropertiesChanged_iddoesnotmatch_shouldNotUpdate() {
|
||||||
|
val linkProperties = LinkProperties()
|
||||||
|
linkProperties.setInterfaceName("eth1")
|
||||||
|
linkProperties.setUsePrivateDns(true)
|
||||||
|
|
||||||
|
ethernetInterface.networkCallback.onLinkPropertiesChanged(mockNetwork, linkProperties)
|
||||||
|
|
||||||
|
assertFalse(ethernetInterface.getLinkProperties().isPrivateDnsActive())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.flags.Flags
|
import android.app.supervision.flags.Flags
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.platform.test.annotations.DisableFlags
|
import android.platform.test.annotations.DisableFlags
|
||||||
@@ -24,6 +25,7 @@ import androidx.fragment.app.testing.FragmentScenario
|
|||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.supervision.SupervisionMainSwitchPreference.Companion.REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS
|
||||||
import com.android.settingslib.widget.MainSwitchPreference
|
import com.android.settingslib.widget.MainSwitchPreference
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -57,7 +59,7 @@ class SupervisionDashboardScreenTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
||||||
fun toggleMainSwitch_disablesChildPreferences() {
|
fun toggleMainSwitch_pinVerificationSucceeded_enablesChildPreferences() {
|
||||||
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
||||||
fragment ->
|
fragment ->
|
||||||
val mainSwitchPreference =
|
val mainSwitchPreference =
|
||||||
@@ -68,8 +70,38 @@ class SupervisionDashboardScreenTest {
|
|||||||
assertThat(childPreference.isEnabled).isFalse()
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
|
||||||
mainSwitchPreference.performClick()
|
mainSwitchPreference.performClick()
|
||||||
|
// Pretend the PIN verification succeeded.
|
||||||
|
fragment.onActivityResult(
|
||||||
|
requestCode = REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
resultCode = Activity.RESULT_OK,
|
||||||
|
data = null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(childPreference.isEnabled).isTrue()
|
assertThat(childPreference.isEnabled).isTrue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
||||||
|
fun toggleMainSwitch_pinVerificationFailed_childPreferencesRemainDisabled() {
|
||||||
|
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
||||||
|
fragment ->
|
||||||
|
val mainSwitchPreference =
|
||||||
|
fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!!
|
||||||
|
val childPreference =
|
||||||
|
fragment.findPreference<Preference>(SupervisionPinManagementScreen.KEY)!!
|
||||||
|
|
||||||
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
|
||||||
|
mainSwitchPreference.performClick()
|
||||||
|
// Pretend the PIN verification failed.
|
||||||
|
fragment.onActivityResult(
|
||||||
|
requestCode = REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
resultCode = Activity.RESULT_CANCELED,
|
||||||
|
data = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(childPreference.isEnabled).isFalse()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,25 +15,33 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.supervision
|
package com.android.settings.supervision
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.supervision.SupervisionManager
|
import android.app.supervision.SupervisionManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.preference.Preference
|
||||||
import androidx.test.core.app.ApplicationProvider
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settings.supervision.SupervisionMainSwitchPreference.Companion.REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS
|
||||||
|
import com.android.settingslib.metadata.PreferenceLifecycleContext
|
||||||
import com.android.settingslib.preference.createAndBindWidget
|
import com.android.settingslib.preference.createAndBindWidget
|
||||||
import com.android.settingslib.widget.MainSwitchPreference
|
import com.android.settingslib.widget.MainSwitchPreference
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.argumentCaptor
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.eq
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.never
|
||||||
import org.mockito.kotlin.stub
|
import org.mockito.kotlin.stub
|
||||||
import org.mockito.kotlin.verify
|
import org.mockito.kotlin.verify
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class SupervisionMainSwitchPreferenceTest {
|
class SupervisionMainSwitchPreferenceTest {
|
||||||
private val preference = SupervisionMainSwitchPreference()
|
private val mockLifeCycleContext = mock<PreferenceLifecycleContext>()
|
||||||
|
|
||||||
private val mockSupervisionManager = mock<SupervisionManager>()
|
private val mockSupervisionManager = mock<SupervisionManager>()
|
||||||
|
|
||||||
private val appContext: Context = ApplicationProvider.getApplicationContext()
|
private val appContext: Context = ApplicationProvider.getApplicationContext()
|
||||||
@@ -46,6 +54,13 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val preference = SupervisionMainSwitchPreference(context)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
preference.onCreate(mockLifeCycleContext)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun checked_supervisionEnabled_returnTrue() {
|
fun checked_supervisionEnabled_returnTrue() {
|
||||||
setSupervisionEnabled(true)
|
setSupervisionEnabled(true)
|
||||||
@@ -61,7 +76,7 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleOn() {
|
fun toggleOn_triggersPinVerification() {
|
||||||
setSupervisionEnabled(false)
|
setSupervisionEnabled(false)
|
||||||
val widget = getMainSwitchPreference()
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
@@ -69,26 +84,90 @@ class SupervisionMainSwitchPreferenceTest {
|
|||||||
|
|
||||||
widget.performClick()
|
widget.performClick()
|
||||||
|
|
||||||
|
verifyConfirmSupervisionCredentialsActivityStarted()
|
||||||
|
assertThat(widget.isChecked).isFalse()
|
||||||
|
verify(mockSupervisionManager, never()).setSupervisionEnabled(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toggleOn_pinVerificationSucceeded_supervisionEnabled() {
|
||||||
|
setSupervisionEnabled(false)
|
||||||
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isFalse()
|
||||||
|
|
||||||
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_OK,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(widget.isChecked).isTrue()
|
assertThat(widget.isChecked).isTrue()
|
||||||
verify(mockSupervisionManager).setSupervisionEnabled(true)
|
verify(mockSupervisionManager).setSupervisionEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toggleOff() {
|
fun toggleOff_pinVerificationSucceeded_supervisionDisabled() {
|
||||||
setSupervisionEnabled(true)
|
setSupervisionEnabled(true)
|
||||||
val widget = getMainSwitchPreference()
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
assertThat(widget.isChecked).isTrue()
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
|
||||||
widget.performClick()
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_OK,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
assertThat(widget.isChecked).isFalse()
|
assertThat(widget.isChecked).isFalse()
|
||||||
verify(mockSupervisionManager).setSupervisionEnabled(false)
|
verify(mockSupervisionManager).setSupervisionEnabled(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMainSwitchPreference(): MainSwitchPreference =
|
@Test
|
||||||
preference.createAndBindWidget(context)
|
fun toggleOff_pinVerificationFailed_supervisionNotEnabled() {
|
||||||
|
setSupervisionEnabled(true)
|
||||||
|
val widget = getMainSwitchPreference()
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
|
||||||
|
preference.onActivityResult(
|
||||||
|
mockLifeCycleContext,
|
||||||
|
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||||
|
Activity.RESULT_CANCELED,
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(widget.isChecked).isTrue()
|
||||||
|
verify(mockSupervisionManager, never()).setSupervisionEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setSupervisionEnabled(enabled: Boolean) =
|
private fun setSupervisionEnabled(enabled: Boolean) =
|
||||||
mockSupervisionManager.stub { on { isSupervisionEnabled } doReturn enabled }
|
mockSupervisionManager.stub { on { isSupervisionEnabled } doReturn enabled }
|
||||||
|
|
||||||
|
private fun getMainSwitchPreference(): MainSwitchPreference {
|
||||||
|
val widget: MainSwitchPreference = preference.createAndBindWidget(context)
|
||||||
|
|
||||||
|
mockLifeCycleContext.stub {
|
||||||
|
on { findPreference<Preference>(SupervisionMainSwitchPreference.KEY) } doReturn widget
|
||||||
|
on {
|
||||||
|
requirePreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)
|
||||||
|
} doReturn widget
|
||||||
|
}
|
||||||
|
return widget
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyConfirmSupervisionCredentialsActivityStarted() {
|
||||||
|
val intentCaptor = argumentCaptor<Intent>()
|
||||||
|
verify(mockLifeCycleContext)
|
||||||
|
.startActivityForResult(
|
||||||
|
intentCaptor.capture(),
|
||||||
|
eq(REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS),
|
||||||
|
eq(null),
|
||||||
|
)
|
||||||
|
assertThat(intentCaptor.allValues.size).isEqualTo(1)
|
||||||
|
assertThat(intentCaptor.firstValue.component?.className)
|
||||||
|
.isEqualTo(ConfirmSupervisionCredentialsActivity::class.java.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
# Bug component: 970984
|
||||||
|
# Large Screen Experiences App Compat
|
||||||
|
gracielawputri@google.com
|
||||||
|
mcarli@google.com
|
||||||
|
mariiasand@google.com
|
@@ -0,0 +1,5 @@
|
|||||||
|
# Bug component: 970984
|
||||||
|
# Large Screen Experiences App Compat
|
||||||
|
gracielawputri@google.com
|
||||||
|
mcarli@google.com
|
||||||
|
mariiasand@google.com
|
@@ -27,13 +27,12 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.app.supervision.SupervisionManager;
|
import android.app.supervision.SupervisionManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.hardware.biometrics.BiometricAuthenticator;
|
import android.hardware.biometrics.BiometricAuthenticator;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@@ -44,6 +43,7 @@ import android.platform.test.flag.junit.CheckFlagsRule;
|
|||||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
import com.android.settingslib.RestrictedLockUtils;
|
||||||
@@ -53,22 +53,29 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ParentalControlsUtilsTest {
|
public class ParentalControlsUtilsTest {
|
||||||
@Rule public final CheckFlagsRule checkFlags = DeviceFlagsValueProvider.createCheckFlagsRule();
|
@Rule
|
||||||
|
public final CheckFlagsRule checkFlags = DeviceFlagsValueProvider.createCheckFlagsRule();
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mocks = MockitoJUnit.rule();
|
||||||
|
|
||||||
@Mock private Context mContext;
|
private Context mContext;
|
||||||
@Mock private DevicePolicyManager mDpm;
|
@Mock
|
||||||
@Mock private SupervisionManager mSm;
|
private DevicePolicyManager mDpm;
|
||||||
|
@Mock
|
||||||
|
private SupervisionManager mSm;
|
||||||
|
|
||||||
private ComponentName mSupervisionComponentName = new ComponentName("pkg", "cls");
|
private final ComponentName mSupervisionComponent = new ComponentName("pkg", "cls");
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||||
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
|
when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDpm);
|
||||||
|
when(mContext.getSystemService(SupervisionManager.class)).thenReturn(mSm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,7 +92,7 @@ public class ParentalControlsUtilsTest {
|
|||||||
.thenReturn(keyguardDisabledFlags);
|
.thenReturn(keyguardDisabledFlags);
|
||||||
|
|
||||||
return ParentalControlsUtils.parentConsentRequiredInternal(
|
return ParentalControlsUtils.parentConsentRequiredInternal(
|
||||||
mDpm, mSm, modality, new UserHandle(UserHandle.myUserId()));
|
mContext, modality, new UserHandle(UserHandle.myUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,11 +104,13 @@ public class ParentalControlsUtilsTest {
|
|||||||
boolean supervisionEnabled,
|
boolean supervisionEnabled,
|
||||||
@BiometricAuthenticator.Modality int modality,
|
@BiometricAuthenticator.Modality int modality,
|
||||||
int keyguardDisabledFlags) {
|
int keyguardDisabledFlags) {
|
||||||
when(mSm.isSupervisionEnabledForUser(anyInt())).thenReturn(supervisionEnabled);
|
|
||||||
when(mDpm.getKeyguardDisabledFeatures(eq(null))).thenReturn(keyguardDisabledFlags);
|
when(mDpm.getKeyguardDisabledFeatures(eq(null))).thenReturn(keyguardDisabledFlags);
|
||||||
|
when(mSm.isSupervisionEnabledForUser(anyInt())).thenReturn(supervisionEnabled);
|
||||||
|
when(mSm.getActiveSupervisionAppPackage()).thenReturn(
|
||||||
|
supervisionEnabled ? mSupervisionComponent.getPackageName() : null);
|
||||||
|
|
||||||
return ParentalControlsUtils.parentConsentRequiredInternal(
|
return ParentalControlsUtils.parentConsentRequiredInternal(
|
||||||
mDpm, mSm, modality, new UserHandle(UserHandle.myUserId()));
|
mContext, modality, new UserHandle(UserHandle.myUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -115,11 +124,11 @@ public class ParentalControlsUtilsTest {
|
|||||||
|
|
||||||
for (int i = 0; i < tests.length; i++) {
|
for (int i = 0; i < tests.length; i++) {
|
||||||
RestrictedLockUtils.EnforcedAdmin admin = getEnforcedAdminForCombination(
|
RestrictedLockUtils.EnforcedAdmin admin = getEnforcedAdminForCombination(
|
||||||
mSupervisionComponentName, tests[i][0] /* modality */,
|
mSupervisionComponent, tests[i][0] /* modality */,
|
||||||
tests[i][1] /* keyguardDisableFlags */);
|
tests[i][1] /* keyguardDisableFlags */);
|
||||||
assertNotNull(admin);
|
assertNotNull(admin);
|
||||||
assertEquals(UserManager.DISALLOW_BIOMETRIC, admin.enforcedRestriction);
|
assertEquals(UserManager.DISALLOW_BIOMETRIC, admin.enforcedRestriction);
|
||||||
assertEquals(mSupervisionComponentName, admin.component);
|
assertEquals(mSupervisionComponent, admin.component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -198,6 +198,7 @@ public class CombinedBiometricStatusUtilsTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void getDisabledAdmin_whenFingerprintDisabled_whenFaceDisabled_returnsRestrictions() {
|
public void getDisabledAdmin_whenFingerprintDisabled_whenFaceDisabled_returnsRestrictions() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||||
.thenReturn(KEYGUARD_DISABLE_FACE | KEYGUARD_DISABLE_FINGERPRINT);
|
.thenReturn(KEYGUARD_DISABLE_FACE | KEYGUARD_DISABLE_FINGERPRINT);
|
||||||
|
|
||||||
|
@@ -155,6 +155,7 @@ public class FaceStatusUtilsTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void getDisabledAdmin_whenFaceDisabled_returnsRestriction() {
|
public void getDisabledAdmin_whenFaceDisabled_returnsRestriction() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
|
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
|
||||||
|
|
||||||
@@ -172,7 +173,8 @@ public class FaceStatusUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_whenNotEnrolled_returnsSummaryNone() {
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_whenNotEnrolled_flagOff_returnsSummaryNone() {
|
||||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||||
|
|
||||||
assertThat(mFaceStatusUtils.getSummary())
|
assertThat(mFaceStatusUtils.getSummary())
|
||||||
@@ -181,6 +183,17 @@ public class FaceStatusUtilsTest {
|
|||||||
"security_settings_face_preference_summary_none"));
|
"security_settings_face_preference_summary_none"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_whenNotEnrolled_flagOn_returnsSummaryNone() {
|
||||||
|
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||||
|
|
||||||
|
assertThat(mFaceStatusUtils.getSummary())
|
||||||
|
.isEqualTo(ResourcesUtils.getResourcesString(
|
||||||
|
mApplicationContext,
|
||||||
|
"security_settings_face_preference_summary_none_new"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_whenEnrolled_returnsSummary() {
|
public void getSummary_whenEnrolled_returnsSummary() {
|
||||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
||||||
|
@@ -161,6 +161,7 @@ public class FingerprintStatusUtilsTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void getDisabledAdmin_whenFingerprintDisabled_returnsRestriction() {
|
public void getDisabledAdmin_whenFingerprintDisabled_returnsRestriction() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
|
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
|
||||||
|
|
||||||
@@ -179,7 +180,8 @@ public class FingerprintStatusUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_whenNotEnrolled_returnsSummaryNone() {
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_whenNotEnrolled_flagOff_returnsSummaryNone() {
|
||||||
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||||
|
|
||||||
assertThat(mFingerprintStatusUtils.getSummary())
|
assertThat(mFingerprintStatusUtils.getSummary())
|
||||||
@@ -188,6 +190,17 @@ public class FingerprintStatusUtilsTest {
|
|||||||
"security_settings_fingerprint_preference_summary_none"));
|
"security_settings_fingerprint_preference_summary_none"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_whenNotEnrolled_flagOn_returnsSummaryNone() {
|
||||||
|
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||||
|
|
||||||
|
assertThat(mFingerprintStatusUtils.getSummary())
|
||||||
|
.isEqualTo(ResourcesUtils.getResourcesString(
|
||||||
|
mApplicationContext,
|
||||||
|
"security_settings_fingerprint_preference_summary_none_new"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_whenEnrolled_returnsSummary() {
|
public void getSummary_whenEnrolled_returnsSummary() {
|
||||||
final int enrolledFingerprintsCount = 2;
|
final int enrolledFingerprintsCount = 2;
|
||||||
|
@@ -187,7 +187,7 @@ public class FaceSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||||
"security_settings_face_preference_title_new",
|
"security_settings_face_preference_title_new",
|
||||||
"security_settings_face_preference_summary_none");
|
"security_settings_face_preference_summary_none_new");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -195,6 +195,7 @@ public class FaceSafetySourceTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void setSafetySourceData_withFaceNotEnrolled_whenSupervisionIsOn_setsData() {
|
public void setSafetySourceData_withFaceNotEnrolled_whenSupervisionIsOn_setsData() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||||
@@ -205,7 +206,7 @@ public class FaceSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||||
"security_settings_face_preference_title_new",
|
"security_settings_face_preference_title_new",
|
||||||
"security_settings_face_preference_summary_none");
|
"security_settings_face_preference_summary_none_new");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -220,7 +221,7 @@ public class FaceSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceEnabledDataSetWithSingularSummary(
|
assertSafetySourceEnabledDataSetWithSingularSummary(
|
||||||
"security_settings_face_preference_title_new",
|
"security_settings_face_preference_title_new",
|
||||||
"security_settings_face_preference_summary_none",
|
"security_settings_face_preference_summary_none_new",
|
||||||
FaceEnrollIntroductionInternal.class.getName());
|
FaceEnrollIntroductionInternal.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +249,7 @@ public class FaceSafetySourceTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void setSafetySourceData_withFaceEnrolled_whenSupervisionIsOn_setsData() {
|
public void setSafetySourceData_withFaceEnrolled_whenSupervisionIsOn_setsData() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
||||||
|
@@ -203,7 +203,7 @@ public class FingerprintSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||||
"security_settings_fingerprint",
|
"security_settings_fingerprint",
|
||||||
"security_settings_fingerprint_preference_summary_none");
|
"security_settings_fingerprint_preference_summary_none_new");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -211,6 +211,7 @@ public class FingerprintSafetySourceTest {
|
|||||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||||
public void setSafetySourceData_withFingerprintNotEnrolled_whenSupervisionIsOn_setsData() {
|
public void setSafetySourceData_withFingerprintNotEnrolled_whenSupervisionIsOn_setsData() {
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||||
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
|
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
|
||||||
@@ -222,7 +223,7 @@ public class FingerprintSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||||
"security_settings_fingerprint",
|
"security_settings_fingerprint",
|
||||||
"security_settings_fingerprint_preference_summary_none");
|
"security_settings_fingerprint_preference_summary_none_new");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -238,7 +239,7 @@ public class FingerprintSafetySourceTest {
|
|||||||
|
|
||||||
assertSafetySourceEnabledDataSetWithSingularSummary(
|
assertSafetySourceEnabledDataSetWithSingularSummary(
|
||||||
"security_settings_fingerprint",
|
"security_settings_fingerprint",
|
||||||
"security_settings_fingerprint_preference_summary_none",
|
"security_settings_fingerprint_preference_summary_none_new",
|
||||||
FingerprintSettings.class.getName());
|
FingerprintSettings.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +273,7 @@ public class FingerprintSafetySourceTest {
|
|||||||
public void setSafetySourceData_withFingerprintsEnrolled_whenSupervisionIsOn_setsData() {
|
public void setSafetySourceData_withFingerprintsEnrolled_whenSupervisionIsOn_setsData() {
|
||||||
int enrolledFingerprintsCount = 2;
|
int enrolledFingerprintsCount = 2;
|
||||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||||
|
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||||
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
|
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
|
||||||
|
1
tests/unit/src/com/android/settings/safetycenter/OWNERS
Normal file
1
tests/unit/src/com/android/settings/safetycenter/OWNERS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
include /src/com/android/settings/safetycenter/OWNERS
|
@@ -32,10 +32,13 @@ import android.content.Intent;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.os.storage.StorageManager;
|
import android.os.storage.StorageManager;
|
||||||
|
import android.platform.test.annotations.DisableFlags;
|
||||||
|
import android.platform.test.annotations.EnableFlags;
|
||||||
import android.platform.test.annotations.RequiresFlagsDisabled;
|
import android.platform.test.annotations.RequiresFlagsDisabled;
|
||||||
import android.platform.test.annotations.RequiresFlagsEnabled;
|
import android.platform.test.annotations.RequiresFlagsEnabled;
|
||||||
import android.platform.test.flag.junit.CheckFlagsRule;
|
import android.platform.test.flag.junit.CheckFlagsRule;
|
||||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||||
|
import android.platform.test.flag.junit.SetFlagsRule;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@@ -64,6 +67,8 @@ public class ScreenLockPreferenceDetailsUtilsTest {
|
|||||||
private static final int SOURCE_METRICS_CATEGORY = 10;
|
private static final int SOURCE_METRICS_CATEGORY = 10;
|
||||||
private static final int USER_ID = 11;
|
private static final int USER_ID = 11;
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||||
@Rule
|
@Rule
|
||||||
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
||||||
@Mock
|
@Mock
|
||||||
@@ -118,7 +123,8 @@ public class ScreenLockPreferenceDetailsUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_unsecureAndDisabledPattern_shouldReturnUnlockModeOff() {
|
@DisableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_unsecureAndDisabledPattern_flagOff_shouldReturnUnlockModeOff() {
|
||||||
final String summary = prepareString("unlock_set_unlock_mode_off", "unlockModeOff");
|
final String summary = prepareString("unlock_set_unlock_mode_off", "unlockModeOff");
|
||||||
|
|
||||||
when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false);
|
when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false);
|
||||||
@@ -127,6 +133,17 @@ public class ScreenLockPreferenceDetailsUtilsTest {
|
|||||||
assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary);
|
assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnableFlags(com.android.settings.flags.Flags.FLAG_BIOMETRICS_ONBOARDING_EDUCATION)
|
||||||
|
public void getSummary_unsecureAndDisabledPattern_flagOn_shouldReturnUnlockModeOff() {
|
||||||
|
final String summary = prepareString("unlock_set_unlock_mode_off_new", "unlockModeOff");
|
||||||
|
|
||||||
|
when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false);
|
||||||
|
when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true);
|
||||||
|
|
||||||
|
assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_unsecurePattern_shouldReturnUnlockModeNone() {
|
public void getSummary_unsecurePattern_shouldReturnUnlockModeNone() {
|
||||||
final String summary =
|
final String summary =
|
||||||
|
Reference in New Issue
Block a user