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_settingslib_flags",
|
||||
"android.app.flags-aconfig",
|
||||
"android.app.supervision.flags-aconfig",
|
||||
"android.provider.flags-aconfig",
|
||||
"android.security.flags-aconfig",
|
||||
"android.view.contentprotection.flags-aconfig",
|
||||
|
@@ -2817,6 +2817,15 @@
|
||||
</intent-filter>
|
||||
</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"
|
||||
android:enabled="false"
|
||||
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_marginTop="8dp"
|
||||
android:visibility="gone"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/input_setting_keys_custom_seekbar_layout"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_vertical"
|
||||
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"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingEnd="36dp"
|
||||
style="@android:style/Widget.Material.SeekBar"
|
||||
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_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="8dp" />
|
||||
<ImageView
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"/>
|
||||
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>
|
||||
</RadioGroup>
|
||||
|
@@ -94,8 +94,5 @@
|
||||
<!-- Volume seekbar colors -->
|
||||
<color name="seekbar_thumb_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>
|
||||
|
||||
|
@@ -1059,6 +1059,20 @@
|
||||
<item>either_charging_or_docked</item>
|
||||
</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">
|
||||
<item>@string/zen_mode_from_anyone</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_modes_foreground">@color/homepage_pink_fg</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_background">@color/homepage_pink_bg</color>
|
||||
<color name="homepage_hub_mode_foreground">@color/homepage_orange_fg</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_background">@color/homepage_orange_bg</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_progress_tint_color">@android:color/system_accent1_800</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>
|
||||
|
@@ -810,13 +810,23 @@
|
||||
<!-- Allowed packages to show the confirmation dialog for a system locale suggestion -->
|
||||
<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">
|
||||
<item>@layout/accessibility_text_reading_preview_app_grid</item>
|
||||
<item>@layout/screen_zoom_preview_1</item>
|
||||
<item>@layout/accessibility_text_reading_preview_mail_content</item>
|
||||
</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 -->
|
||||
<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] -->
|
||||
<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]-->
|
||||
<string name="qr_code_content_description">QR code</string>
|
||||
<!-- Previous button for preview pager. [CHAR LIMIT=NONE] -->
|
||||
@@ -833,6 +839,8 @@
|
||||
<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] -->
|
||||
<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] -->
|
||||
<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] -->
|
||||
@@ -1006,6 +1014,8 @@
|
||||
}</string>
|
||||
<!-- message shown in summary field when no fingerprints are registered -->
|
||||
<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] -->
|
||||
<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] -->
|
||||
@@ -1771,6 +1781,8 @@
|
||||
|
||||
<!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
|
||||
<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] -->
|
||||
<string name="unlock_set_unlock_mode_none">Swipe</string>
|
||||
<!-- Summary for "Configure lockscreen" when security pattern is enabled [CHAR LIMIT=45] -->
|
||||
@@ -3655,6 +3667,21 @@
|
||||
<string name="communal_settings_title">Communal</string>
|
||||
<!-- Summary of the communal settings under Settings > Communal [CHAR LIMIT=50] -->
|
||||
<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 screen title-->
|
||||
@@ -3897,6 +3924,18 @@
|
||||
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
||||
<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-->
|
||||
<!-- Label for ethernet tether checkbox [CHAR LIMIT=NONE]-->
|
||||
<string name="ethernet_tether_checkbox_text">Ethernet tethering</string>
|
||||
@@ -5691,6 +5730,9 @@
|
||||
<string name="accessibility_autoclick_longer_desc">Longer</string>
|
||||
<!-- Description for the seekbar that adjust auto click time. [CHAR_LIMIT=NONE] -->
|
||||
<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] -->
|
||||
<!-- TODO(b/394683600): Update string to translatable once approved by UXW. -->
|
||||
<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] -->
|
||||
<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] -->
|
||||
<!-- 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>
|
||||
</resources>
|
||||
|
@@ -30,6 +30,11 @@
|
||||
settings:searchable="false"
|
||||
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
|
||||
android:key="autoclick_shortcut_preference"
|
||||
android:title="@string/accessibility_autoclick_shortcut_title"
|
||||
|
@@ -88,6 +88,12 @@
|
||||
android:persistent="false"
|
||||
android:title="@string/accessibility_text_reading_options_title"
|
||||
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
|
||||
|
@@ -24,4 +24,36 @@
|
||||
android:selectable="false"
|
||||
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>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
android:order="10"
|
||||
settings:controller="com.android.settings.inputmethod.MousePointerAccelerationPreferenceController" />
|
||||
|
||||
<com.android.settings.widget.SeekBarPreference
|
||||
<com.android.settings.widget.LabeledSeekBarPreference
|
||||
android:key="pointer_speed"
|
||||
android:title="@string/pointer_speed"
|
||||
android:order="20"
|
||||
@@ -50,12 +50,6 @@
|
||||
android:summary="@string/accessibility_pointer_and_touchpad_summary"
|
||||
settings:searchable="true"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="pointer_category"
|
||||
android:persistent="false"
|
||||
android:order="51"
|
||||
android:title="@string/mouse_scrolling_category_title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="mouse_reverse_vertical_scrolling"
|
||||
android:order="52"
|
||||
@@ -69,13 +63,11 @@
|
||||
android:title="@string/mouse_scrolling_acceleration"
|
||||
settings:controller="com.android.settings.inputmethod.MouseScrollingAccelerationPreferenceController" />
|
||||
|
||||
<com.android.settings.widget.SeekBarPreference
|
||||
<com.android.settings.widget.LabeledSeekBarPreference
|
||||
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>
|
||||
|
@@ -61,7 +61,7 @@
|
||||
settings:controller="com.android.settings.inputmethod.TouchpadAccelerationPreferenceController"
|
||||
android:order="38"/>
|
||||
|
||||
<com.android.settings.widget.SeekBarPreference
|
||||
<com.android.settings.widget.LabeledSeekBarPreference
|
||||
android:key="touchpad_pointer_speed"
|
||||
android:title="@string/trackpad_pointer_speed"
|
||||
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 =
|
||||
origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
||||
final int[] previewSamples = getPreviewSampleLayouts(mContext);
|
||||
final int[] previewContentDescriptions = getPreviewSampleContentDescriptions(mContext);
|
||||
final PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(mContext, isLayoutRtl,
|
||||
previewSamples, createConfig(origConfig));
|
||||
mPreviewPreference.setPreviewAdapter(pagerAdapter);
|
||||
mPreviewPreference.setCurrentItem(
|
||||
isLayoutRtl ? previewSamples.length - 1 : FRAME_INITIAL_INDEX);
|
||||
mPreviewPreference.setContentDescription(previewContentDescriptions);
|
||||
|
||||
final int initialPagerIndex =
|
||||
mLastFontProgress * mDisplaySizeData.getValues().size() + mLastDisplayProgress;
|
||||
@@ -188,6 +190,20 @@ class TextReadingPreviewController extends BasePreferenceController implements
|
||||
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() {
|
||||
final int displayDataSize = mDisplaySizeData.getValues().size();
|
||||
final int fontSizeProgress = mFontSizePreference.getProgress();
|
||||
|
@@ -43,28 +43,11 @@ public class TextReadingPreviewPreference extends Preference {
|
||||
private int mCurrentItem;
|
||||
private int mLastLayerIndex;
|
||||
private PreviewPagerAdapter mPreviewAdapter;
|
||||
private int[] mContentDescriptions;
|
||||
|
||||
private int mLayoutMinHorizontalPadding = 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) {
|
||||
super(context);
|
||||
init();
|
||||
@@ -95,7 +78,23 @@ public class TextReadingPreviewPreference extends Preference {
|
||||
adjustPaddings(previewLayout, backgroundView);
|
||||
|
||||
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 =
|
||||
(DotsPageIndicator) holder.findViewById(R.id.page_indicator);
|
||||
updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
|
||||
@@ -122,6 +121,10 @@ public class TextReadingPreviewPreference extends Preference {
|
||||
viewPager.setCurrentItem(getCurrentItem() + 1));
|
||||
nextButton.setContentDescription(getContext().getString(
|
||||
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
|
||||
@@ -170,6 +173,10 @@ public class TextReadingPreviewPreference extends Preference {
|
||||
);
|
||||
}
|
||||
|
||||
void setContentDescription(int[] stringIds) {
|
||||
mContentDescriptions = stringIds;
|
||||
}
|
||||
|
||||
void setPreviewAdapter(PreviewPagerAdapter previewAdapter) {
|
||||
if (previewAdapter != mPreviewAdapter) {
|
||||
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 {
|
||||
throw UnsupportedOperationException("query operation not supported currently.")
|
||||
throw UnsupportedOperationException("delete operation not supported currently.")
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
|
@@ -31,6 +31,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
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,
|
||||
@@ -59,12 +60,7 @@ public class ParentalControlsUtils {
|
||||
UserManager.DISALLOW_BIOMETRIC, userHandle);
|
||||
}
|
||||
|
||||
final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
|
||||
final SupervisionManager sm =
|
||||
android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()
|
||||
? context.getSystemService(SupervisionManager.class)
|
||||
: null;
|
||||
return parentConsentRequiredInternal(dpm, sm, modality, userHandle);
|
||||
return parentConsentRequiredInternal(context, modality, userHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,18 +70,22 @@ public class ParentalControlsUtils {
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
static RestrictedLockUtils.EnforcedAdmin parentConsentRequiredInternal(
|
||||
@NonNull DevicePolicyManager dpm,
|
||||
@Nullable SupervisionManager sm,
|
||||
@NonNull Context context,
|
||||
@BiometricAuthenticator.Modality int modality,
|
||||
@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(
|
||||
dpm, sm, modality, userHandle)) {
|
||||
return null;
|
||||
}
|
||||
if (android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()) {
|
||||
// Supervision doesn't necessarily have have an admin component.
|
||||
return new RestrictedLockUtils.EnforcedAdmin(
|
||||
/* component= */ null, UserManager.DISALLOW_BIOMETRIC, userHandle);
|
||||
return SupervisionRestrictionsHelper.createEnforcedAdmin(
|
||||
context, UserManager.DISALLOW_BIOMETRIC, userHandle);
|
||||
} else {
|
||||
final ComponentName cn =
|
||||
ParentalControlsUtilsInternal.getSupervisionComponentName(dpm, userHandle);
|
||||
|
@@ -70,6 +70,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "FaceSettings";
|
||||
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_BIOMETRICS_SUCCESSFULLY_AUTHENTICATED =
|
||||
"biometrics_successfully_authenticated";
|
||||
@@ -163,6 +164,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putByteArray(KEY_TOKEN, mToken);
|
||||
outState.putBoolean(KEY_CONFIRMING_PASSWORD, mConfirmingPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -273,6 +275,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mToken = savedInstanceState.getByteArray(KEY_TOKEN);
|
||||
mConfirmingPassword = savedInstanceState.getBoolean(KEY_CONFIRMING_PASSWORD);
|
||||
}
|
||||
|
||||
if (Flags.biometricsOnboardingEducation()) {
|
||||
|
@@ -98,11 +98,14 @@ public class FaceStatusUtils {
|
||||
return mContext.getString(
|
||||
com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
|
||||
} 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()
|
||||
.getString(
|
||||
hasEnrolled()
|
||||
? 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);
|
||||
} else {
|
||||
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.
|
||||
*/
|
||||
public static boolean isAvailable(Context context) {
|
||||
if (com.android.systemui.Flags.glanceableHubV2()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Utils.canCurrentUserDream(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (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);
|
||||
return context.getResources().getBoolean(R.bool.config_show_communal_settings);
|
||||
}
|
||||
}
|
||||
|
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.BluetoothLeBroadcastReceiveState;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -87,6 +92,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
@Nullable private final LocalBluetoothProfileManager mProfileManager;
|
||||
@Nullable private final LocalBluetoothLeBroadcast mBroadcast;
|
||||
@Nullable private final LocalBluetoothLeBroadcastAssistant mAssistant;
|
||||
@Nullable private final ContentResolver mContentResolver;
|
||||
private final Executor mExecutor;
|
||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
@Nullable private PreferenceGroup mPreferenceGroup;
|
||||
@@ -187,6 +193,17 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
@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) {
|
||||
super(context, KEY);
|
||||
mBtManager = Utils.getLocalBtManager(mContext);
|
||||
@@ -198,6 +215,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
mProfileManager == null
|
||||
? null
|
||||
: mProfileManager.getLeAudioBroadcastAssistantProfile();
|
||||
mContentResolver = context.getContentResolver();
|
||||
mExecutor = Executors.newSingleThreadExecutor();
|
||||
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
|
||||
}
|
||||
@@ -217,6 +235,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
if (mEventManager == null
|
||||
|| mAssistant == null
|
||||
|| mDialogHandler == null
|
||||
|| mContentResolver == null
|
||||
|| mBluetoothDeviceUpdater == null) {
|
||||
Log.d(TAG, "Skip onStart(), profile is not ready.");
|
||||
return;
|
||||
@@ -225,6 +244,10 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
mEventManager.registerCallback(this);
|
||||
mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
|
||||
mDialogHandler.registerCallbacks(mExecutor);
|
||||
mContentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(BluetoothUtils.getPrimaryGroupIdUriForBroadcast()),
|
||||
false,
|
||||
mSettingsObserver);
|
||||
mBluetoothDeviceUpdater.registerCallback();
|
||||
mBluetoothDeviceUpdater.refreshPreference();
|
||||
mIsAudioModeOngoingCall.set(isAudioModeOngoingCall(mContext));
|
||||
@@ -245,6 +268,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
if (mEventManager == null
|
||||
|| mAssistant == null
|
||||
|| mDialogHandler == null
|
||||
|| mContentResolver == null
|
||||
|| mBluetoothDeviceUpdater == null) {
|
||||
Log.d(TAG, "Skip onStop(), profile is not ready.");
|
||||
return;
|
||||
@@ -253,6 +277,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
||||
mEventManager.unregisterCallback(this);
|
||||
mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
|
||||
mDialogHandler.unregisterCallbacks();
|
||||
mContentResolver.unregisterContentObserver(mSettingsObserver);
|
||||
mBluetoothDeviceUpdater.unregisterCallback();
|
||||
});
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
@@ -88,8 +89,10 @@ public class AudioStreamHeaderController extends BasePreferenceController
|
||||
var localSourceState = getLocalSourceState(state);
|
||||
if (localSourceState == STREAMING) {
|
||||
updateSummary();
|
||||
if (!Flags.audioStreamMediaServiceByReceiveState()) {
|
||||
mAudioStreamsHelper.startMediaService(
|
||||
mContext, mBroadcastId, mBroadcastName);
|
||||
}
|
||||
} else if (mHysteresisModeFixAvailable && localSourceState == PAUSED) {
|
||||
// if source paused, only update the summary
|
||||
updateSummary();
|
||||
|
@@ -16,9 +16,13 @@
|
||||
|
||||
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.STREAMING;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
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.LocalBluetoothLeBroadcastSourceState;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.PrivateBroadcastReceiveData;
|
||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AudioStreamMediaService extends Service {
|
||||
@@ -103,7 +110,7 @@ public class AudioStreamMediaService extends Service {
|
||||
private final PlaybackState.Builder mPlayStateHysteresisBuilder =
|
||||
new PlaybackState.Builder()
|
||||
.setState(
|
||||
PlaybackState.STATE_STOPPED,
|
||||
PlaybackState.STATE_PAUSED,
|
||||
STATIC_PLAYBACK_POSITION,
|
||||
ZERO_PLAYBACK_SPEED)
|
||||
.addCustomAction(
|
||||
@@ -122,7 +129,9 @@ public class AudioStreamMediaService extends Service {
|
||||
private int mLatestPositiveVolume = 25;
|
||||
private boolean mHysteresisModeFixAvailable;
|
||||
private int mBroadcastId;
|
||||
@Nullable private Map<BluetoothDevice, LocalBluetoothLeBroadcastSourceState> mStateByDevice;
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
Map<BluetoothDevice, LocalBluetoothLeBroadcastSourceState> mStateByDevice;
|
||||
@Nullable private LocalBluetoothManager mLocalBtManager;
|
||||
@Nullable private AudioStreamsHelper mAudioStreamsHelper;
|
||||
@Nullable private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
|
||||
@@ -236,6 +245,19 @@ public class AudioStreamMediaService extends Service {
|
||||
stopSelf();
|
||||
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(() -> {
|
||||
mBroadcastId = intent.getIntExtra(BROADCAST_ID, -1);
|
||||
if (mBroadcastId == -1) {
|
||||
@@ -258,6 +280,78 @@ public class AudioStreamMediaService extends Service {
|
||||
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) {
|
||||
if (mLocalSession != null) {
|
||||
return mLocalSession.getSessionToken();
|
||||
@@ -288,7 +382,8 @@ public class AudioStreamMediaService extends Service {
|
||||
}
|
||||
|
||||
private String getDeviceName() {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty() || mLocalBtManager == null) {
|
||||
List<BluetoothDevice> validDevices = getDeviceInValidState();
|
||||
if (validDevices.isEmpty() || mLocalBtManager == null) {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
@@ -297,8 +392,7 @@ public class AudioStreamMediaService extends Service {
|
||||
return DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
CachedBluetoothDevice device = manager.findDevice(
|
||||
mStateByDevice.keySet().iterator().next());
|
||||
CachedBluetoothDevice device = manager.findDevice(validDevices.getFirst());
|
||||
return device != null ? device.getName() : DEFAULT_DEVICE_NAME;
|
||||
}
|
||||
|
||||
@@ -320,6 +414,47 @@ public class AudioStreamMediaService extends Service {
|
||||
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
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
@@ -342,6 +477,9 @@ public class AudioStreamMediaService extends Service {
|
||||
@Override
|
||||
public void onReceiveStateChanged(
|
||||
BluetoothDevice sink, int sourceId, BluetoothLeBroadcastReceiveState state) {
|
||||
if (Flags.audioStreamMediaServiceByReceiveState()) {
|
||||
return;
|
||||
}
|
||||
super.onReceiveStateChanged(sink, sourceId, state);
|
||||
if (!mHysteresisModeFixAvailable || mStateByDevice == null
|
||||
|| !mStateByDevice.containsKey(sink)) {
|
||||
@@ -383,14 +521,13 @@ public class AudioStreamMediaService extends Service {
|
||||
@Override
|
||||
public void onDeviceVolumeChanged(
|
||||
@NonNull BluetoothDevice device, @IntRange(from = -255, to = 255) int volume) {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
if (!getDeviceInValidState().contains(device)) {
|
||||
Log.w(TAG, "onDeviceVolumeChanged() : device not in valid state list");
|
||||
return;
|
||||
}
|
||||
Log.d(
|
||||
TAG,
|
||||
"onDeviceVolumeChanged() bluetoothDevice : " + device + " volume: " + volume);
|
||||
if (mStateByDevice.containsKey(device)) {
|
||||
if (volume == 0) {
|
||||
mIsMuted = true;
|
||||
} else {
|
||||
@@ -402,7 +539,6 @@ public class AudioStreamMediaService extends Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class BtCallback implements BluetoothCallback {
|
||||
@Override
|
||||
@@ -426,7 +562,7 @@ public class AudioStreamMediaService extends Service {
|
||||
&& mStateByDevice != null) {
|
||||
mStateByDevice.remove(cachedDevice.getDevice());
|
||||
}
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
if (getDeviceInValidState().isEmpty()) {
|
||||
Log.d(TAG, "onProfileConnectionStateChanged() : stopSelf");
|
||||
stopSelf();
|
||||
}
|
||||
@@ -484,11 +620,7 @@ public class AudioStreamMediaService extends Service {
|
||||
}
|
||||
|
||||
private void handleOnPlay() {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
return;
|
||||
}
|
||||
mStateByDevice.keySet().forEach(device -> {
|
||||
getDeviceInValidState().forEach(device -> {
|
||||
Log.d(TAG, "onPlay() setting volume for device : " + device + " volume: "
|
||||
+ mLatestPositiveVolume);
|
||||
setDeviceVolume(device, mLatestPositiveVolume);
|
||||
@@ -496,11 +628,7 @@ public class AudioStreamMediaService extends Service {
|
||||
}
|
||||
|
||||
private void handleOnPause() {
|
||||
if (mStateByDevice == null || mStateByDevice.isEmpty()) {
|
||||
Log.w(TAG, "active device or device has source is null!");
|
||||
return;
|
||||
}
|
||||
mStateByDevice.keySet().forEach(device -> {
|
||||
getDeviceInValidState().forEach(device -> {
|
||||
Log.d(TAG, "onPause() setting volume for device : " + device + " volume: " + 0);
|
||||
setDeviceVolume(device, /* volume= */ 0);
|
||||
});
|
||||
|
@@ -26,6 +26,7 @@ import androidx.preference.Preference;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
|
||||
class SourceAddedState extends AudioStreamStateHandler {
|
||||
@VisibleForTesting
|
||||
@@ -55,10 +56,12 @@ class SourceAddedState extends AudioStreamStateHandler {
|
||||
if (cached != null) {
|
||||
mAudioStreamsRepository.saveMetadata(context, cached);
|
||||
}
|
||||
if (!Flags.audioStreamMediaServiceByReceiveState()) {
|
||||
helper.startMediaService(
|
||||
context,
|
||||
preference.getAudioStreamBroadcastId(),
|
||||
String.valueOf(preference.getTitle()));
|
||||
}
|
||||
mMetricsFeatureProvider.action(
|
||||
preference.getContext(),
|
||||
SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
|
||||
|
@@ -81,9 +81,11 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
||||
implements SeekBar.OnSeekBarChangeListener {
|
||||
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_SEEKBAR_DELAY_MS = 100;
|
||||
private final DisplaySizeData mDisplaySizeData;
|
||||
private int mLastDisplayProgress;
|
||||
private long mLastCommitTime;
|
||||
private boolean mSeekByTouch;
|
||||
ExternalDisplaySizePreferenceStateHandler(DisplaySizeData displaySizeData) {
|
||||
mDisplaySizeData = displaySizeData;
|
||||
}
|
||||
@@ -99,8 +101,7 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
||||
mLastCommitTime = SystemClock.elapsedRealtime();
|
||||
}
|
||||
|
||||
private void postCommitDelayed() {
|
||||
var commitDelayMs = CHANGE_BY_BUTTON_DELAY_MS;
|
||||
private void postCommitDelayed(long commitDelayMs) {
|
||||
if (SystemClock.elapsedRealtime() - mLastCommitTime < MIN_COMMIT_INTERVAL_MS) {
|
||||
commitDelayMs += MIN_COMMIT_INTERVAL_MS;
|
||||
}
|
||||
@@ -112,13 +113,18 @@ public class ExternalDisplaySizePreference extends AccessibilitySeekBarPreferenc
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(@NonNull SeekBar seekBar, int i, boolean b) {
|
||||
postCommitDelayed();
|
||||
if (!mSeekByTouch) postCommitDelayed(CHANGE_BY_BUTTON_DELAY_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(@NonNull SeekBar seekBar) {}
|
||||
public void onStartTrackingTouch(@NonNull SeekBar seekBar) {
|
||||
mSeekByTouch = true;
|
||||
}
|
||||
|
||||
@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. */
|
||||
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);
|
||||
TextView customValueTextView = accessibilityKeyDialog.findViewById(
|
||||
R.id.input_setting_keys_value_custom_value);
|
||||
View seekbarView = accessibilityKeyDialog.findViewById(
|
||||
R.id.input_setting_keys_custom_seekbar_layout);
|
||||
SeekBar customProgressBar = accessibilityKeyDialog.findViewById(
|
||||
R.id.input_setting_keys_value_custom_slider);
|
||||
TextView titleTextView = accessibilityKeyDialog.findViewById(
|
||||
@@ -147,7 +149,7 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
||||
customValueTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
customValueTextView.setText(
|
||||
progressToThresholdInSecond(customProgressBar.getProgress()));
|
||||
customProgressBar.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
seekbarView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
buttonView.setChecked(isChecked);
|
||||
});
|
||||
cannedValueRadioGroup.setOnCheckedChangeListener(
|
||||
@@ -174,14 +176,14 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
||||
// setting
|
||||
initStateBasedOnThreshold(cannedValueRadioGroup, customRadioButton,
|
||||
customValueTextView,
|
||||
customProgressBar);
|
||||
customProgressBar, seekbarView);
|
||||
} else if (customRadioButton.isChecked()) {
|
||||
cannedValueRadioGroup.clearCheck();
|
||||
customRadioButton.setChecked(true);
|
||||
customValueTextView.setVisibility(View.VISIBLE);
|
||||
customValueTextView.setText(
|
||||
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,
|
||||
RadioButton customRadioButton, TextView customValueTextView,
|
||||
SeekBar customProgressBar) {
|
||||
SeekBar customProgressBar, View seekbarView) {
|
||||
int inputSettingKeysThreshold = getInputSettingKeysValue();
|
||||
switch (inputSettingKeysThreshold) {
|
||||
case 600 -> cannedValueRadioGroup.check(R.id.input_setting_keys_value_600);
|
||||
@@ -213,5 +215,6 @@ public abstract class KeyboardAccessibilityKeysDialogFragment extends DialogFrag
|
||||
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.net.ConnectivityManager
|
||||
import android.net.ConnectivityManager.NetworkCallback
|
||||
import android.net.EthernetManager
|
||||
import android.net.EthernetManager.STATE_ABSENT
|
||||
import android.net.EthernetNetworkManagementException
|
||||
import android.net.EthernetNetworkUpdateRequest
|
||||
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.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
|
||||
class EthernetInterface(private val context: Context, private val id: String) :
|
||||
EthernetManager.InterfaceStateListener {
|
||||
interface EthernetInterfaceStateListener {
|
||||
fun interfaceUpdated()
|
||||
}
|
||||
|
||||
private val ethernetManager: EthernetManager? =
|
||||
context.getSystemService(EthernetManager::class.java)
|
||||
private val connectivityManager: ConnectivityManager? =
|
||||
context.getSystemService(ConnectivityManager::class.java)
|
||||
private val executor = ContextCompat.getMainExecutor(context)
|
||||
private val interfaceListeners = mutableListOf<EthernetInterfaceStateListener>()
|
||||
|
||||
private val TAG = "EthernetInterface"
|
||||
|
||||
private val networkRequest: NetworkRequest =
|
||||
NetworkRequest.Builder()
|
||||
.clearCapabilities()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.build()
|
||||
|
||||
private var interfaceState = STATE_ABSENT
|
||||
private var ipConfiguration = IpConfiguration()
|
||||
private var linkProperties = LinkProperties()
|
||||
|
||||
fun getInterfaceState() = interfaceState
|
||||
|
||||
fun getId() = id
|
||||
|
||||
fun getConfiguration(): IpConfiguration {
|
||||
return ipConfiguration
|
||||
fun getConfiguration() = 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) {
|
||||
@@ -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?) {
|
||||
if (id == this.id) {
|
||||
ipConfiguration = cfg ?: IpConfiguration()
|
||||
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.net.EthernetManager
|
||||
import android.net.IpConfiguration
|
||||
import android.net.LinkProperties
|
||||
import android.net.StaticIpConfiguration
|
||||
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.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
@@ -30,13 +37,25 @@ class EthernetInterfaceDetailsController(
|
||||
context: Context,
|
||||
private val fragment: PreferenceFragmentCompat,
|
||||
private val preferenceId: String,
|
||||
) : AbstractPreferenceController(context) {
|
||||
private val lifecycle: Lifecycle,
|
||||
) :
|
||||
AbstractPreferenceController(context),
|
||||
EthernetInterface.EthernetInterfaceStateListener,
|
||||
LifecycleEventObserver {
|
||||
private val KEY_HEADER = "ethernet_details"
|
||||
|
||||
private val ethernetManager = context.getSystemService(EthernetManager::class.java)
|
||||
private val ethernetInterface =
|
||||
EthernetTrackerImpl.getInstance(context).getInterface(preferenceId)
|
||||
|
||||
private lateinit var entityHeaderController: EntityHeaderController
|
||||
|
||||
private var ipAddressPref: Preference? = null
|
||||
|
||||
init {
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
override fun isAvailable(): Boolean {
|
||||
return true
|
||||
}
|
||||
@@ -45,10 +64,24 @@ class EthernetInterfaceDetailsController(
|
||||
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) {
|
||||
val headerPref: LayoutPreference? = screen.findPreference(KEY_HEADER)
|
||||
|
||||
val mEntityHeaderController =
|
||||
entityHeaderController =
|
||||
EntityHeaderController.newInstance(
|
||||
fragment.getActivity(),
|
||||
fragment,
|
||||
@@ -59,7 +92,8 @@ class EthernetInterfaceDetailsController(
|
||||
|
||||
iconView?.setScaleType(ImageView.ScaleType.CENTER_INSIDE)
|
||||
|
||||
mEntityHeaderController
|
||||
if (entityHeaderController != null) {
|
||||
entityHeaderController
|
||||
.setLabel("Ethernet")
|
||||
.setSummary(
|
||||
if (ethernetInterface?.getInterfaceState() == EthernetManager.STATE_LINK_UP) {
|
||||
@@ -72,4 +106,35 @@ class EthernetInterfaceDetailsController(
|
||||
.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(
|
||||
context: Context
|
||||
): 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_INSTALL_UNKNOWN_SOURCES
|
||||
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.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION
|
||||
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.SettingsAlertDialogContent
|
||||
import com.android.settingslib.wifi.WifiUtils.Companion.DIALOG_WINDOW_TYPE
|
||||
import android.security.advancedprotection.AdvancedProtectionManager
|
||||
|
||||
class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
SettingsAlertDialogContent(
|
||||
confirmButton = AlertDialogButton(getString(R.string.okay)) { finish() },
|
||||
confirmButton = AlertDialogButton(getString(R.string.okay)) {
|
||||
finish()
|
||||
logDialogShown(learnMoreClicked = false)
|
||||
},
|
||||
dismissButton = getSupportButtonIfExists(),
|
||||
title = getString(R.string.disabled_by_advanced_protection_title),
|
||||
icon = {
|
||||
@@ -56,8 +61,8 @@ class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
||||
}
|
||||
|
||||
private fun getDialogMessage(): String {
|
||||
val featureId = intent.getIntExtra(EXTRA_SUPPORT_DIALOG_FEATURE, -1)
|
||||
val type = intent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_UNKNOWN)
|
||||
val featureId = getIntentFeatureId()
|
||||
val type = getIntentDialogueType()
|
||||
val messageId = when (type) {
|
||||
SUPPORT_DIALOG_TYPE_DISABLED_SETTING -> {
|
||||
if (featureIdsWithSettingOn.contains(featureId)) {
|
||||
@@ -93,6 +98,7 @@ class ActionDisabledByAdvancedProtectionDialog : SpaDialogWindowTypeActivity() {
|
||||
) {
|
||||
startActivity(helpIntent)
|
||||
finish()
|
||||
logDialogShown(learnMoreClicked = true)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
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
|
||||
}
|
||||
|
||||
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)) {
|
||||
intent.getIntExtra(DIALOG_WINDOW_TYPE, WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW)
|
||||
} 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 {
|
||||
const val TAG = "AdvancedProtectionDlg"
|
||||
val defaultMessageId = R.string.disabled_by_advanced_protection_action_message
|
||||
|
@@ -178,7 +178,9 @@ public class ScreenLockPreferenceDetailsUtils {
|
||||
if (!mLockPatternUtils.isSecure(userId)) {
|
||||
if (userId == mProfileChallengeUserId
|
||||
|| 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 {
|
||||
return R.string.unlock_set_unlock_mode_none;
|
||||
}
|
||||
|
@@ -16,9 +16,12 @@
|
||||
|
||||
package com.android.settings.sound
|
||||
|
||||
import android.app.settings.SettingsEnums.ACTION_SHOW_MEDIA_ON_LOCK_SCREEN
|
||||
import android.content.Context
|
||||
import android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN
|
||||
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.KeyValueStoreDelegate
|
||||
import com.android.settingslib.datastore.SettingsSecureStore
|
||||
@@ -32,7 +35,13 @@ class MediaControlsLockscreenSwitchPreference :
|
||||
KEY,
|
||||
R.string.media_controls_lockscreen_title,
|
||||
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
|
||||
get() = SensitivityLevel.NO_SENSITIVITY
|
||||
|
@@ -16,30 +16,39 @@
|
||||
|
||||
package com.android.settings.sound
|
||||
|
||||
import android.app.settings.SettingsEnums.ACTION_PIN_MEDIA_PLAYER
|
||||
import android.content.Context
|
||||
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.SettingsSecureStore
|
||||
import com.android.settingslib.metadata.ReadWritePermit
|
||||
import com.android.settingslib.metadata.SensitivityLevel
|
||||
import com.android.settingslib.metadata.SwitchPreference
|
||||
import com.android.settings.R
|
||||
|
||||
// LINT.IfChange
|
||||
class MediaControlsSwitchPreference(
|
||||
private val mediaControlsStore: MediaControlsScreen.MediaControlsStore,
|
||||
) : SwitchPreference(
|
||||
private val mediaControlsStore: MediaControlsScreen.MediaControlsStore
|
||||
) :
|
||||
SwitchPreference(
|
||||
KEY,
|
||||
R.string.media_controls_resume_title,
|
||||
R.string.media_controls_resume_description,
|
||||
) {
|
||||
),
|
||||
PreferenceActionMetricsProvider {
|
||||
override val sensitivityLevel
|
||||
get() = SensitivityLevel.NO_SENSITIVITY
|
||||
|
||||
override val keywords: Int
|
||||
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 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) =
|
||||
preferenceHierarchy(context, this) {
|
||||
+SupervisionMainSwitchPreference()
|
||||
+SupervisionMainSwitchPreference(context)
|
||||
+TitlelessPreferenceGroup(SUPERVISION_DYNAMIC_GROUP_1) += {
|
||||
+SupervisionWebContentFiltersScreen.KEY
|
||||
}
|
||||
|
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package com.android.settings.supervision
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.supervision.SupervisionManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.preference.Preference
|
||||
import com.android.settings.R
|
||||
import com.android.settingslib.datastore.KeyValueStore
|
||||
@@ -32,19 +34,22 @@ import com.android.settingslib.preference.MainSwitchPreferenceBinding
|
||||
import com.android.settingslib.preference.forEachRecursively
|
||||
|
||||
/** Main toggle to enable or disable device supervision. */
|
||||
class SupervisionMainSwitchPreference :
|
||||
class SupervisionMainSwitchPreference(context: Context) :
|
||||
MainSwitchPreference(KEY, R.string.device_supervision_switch_title),
|
||||
PreferenceSummaryProvider,
|
||||
MainSwitchPreferenceBinding,
|
||||
Preference.OnPreferenceChangeListener,
|
||||
PreferenceLifecycleProvider {
|
||||
|
||||
private val supervisionMainSwitchStorage = SupervisionMainSwitchStorage(context)
|
||||
private lateinit var lifeCycleContext: PreferenceLifecycleContext
|
||||
|
||||
// TODO(b/383568136): Make presence of summary conditional on whether PIN
|
||||
// has been set up before or not.
|
||||
override fun getSummary(context: Context): CharSequence? =
|
||||
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) =
|
||||
ReadWritePermit.DISALLOW
|
||||
@@ -55,26 +60,49 @@ class SupervisionMainSwitchPreference :
|
||||
override val sensitivityLevel: Int
|
||||
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) {
|
||||
super.bind(preference, metadata)
|
||||
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 {
|
||||
if (newValue !is Boolean) return true
|
||||
|
||||
updateDependentPreferencesEnabledState(preference, newValue)
|
||||
|
||||
return true
|
||||
val intent = Intent(lifeCycleContext, ConfirmSupervisionCredentialsActivity::class.java)
|
||||
lifeCycleContext.startActivityForResult(
|
||||
intent,
|
||||
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||
null,
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun updateDependentPreferencesEnabledState(
|
||||
@@ -83,9 +111,8 @@ class SupervisionMainSwitchPreference :
|
||||
) {
|
||||
preference?.parent?.forEachRecursively {
|
||||
if (
|
||||
it.parent?.key?.toString() ==
|
||||
SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
||||
it.key?.toString() == SupervisionPinManagementScreen.KEY
|
||||
it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
|
||||
it.key == SupervisionPinManagementScreen.KEY
|
||||
) {
|
||||
it.isEnabled = isChecked
|
||||
}
|
||||
@@ -103,7 +130,6 @@ class SupervisionMainSwitchPreference :
|
||||
as 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) {
|
||||
val supervisionManager = context.getSystemService(SupervisionManager::class.java)
|
||||
supervisionManager?.setSupervisionEnabled(value)
|
||||
@@ -113,5 +139,6 @@ class SupervisionMainSwitchPreference :
|
||||
|
||||
companion object {
|
||||
const val KEY = "device_supervision_switch"
|
||||
const val REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS = 0
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.accessibility;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -76,6 +78,15 @@ public class TextReadingPreviewControllerTest {
|
||||
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
|
||||
public void initPreviewerAdapter_verifyAction() {
|
||||
when(mPreferenceScreen.findPreference(PREVIEW_KEY)).thenReturn(mPreviewPreference);
|
||||
|
@@ -49,29 +49,48 @@ import org.robolectric.RobolectricTestRunner;
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class TextReadingPreviewPreferenceTest {
|
||||
|
||||
private Context mContext;
|
||||
private TextReadingPreviewPreference mTextReadingPreviewPreference;
|
||||
private PreferenceViewHolder mHolder;
|
||||
private ViewPager mViewPager;
|
||||
private PreviewPagerAdapter mPreviewPagerAdapter;
|
||||
private int mPreviewSampleCount;
|
||||
private int[] mPreviewContentDescriptions;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
final Context context = ApplicationProvider.getApplicationContext();
|
||||
final int[] previewSamples = TextReadingPreviewController.getPreviewSampleLayouts(context);
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
mPreviewContentDescriptions =
|
||||
TextReadingPreviewController.getPreviewSampleContentDescriptions(mContext);
|
||||
final int[] previewSamples = TextReadingPreviewController.getPreviewSampleLayouts(mContext);
|
||||
mPreviewSampleCount = previewSamples.length;
|
||||
final Configuration[] configurations = createConfigurations(mPreviewSampleCount);
|
||||
mTextReadingPreviewPreference = new TextReadingPreviewPreference(context);
|
||||
mTextReadingPreviewPreference = new TextReadingPreviewPreference(mContext);
|
||||
mPreviewPagerAdapter =
|
||||
spy(new PreviewPagerAdapter(context, /* isLayoutRtl= */ false,
|
||||
spy(new PreviewPagerAdapter(mContext, /* isLayoutRtl= */ false,
|
||||
previewSamples, configurations));
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
final View view =
|
||||
inflater.inflate(mTextReadingPreviewPreference.getLayoutResource(),
|
||||
new LinearLayout(context), false);
|
||||
new LinearLayout(mContext), false);
|
||||
mHolder = PreferenceViewHolder.createInstanceForTests(view);
|
||||
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
|
||||
|
@@ -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.FaceManager;
|
||||
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.preference.Preference;
|
||||
@@ -50,6 +53,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -67,6 +71,8 @@ public class FaceStatusPreferenceControllerTest {
|
||||
|
||||
private static final String TEST_PREF_KEY = "baz";
|
||||
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
@Mock
|
||||
@@ -125,7 +131,8 @@ public class FaceStatusPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
@@ -135,6 +142,18 @@ public class FaceStatusPreferenceControllerTest {
|
||||
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
|
||||
public void updateState_hasFace_shouldShowSummary() {
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
|
@@ -36,6 +36,9 @@ import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
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.preference.Preference;
|
||||
@@ -51,6 +54,7 @@ import com.android.settingslib.utils.StringUtil;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -66,6 +70,8 @@ import java.util.Collections;
|
||||
@Config(shadows = {ShadowRestrictedLockUtilsInternal.class})
|
||||
public class FingerprintStatusPreferenceControllerTest {
|
||||
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
@Mock
|
||||
private LockPatternUtils mLockPatternUtils;
|
||||
@Mock
|
||||
@@ -125,7 +131,8 @@ public class FingerprintStatusPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
@@ -135,6 +142,19 @@ public class FingerprintStatusPreferenceControllerTest {
|
||||
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
|
||||
public void updateState_hasFingerprint_shouldShowSummary() {
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
|
@@ -16,11 +16,8 @@
|
||||
|
||||
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.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -66,6 +63,7 @@ public class CommunalPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||
public void isAvailable_communalEnabled_shouldBeTrueForPrimaryUser() {
|
||||
setCommunalEnabled(true);
|
||||
mShadowUserManager.setUserForeground(true);
|
||||
@@ -73,6 +71,7 @@ public class CommunalPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||
public void isAvailable_communalEnabled_shouldBeFalseForSecondaryUser() {
|
||||
setCommunalEnabled(true);
|
||||
mShadowUserManager.setUserForeground(false);
|
||||
@@ -80,6 +79,7 @@ public class CommunalPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||
public void isAvailable_communalDisabled_shouldBeFalseForPrimaryUser() {
|
||||
setCommunalEnabled(false);
|
||||
mShadowUserManager.setUserForeground(true);
|
||||
@@ -88,36 +88,8 @@ public class CommunalPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
|
||||
public void isAvailable_communalOnMobileEnabled_shouldBeTrueForPrimaryUser() {
|
||||
setCommunalEnabled(false);
|
||||
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);
|
||||
public void isAvailable_glanceableHubV2Enabled_shouldBeFalseForPrimaryUser() {
|
||||
setCommunalEnabled(true);
|
||||
mShadowUserManager.setUserForeground(true);
|
||||
assertFalse(mController.isAvailable());
|
||||
}
|
||||
@@ -125,9 +97,4 @@ public class CommunalPreferenceControllerTest {
|
||||
private void setCommunalEnabled(boolean 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.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
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.BluetoothCallback;
|
||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||
import com.android.settingslib.bluetooth.HeadsetProfile;
|
||||
@@ -144,6 +146,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
@Mock private LeAudioProfile mLeAudioProfile;
|
||||
@Mock private A2dpProfile mA2dpProfile;
|
||||
@Mock private HeadsetProfile mHeadsetProfile;
|
||||
@Mock private ContentResolver mContentResolver;
|
||||
|
||||
private Context mContext;
|
||||
private AudioSharingDevicePreferenceController mController;
|
||||
@@ -156,7 +159,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
|
||||
mShadowBluetoothAdapter.setEnabled(true);
|
||||
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
|
||||
@@ -185,6 +188,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP);
|
||||
when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
|
||||
when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
|
||||
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
when(mScreen.getContext()).thenReturn(mContext);
|
||||
mPreferenceGroup = spy(new PreferenceCategory(mContext));
|
||||
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
|
||||
@@ -211,6 +215,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
verify(mAssistant, never())
|
||||
.registerServiceCallBack(
|
||||
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()).refreshPreference();
|
||||
}
|
||||
@@ -224,6 +234,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
verify(mAssistant)
|
||||
.registerServiceCallBack(
|
||||
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||
verify(mContentResolver)
|
||||
.registerContentObserver(
|
||||
Settings.Secure.getUriFor(
|
||||
BluetoothUtils.getPrimaryGroupIdUriForBroadcast()),
|
||||
false,
|
||||
mController.mSettingsObserver);
|
||||
verify(mBluetoothDeviceUpdater).registerCallback();
|
||||
verify(mBluetoothDeviceUpdater).refreshPreference();
|
||||
}
|
||||
@@ -236,6 +252,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
verify(mDialogHandler, never()).unregisterCallbacks();
|
||||
verify(mAssistant, never())
|
||||
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||
verify(mContentResolver, never()).unregisterContentObserver(mController.mSettingsObserver);
|
||||
verify(mBluetoothDeviceUpdater, never()).unregisterCallback();
|
||||
}
|
||||
|
||||
@@ -247,6 +264,7 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
verify(mDialogHandler).unregisterCallbacks();
|
||||
verify(mAssistant)
|
||||
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
|
||||
verify(mContentResolver).unregisterContentObserver(mController.mSettingsObserver);
|
||||
verify(mBluetoothDeviceUpdater).unregisterCallback();
|
||||
}
|
||||
|
||||
@@ -485,6 +503,12 @@ public class AudioSharingDevicePreferenceControllerTest {
|
||||
verifyNoInteractions(mDialogHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onFallbackDeviceChanged_updateSummary() {
|
||||
mController.mSettingsObserver.onChange(true);
|
||||
verify(mBluetoothDeviceUpdater).refreshPreference();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
|
||||
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.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.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -39,6 +42,7 @@ import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.platform.test.annotations.EnableFlags;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
@@ -52,6 +56,7 @@ import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -254,6 +259,7 @@ public class AudioStreamHeaderControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE)
|
||||
public void testCallback_onReceiveStateChanged_updateButton() {
|
||||
when(mAudioStreamsHelper.getConnectedBroadcastIdAndState(anyBoolean()))
|
||||
.thenReturn(Map.of(BROADCAST_ID, STREAMING));
|
||||
@@ -271,6 +277,7 @@ public class AudioStreamHeaderControllerTest {
|
||||
verify(mHeaderController, times(2))
|
||||
.setSummary(mContext.getString(AUDIO_STREAM_HEADER_LISTENING_NOW_SUMMARY));
|
||||
verify(mHeaderController, times(2)).done(true);
|
||||
verify(mAudioStreamsHelper, never()).startMediaService(any(), anyInt(), anyString());
|
||||
}
|
||||
|
||||
@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.DEVICES;
|
||||
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;
|
||||
|
||||
@@ -57,6 +61,7 @@ import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.android.settings.connecteddevice.audiosharing.audiostreams.testshadows.ShadowAudioStreamsHelper;
|
||||
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.LocalBluetoothManager;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||
import com.android.settingslib.bluetooth.PrivateBroadcastReceiveData;
|
||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
|
||||
@@ -116,6 +122,8 @@ public class AudioStreamMediaServiceTest {
|
||||
@Mock private VolumeControlProfile mVolumeControlProfile;
|
||||
@Mock private CachedBluetoothDevice mCachedBluetoothDevice;
|
||||
@Mock private BluetoothDevice mDevice;
|
||||
@Mock
|
||||
private BluetoothDevice mDevice2;
|
||||
@Mock private ISession mISession;
|
||||
@Mock private ISessionController mISessionController;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@@ -240,6 +248,7 @@ public class AudioStreamMediaServiceTest {
|
||||
@Test
|
||||
public void onDestroy_flagOn_cleanup() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
var devices = new ArrayList<BluetoothDevice>();
|
||||
devices.add(mDevice);
|
||||
|
||||
@@ -256,8 +265,33 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void onStartCommand_noBroadcastId_stopSelf() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
mAudioStreamMediaService.onStartCommand(new Intent(), /* flags= */ 0, /* startId= */ 0);
|
||||
|
||||
verify(mAudioStreamMediaService).stopSelf();
|
||||
@@ -265,6 +299,7 @@ public class AudioStreamMediaServiceTest {
|
||||
|
||||
@Test
|
||||
public void onStartCommand_noDevice_stopSelf() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(BROADCAST_ID, 1);
|
||||
|
||||
@@ -273,8 +308,110 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void onStartCommand_createSessionAndStartForeground() {
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
var devices = new ArrayList<BluetoothDevice>();
|
||||
devices.add(mDevice);
|
||||
|
||||
@@ -317,6 +454,7 @@ public class AudioStreamMediaServiceTest {
|
||||
|
||||
@Test
|
||||
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_ENABLE_LE_AUDIO_SHARING);
|
||||
|
||||
@@ -338,6 +476,7 @@ public class AudioStreamMediaServiceTest {
|
||||
|
||||
@Test
|
||||
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_ENABLE_LE_AUDIO_SHARING);
|
||||
|
||||
@@ -357,6 +496,7 @@ public class AudioStreamMediaServiceTest {
|
||||
|
||||
@Test
|
||||
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.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
|
||||
@@ -386,6 +526,7 @@ public class AudioStreamMediaServiceTest {
|
||||
@Test
|
||||
public void bluetoothCallback_onDeviceDisconnect_stopSelf() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
mAudioStreamMediaService.onCreate();
|
||||
assertThat(mAudioStreamMediaService.mBluetoothCallback).isNotNull();
|
||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||
@@ -398,9 +539,26 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void mediaSessionCallback_onPause_setVolume() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
|
||||
mAudioStreamMediaService.onCreate();
|
||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||
@@ -415,9 +573,26 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void mediaSessionCallback_onPlay_setVolume() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
|
||||
mAudioStreamMediaService.onCreate();
|
||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||
@@ -432,9 +607,66 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void mediaSessionCallback_onCustomAction_leaveBroadcast() {
|
||||
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
|
||||
mSetFlagsRule.disableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE);
|
||||
|
||||
mAudioStreamMediaService.onCreate();
|
||||
mAudioStreamMediaService.onStartCommand(setupIntent(), /* flags= */ 0, /* startId= */ 0);
|
||||
@@ -449,6 +681,23 @@ public class AudioStreamMediaServiceTest {
|
||||
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
|
||||
public void onBind_returnNull() {
|
||||
IBinder binder = mAudioStreamMediaService.onBind(new Intent());
|
||||
@@ -466,4 +715,13 @@ public class AudioStreamMediaServiceTest {
|
||||
intent.putParcelableArrayListExtra(DEVICES, devices);
|
||||
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 org.mockito.ArgumentMatchers.any;
|
||||
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.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -33,6 +36,9 @@ import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
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.preference.Preference;
|
||||
@@ -43,6 +49,7 @@ import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.shadow.ShadowFragment;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.flags.Flags;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -62,6 +69,7 @@ import org.robolectric.annotation.Config;
|
||||
})
|
||||
public class SourceAddedStateTest {
|
||||
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
private static final int BROADCAST_ID = 1;
|
||||
private static final String BROADCAST_TITLE = "title";
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
@@ -105,7 +113,8 @@ public class SourceAddedStateTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformAction() {
|
||||
@DisableFlags(Flags.FLAG_AUDIO_STREAM_MEDIA_SERVICE_BY_RECEIVE_STATE)
|
||||
public void testPerformAction_startService() {
|
||||
mInstance.setAudioStreamsRepositoryForTesting(mRepository);
|
||||
BluetoothLeBroadcastMetadata mockMetadata = mock(BluetoothLeBroadcastMetadata.class);
|
||||
when(mRepository.getCachedMetadata(anyInt())).thenReturn(mockMetadata);
|
||||
@@ -124,6 +133,27 @@ public class SourceAddedStateTest {
|
||||
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
|
||||
public void testGetOnClickListener_startSubSettings() {
|
||||
when(mController.getFragment()).thenReturn(mFragment);
|
||||
|
@@ -18,22 +18,30 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class EthernetInterfaceDetailsControllerTest {
|
||||
private val ethernetInterfaceDetailsFragment = EthernetInterfaceDetailsFragment()
|
||||
private val lifecycle = mock<Lifecycle>()
|
||||
|
||||
private val context: Context =
|
||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {}
|
||||
|
||||
private val ethernetInterfaceDetailsController =
|
||||
EthernetInterfaceDetailsController(context, ethernetInterfaceDetailsFragment, "eth0")
|
||||
EthernetInterfaceDetailsController(
|
||||
context,
|
||||
ethernetInterfaceDetailsFragment,
|
||||
"eth0",
|
||||
lifecycle,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun isAvailable_ShouldReturnTrue() {
|
||||
|
@@ -18,14 +18,19 @@ package com.android.settings.network.ethernet
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.EthernetManager
|
||||
import android.net.EthernetManager.STATE_ABSENT
|
||||
import android.net.EthernetManager.STATE_LINK_DOWN
|
||||
import android.net.EthernetManager.STATE_LINK_UP
|
||||
import android.net.IpConfiguration
|
||||
import android.net.LinkProperties
|
||||
import android.net.Network
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.mock
|
||||
@@ -34,12 +39,15 @@ import org.mockito.kotlin.mock
|
||||
class EthernetInterfaceTest {
|
||||
|
||||
private val mockEthernetManager = mock<EthernetManager>()
|
||||
private val mockConnectivityManager = mock<ConnectivityManager>()
|
||||
private val mockNetwork = mock<Network>()
|
||||
|
||||
private val context: Context =
|
||||
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
|
||||
override fun getSystemService(name: String): Any? =
|
||||
when (name) {
|
||||
Context.ETHERNET_SERVICE -> mockEthernetManager
|
||||
Context.CONNECTIVITY_SERVICE -> mockConnectivityManager
|
||||
else -> super.getSystemService(name)
|
||||
}
|
||||
}
|
||||
@@ -85,4 +93,27 @@ class EthernetInterfaceTest {
|
||||
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
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.supervision.flags.Flags
|
||||
import android.content.Context
|
||||
import android.platform.test.annotations.DisableFlags
|
||||
@@ -24,6 +25,7 @@ import androidx.fragment.app.testing.FragmentScenario
|
||||
import androidx.preference.Preference
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
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.google.common.truth.Truth.assertThat
|
||||
import org.junit.Rule
|
||||
@@ -57,7 +59,7 @@ class SupervisionDashboardScreenTest {
|
||||
|
||||
@Test
|
||||
@EnableFlags(Flags.FLAG_ENABLE_SUPERVISION_SETTINGS_SCREEN)
|
||||
fun toggleMainSwitch_disablesChildPreferences() {
|
||||
fun toggleMainSwitch_pinVerificationSucceeded_enablesChildPreferences() {
|
||||
FragmentScenario.launchInContainer(preferenceScreenCreator.fragmentClass()).onFragment {
|
||||
fragment ->
|
||||
val mainSwitchPreference =
|
||||
@@ -68,8 +70,38 @@ class SupervisionDashboardScreenTest {
|
||||
assertThat(childPreference.isEnabled).isFalse()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.supervision.SupervisionManager
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import androidx.preference.Preference
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
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.widget.MainSwitchPreference
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.stub
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class SupervisionMainSwitchPreferenceTest {
|
||||
private val preference = SupervisionMainSwitchPreference()
|
||||
|
||||
private val mockLifeCycleContext = mock<PreferenceLifecycleContext>()
|
||||
private val mockSupervisionManager = mock<SupervisionManager>()
|
||||
|
||||
private val appContext: Context = ApplicationProvider.getApplicationContext()
|
||||
@@ -46,6 +54,13 @@ class SupervisionMainSwitchPreferenceTest {
|
||||
}
|
||||
}
|
||||
|
||||
private val preference = SupervisionMainSwitchPreference(context)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
preference.onCreate(mockLifeCycleContext)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checked_supervisionEnabled_returnTrue() {
|
||||
setSupervisionEnabled(true)
|
||||
@@ -61,7 +76,7 @@ class SupervisionMainSwitchPreferenceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toggleOn() {
|
||||
fun toggleOn_triggersPinVerification() {
|
||||
setSupervisionEnabled(false)
|
||||
val widget = getMainSwitchPreference()
|
||||
|
||||
@@ -69,26 +84,90 @@ class SupervisionMainSwitchPreferenceTest {
|
||||
|
||||
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()
|
||||
verify(mockSupervisionManager).setSupervisionEnabled(true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toggleOff() {
|
||||
fun toggleOff_pinVerificationSucceeded_supervisionDisabled() {
|
||||
setSupervisionEnabled(true)
|
||||
val widget = getMainSwitchPreference()
|
||||
|
||||
assertThat(widget.isChecked).isTrue()
|
||||
|
||||
widget.performClick()
|
||||
preference.onActivityResult(
|
||||
mockLifeCycleContext,
|
||||
REQUEST_CODE_CONFIRM_SUPERVISION_CREDENTIALS,
|
||||
Activity.RESULT_OK,
|
||||
null,
|
||||
)
|
||||
|
||||
assertThat(widget.isChecked).isFalse()
|
||||
verify(mockSupervisionManager).setSupervisionEnabled(false)
|
||||
}
|
||||
|
||||
private fun getMainSwitchPreference(): MainSwitchPreference =
|
||||
preference.createAndBindWidget(context)
|
||||
@Test
|
||||
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) =
|
||||
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.anyInt;
|
||||
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 android.app.admin.DevicePolicyManager;
|
||||
import android.app.supervision.SupervisionManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.BiometricAuthenticator;
|
||||
import android.os.UserHandle;
|
||||
@@ -44,6 +43,7 @@ import android.platform.test.flag.junit.CheckFlagsRule;
|
||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
@@ -53,22 +53,29 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
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;
|
||||
@Mock private DevicePolicyManager mDpm;
|
||||
@Mock private SupervisionManager mSm;
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private DevicePolicyManager mDpm;
|
||||
@Mock
|
||||
private SupervisionManager mSm;
|
||||
|
||||
private ComponentName mSupervisionComponentName = new ComponentName("pkg", "cls");
|
||||
private final ComponentName mSupervisionComponent = new ComponentName("pkg", "cls");
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
when(mContext.getSystemService(DevicePolicyManager.class)).thenReturn(mDpm);
|
||||
when(mContext.getSystemService(SupervisionManager.class)).thenReturn(mSm);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +92,7 @@ public class ParentalControlsUtilsTest {
|
||||
.thenReturn(keyguardDisabledFlags);
|
||||
|
||||
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,
|
||||
@BiometricAuthenticator.Modality int modality,
|
||||
int keyguardDisabledFlags) {
|
||||
when(mSm.isSupervisionEnabledForUser(anyInt())).thenReturn(supervisionEnabled);
|
||||
when(mDpm.getKeyguardDisabledFeatures(eq(null))).thenReturn(keyguardDisabledFlags);
|
||||
when(mSm.isSupervisionEnabledForUser(anyInt())).thenReturn(supervisionEnabled);
|
||||
when(mSm.getActiveSupervisionAppPackage()).thenReturn(
|
||||
supervisionEnabled ? mSupervisionComponent.getPackageName() : null);
|
||||
|
||||
return ParentalControlsUtils.parentConsentRequiredInternal(
|
||||
mDpm, mSm, modality, new UserHandle(UserHandle.myUserId()));
|
||||
mContext, modality, new UserHandle(UserHandle.myUserId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,11 +124,11 @@ public class ParentalControlsUtilsTest {
|
||||
|
||||
for (int i = 0; i < tests.length; i++) {
|
||||
RestrictedLockUtils.EnforcedAdmin admin = getEnforcedAdminForCombination(
|
||||
mSupervisionComponentName, tests[i][0] /* modality */,
|
||||
mSupervisionComponent, tests[i][0] /* modality */,
|
||||
tests[i][1] /* keyguardDisableFlags */);
|
||||
assertNotNull(admin);
|
||||
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)
|
||||
public void getDisabledAdmin_whenFingerprintDisabled_whenFaceDisabled_returnsRestrictions() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||
.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)
|
||||
public void getDisabledAdmin_whenFaceDisabled_returnsRestriction() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE);
|
||||
|
||||
@@ -172,7 +173,8 @@ public class FaceStatusUtilsTest {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
assertThat(mFaceStatusUtils.getSummary())
|
||||
@@ -181,6 +183,17 @@ public class FaceStatusUtilsTest {
|
||||
"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
|
||||
public void getSummary_whenEnrolled_returnsSummary() {
|
||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
||||
|
@@ -161,6 +161,7 @@ public class FingerprintStatusUtilsTest {
|
||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||
public void getDisabledAdmin_whenFingerprintDisabled_returnsRestriction() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mDevicePolicyManager.getKeyguardDisabledFeatures(null))
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
|
||||
|
||||
@@ -179,7 +180,8 @@ public class FingerprintStatusUtilsTest {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
assertThat(mFingerprintStatusUtils.getSummary())
|
||||
@@ -188,6 +190,17 @@ public class FingerprintStatusUtilsTest {
|
||||
"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
|
||||
public void getSummary_whenEnrolled_returnsSummary() {
|
||||
final int enrolledFingerprintsCount = 2;
|
||||
|
@@ -187,7 +187,7 @@ public class FaceSafetySourceTest {
|
||||
|
||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||
"security_settings_face_preference_title_new",
|
||||
"security_settings_face_preference_summary_none");
|
||||
"security_settings_face_preference_summary_none_new");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -195,6 +195,7 @@ public class FaceSafetySourceTest {
|
||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||
public void setSafetySourceData_withFaceNotEnrolled_whenSupervisionIsOn_setsData() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
|
||||
@@ -205,7 +206,7 @@ public class FaceSafetySourceTest {
|
||||
|
||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||
"security_settings_face_preference_title_new",
|
||||
"security_settings_face_preference_summary_none");
|
||||
"security_settings_face_preference_summary_none_new");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -220,7 +221,7 @@ public class FaceSafetySourceTest {
|
||||
|
||||
assertSafetySourceEnabledDataSetWithSingularSummary(
|
||||
"security_settings_face_preference_title_new",
|
||||
"security_settings_face_preference_summary_none",
|
||||
"security_settings_face_preference_summary_none_new",
|
||||
FaceEnrollIntroductionInternal.class.getName());
|
||||
}
|
||||
|
||||
@@ -248,6 +249,7 @@ public class FaceSafetySourceTest {
|
||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||
public void setSafetySourceData_withFaceEnrolled_whenSupervisionIsOn_setsData() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
when(mFaceManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
|
||||
|
@@ -203,7 +203,7 @@ public class FingerprintSafetySourceTest {
|
||||
|
||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||
"security_settings_fingerprint",
|
||||
"security_settings_fingerprint_preference_summary_none");
|
||||
"security_settings_fingerprint_preference_summary_none_new");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -211,6 +211,7 @@ public class FingerprintSafetySourceTest {
|
||||
@EnableFlags(android.app.supervision.flags.Flags.FLAG_DEPRECATE_DPM_SUPERVISION_APIS)
|
||||
public void setSafetySourceData_withFingerprintNotEnrolled_whenSupervisionIsOn_setsData() {
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
|
||||
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
|
||||
@@ -222,7 +223,7 @@ public class FingerprintSafetySourceTest {
|
||||
|
||||
assertSafetySourceDisabledDataSetWithSingularSummary(
|
||||
"security_settings_fingerprint",
|
||||
"security_settings_fingerprint_preference_summary_none");
|
||||
"security_settings_fingerprint_preference_summary_none_new");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -238,7 +239,7 @@ public class FingerprintSafetySourceTest {
|
||||
|
||||
assertSafetySourceEnabledDataSetWithSingularSummary(
|
||||
"security_settings_fingerprint",
|
||||
"security_settings_fingerprint_preference_summary_none",
|
||||
"security_settings_fingerprint_preference_summary_none_new",
|
||||
FingerprintSettings.class.getName());
|
||||
}
|
||||
|
||||
@@ -272,6 +273,7 @@ public class FingerprintSafetySourceTest {
|
||||
public void setSafetySourceData_withFingerprintsEnrolled_whenSupervisionIsOn_setsData() {
|
||||
int enrolledFingerprintsCount = 2;
|
||||
when(mSupervisionManager.isSupervisionEnabledForUser(USER_ID)).thenReturn(true);
|
||||
when(mSupervisionManager.getActiveSupervisionAppPackage()).thenReturn("supervision.pkg");
|
||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||
when(mFingerprintManager.isHardwareDetected()).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.os.UserManager;
|
||||
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.RequiresFlagsEnabled;
|
||||
import android.platform.test.flag.junit.CheckFlagsRule;
|
||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||
import android.platform.test.flag.junit.SetFlagsRule;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
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 USER_ID = 11;
|
||||
|
||||
@Rule
|
||||
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
|
||||
@Rule
|
||||
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
|
||||
@Mock
|
||||
@@ -118,7 +123,8 @@ public class ScreenLockPreferenceDetailsUtilsTest {
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false);
|
||||
@@ -127,6 +133,17 @@ public class ScreenLockPreferenceDetailsUtilsTest {
|
||||
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
|
||||
public void getSummary_unsecurePattern_shouldReturnUnlockModeNone() {
|
||||
final String summary =
|
||||
|
Reference in New Issue
Block a user