Snap for 13061484 from fdb47cee3b to 25Q2-release

Change-Id: Ie5fa996b7118f2010f1aa442b97a1dac1dbdd649
This commit is contained in:
Android Build Coastguard Worker
2025-02-13 16:37:06 -08:00
93 changed files with 1087 additions and 1527 deletions

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/settingslib_expressive_radius_medium" />
<stroke android:width="1dp" android:color="@color/settingslib_materialColorOutline" />
</shape>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:drawable="@drawable/expressive_battery_hints_chip_bg"/>
</ripple>

View File

@@ -1,21 +0,0 @@
<!--
Copyright (C) 2016 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
android:height="24dp" android:viewportWidth="960" android:viewportHeight="960"
android:tint="?android:attr/colorControlNormal">
<path android:fillColor="@android:color/white"
android:pathData="M480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,473 799.5,465.5Q799,458 799,453Q794,482 772,501Q750,520 720,520L640,520Q607,520 583.5,496.5Q560,473 560,440L560,400L400,400L400,320Q400,287 423.5,263.5Q447,240 480,240L520,240L520,240Q520,217 532.5,199.5Q545,182 563,171Q543,166 522.5,163Q502,160 480,160Q346,160 253,253Q160,346 160,480Q160,480 160,480Q160,480 160,480L360,480Q426,480 473,527Q520,574 520,640L520,680L400,680L400,790Q420,795 439.5,797.5Q459,800 480,800Z"/>
</vector>

View File

@@ -0,0 +1,25 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M480,880Q396.67,880 323.67,848.5Q250.67,817 196.5,762.83Q142.33,708.67 111.17,635.33Q80,562 80,478.67Q80,395 111.17,322.5Q142.33,250 196.5,195.83Q250.67,141.67 323.67,110.83Q396.67,80 480,80Q563.67,80 636.5,110.83Q709.33,141.67 763.5,195.83Q817.67,250 848.83,322.5Q880,395 880,478.67Q880,562 848.83,635.33Q817.67,708.67 763.5,762.83Q709.33,817 636.5,848.5Q563.67,880 480,880ZM480,814Q512,778 534,734Q556,690 570,632.67L390.67,632.67Q404,687.33 426,732.33Q448,777.33 480,814ZM388.67,800.67Q366,764.33 349.5,723.17Q333,682 322,632.67L182.67,632.67Q217.67,696.67 265.5,736Q313.33,775.33 388.67,800.67ZM572,800Q638.67,778.67 691.5,735.67Q744.33,692.67 777.33,632.67L638.67,632.67Q627,681.33 610.83,722.5Q594.67,763.67 572,800ZM158,566L309.33,566Q306.33,541.33 305.5,520.5Q304.67,499.67 304.67,478.67Q304.67,455 305.83,435.5Q307,416 310,393.33L158,393.33Q151.67,416 149.17,435.17Q146.67,454.33 146.67,478.67Q146.67,503 149.17,523.17Q151.67,543.33 158,566ZM377.33,566L583.33,566Q587,538.67 588.17,519.17Q589.33,499.67 589.33,478.67Q589.33,458.33 588.17,439.5Q587,420.67 583.33,393.33L377.33,393.33Q373.67,420.67 372.5,439.5Q371.33,458.33 371.33,478.67Q371.33,499.67 372.5,519.17Q373.67,538.67 377.33,566ZM650,566L802,566Q808.33,543.33 810.83,523.17Q813.33,503 813.33,478.67Q813.33,454.33 810.83,435.17Q808.33,416 802,393.33L650.67,393.33Q653.67,423.33 654.83,442.17Q656,461 656,478.67Q656,500.33 654.5,519.83Q653,539.33 650,566ZM638,326.67L777.33,326.67Q745.67,264 692.83,221Q640,178 571.33,159.33Q594,195 610.17,235.5Q626.33,276 638,326.67ZM390.67,326.67L570.67,326.67Q559.33,276.67 535.67,230.67Q512,184.67 480,147.33Q450,177.33 429,219.67Q408,262 390.67,326.67ZM182.67,326.67L322.67,326.67Q333,278 348.83,237.83Q364.67,197.67 388,160Q319.33,178.67 267.5,221Q215.67,263.33 182.67,326.67Z"/>
</vector>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?><!--
~ 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:orientation="vertical">
<include layout="@layout/settingslib_expressive_preference"
android:id="@+id/preference_frame"/>
<LinearLayout
android:id="@+id/warning_chip_frame"
android:visibility="gone"
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/settingslib_expressive_space_small1"
android:layout_marginTop="-8dp">
<Space
android:id="@+id/warning_padding_placeholder"
android:layout_width="@dimen/settingslib_expressive_space_medium3"
android:layout_height="1px"
android:layout_marginEnd="@dimen/settingslib_expressive_space_extrasmall6"/>
<include layout="@layout/power_anomaly_hints"/>
</LinearLayout>
</LinearLayout>

View File

@@ -44,7 +44,8 @@
android:textAlignment="textStart" android:textAlignment="textStart"
android:text="@string/add_a_language" android:text="@string/add_a_language"
style="@style/Base.Widget.AppCompat.Button.Borderless" style="@style/Base.Widget.AppCompat.Button.Borderless"
android:textAppearance="?android:attr/textAppearanceListItem"/> android:textAppearance="?android:attr/textAppearanceListItem"
android:visibility="gone"/>
</LinearLayout> </LinearLayout>

View File

@@ -17,13 +17,12 @@
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:gravity="center_vertical|start" android:gravity="center_vertical|start"
android:padding="8dp" android:id="@+id/warning_chip"
android:background="@drawable/battery_hints_chip_bg_ripple"> android:padding="8dp">
<ImageView <ImageView
android:layout_width="16dp" android:layout_width="16dp"

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="vertical">
<TextView
android:id="@+id/time_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@+id/time_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
<include layout="@layout/power_anomaly_hints"
android:visibility="gone"
android:id="@+id/anomaly_hints"
android:paddingBottom="20dp"/>
</LinearLayout>

View File

@@ -66,6 +66,8 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:paddingStart="0dp" android:paddingStart="0dp"
android:paddingEnd="12dp" android:paddingEnd="12dp"
android:progressBackgroundTint="@color/settingslib_materialColorOutline"
android:progressTint="@color/settingslib_materialColorPrimaryFixed"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp"/> android:layout_height="48dp"/>

View File

@@ -16,8 +16,10 @@
<ScrollView <ScrollView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:theme="@style/Theme.AppCompat.DayNight">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -43,17 +45,24 @@
android:id="@+id/private_dns_mode_provider" android:id="@+id/private_dns_mode_provider"
layout="@layout/preference_widget_dialog_radiobutton"/> layout="@layout/preference_widget_dialog_radiobutton"/>
<EditText <com.google.android.material.textfield.TextInputLayout
android:id="@+id/private_dns_mode_provider_hostname" android:id="@+id/private_dns_mode_provider_hostname_layout"
android:hint="@string/private_dns_mode_provider_hostname_hint"
style="@android:style/Widget.CompoundButton.RadioButton"
android:imeOptions="actionDone"
android:inputType="textFilter|textUri|textMultiLine"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="3dp" android:hint="@string/private_dns_title"
android:layout_marginEnd="8dp" android:theme="@style/Theme.Settings"
android:minHeight="@dimen/developer_option_dialog_min_height"/> app:endIconMode="clear_text"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/private_dns_mode_provider_hostname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="textFilter|textUri|textMultiLine"
android:layout_marginStart="3dp"
android:layout_marginEnd="8dp"/>
</com.google.android.material.textfield.TextInputLayout>
</RadioGroup> </RadioGroup>
<include <include

View File

@@ -22,7 +22,7 @@
<include layout="@layout/preference_app"/> <include layout="@layout/preference_app"/>
<LinearLayout <LinearLayout
android:id="@+id/warning_chip" android:id="@+id/warning_chip_frame"
android:visibility="gone" android:visibility="gone"
android:clickable="false" android:clickable="false"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -32,13 +32,12 @@
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<Space <Space
android:id="@+id/warning_padding_placeholder"
android:layout_width="@dimen/secondary_app_icon_size" android:layout_width="@dimen/secondary_app_icon_size"
android:layout_height="wrap_content" android:layout_height="1px"
android:layout_marginEnd="16dp"/> android:layout_marginEnd="16dp"/>
<include layout="@layout/power_anomaly_hints" /> <include layout="@layout/power_anomaly_hints"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -555,4 +555,10 @@
<dimen name="display_block_padding">5dp</dimen> <dimen name="display_block_padding">5dp</dimen>
<dimen name="display_block_highlight_width">2dp</dimen> <dimen name="display_block_highlight_width">2dp</dimen>
<dimen name="display_block_corner_radius">10dp</dimen> <dimen name="display_block_corner_radius">10dp</dimen>
<!-- Locale Picker -->
<dimen name="locale_picker_dialog_icon_padding">10dp</dimen>
<dimen name="locale_picker_dialog_title_padding">16dp</dimen>
<dimen name="locale_picker_dialog_message_padding_left_right">24dp</dimen>
<dimen name="locale_picker_dialog_message_padding_bottom">32dp</dimen>
</resources> </resources>

View File

@@ -305,8 +305,6 @@
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]--> <!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
<string name="connected_device_media_device_title">Media devices</string> <string name="connected_device_media_device_title">Media devices</string>
<!-- Title for temporary bond device group [CHAR LIMIT=none]-->
<string name="connected_device_temp_bond_device_title">Guest devices</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]--> <!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
<string name="connected_device_call_device_title">Call devices</string> <string name="connected_device_call_device_title">Call devices</string>
<!-- Title for connected device group [CHAR LIMIT=none]--> <!-- Title for connected device group [CHAR LIMIT=none]-->
@@ -502,7 +500,7 @@
<!-- The text of the confirmation dialog showing the system locale will be changed. [CHAR LIMIT=NONE]--> <!-- The text of the confirmation dialog showing the system locale will be changed. [CHAR LIMIT=NONE]-->
<string name="desc_notice_device_locale_settings_change">Your device settings and regional preferences will change.</string> <string name="desc_notice_device_locale_settings_change">Your device settings and regional preferences will change.</string>
<!-- A dialog button for confirmmation of system locale change. [CHAR LIMIT=25]--> <!-- A dialog button for confirmation of system locale change. [CHAR LIMIT=25]-->
<string name="button_label_confirmation_of_system_locale_change">Change</string> <string name="button_label_confirmation_of_system_locale_change">Change</string>
<!-- Title for saying this selected locale is unavailable to use. [CHAR LIMIT=50]--> <!-- Title for saying this selected locale is unavailable to use. [CHAR LIMIT=50]-->
@@ -530,10 +528,11 @@
<!-- Category for more language settings. [CHAR LIMIT=NONE]--> <!-- Category for more language settings. [CHAR LIMIT=NONE]-->
<string name="more_language_settings_category">More language settings</string> <string name="more_language_settings_category">More language settings</string>
<!-- Title for asking to change system locale region or not. [CHAR LIMIT=50]--> <!-- Title for asking to change system locale region or not. [CHAR LIMIT=50]-->
<string name="title_change_system_locale_region">Change region to %s ?</string> <string name="title_change_system_locale_region">Change region to <xliff:g id="system_language_region" example="Canada">%1$s</xliff:g> ?</string>
<!-- Message for asking to change system locale region or not. [CHAR LIMIT=50]--> <!-- Message for asking to change system locale region or not. [CHAR LIMIT=50]-->
<string name="body_change_system_locale_region">Your device will keep %s as a system language</string> <string name="body_change_system_locale_region">Your device will keep <xliff:g id="system_language" example="English">%1$s</xliff:g> as a system language</string>
<string name="top_intro_numbering_system_title">The digits used will be dependent on the numbering system</string> <!-- Description for the numbering system language. [CHAR LIMIT=NONE]-->
<string name="top_intro_numbering_system_title">Most apps will use your regional preferences</string>
<!-- Regional Preferences begin --> <!-- Regional Preferences begin -->
<!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] --> <!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
@@ -2937,6 +2936,12 @@
<string name="emergency_address_title">Emergency address</string> <string name="emergency_address_title">Emergency address</string>
<!-- Summary of Update Emergency Address preference, explaining usage of emergency address [CHAR LIMIT=NONE] --> <!-- Summary of Update Emergency Address preference, explaining usage of emergency address [CHAR LIMIT=NONE] -->
<string name="emergency_address_summary">Used as your location when you make an emergency call over Wi\u2011Fi</string> <string name="emergency_address_summary">Used as your location when you make an emergency call over Wi\u2011Fi</string>
<!-- Title of a preference for private DNS provider hostname [CHAR LIMIT=40] -->
<string name="private_dns_title">Hostname</string>
<!-- Message of private dns hostname that the field is required. [CHAR LIMIT=NONE] -->
<string name="private_dns_field_require">The field is required</string>
<!-- The error if the private dns hostname is not valid -->
<string name="private_dns_hostname_invalid">The hostname you typed isn\u2019t valid</string>
<!-- Message of private dns that provides a help link. [CHAR LIMIT=NONE] --> <!-- Message of private dns that provides a help link. [CHAR LIMIT=NONE] -->
<string name="private_dns_help_message"><annotation id="url">Learn more</annotation> about Private DNS features</string> <string name="private_dns_help_message"><annotation id="url">Learn more</annotation> about Private DNS features</string>
<!-- Message to display when private dns is on. [CHAR LIMIT=10] --> <!-- Message to display when private dns is on. [CHAR LIMIT=10] -->
@@ -13968,13 +13973,15 @@
<string name="audio_sharing_share_with_button_label">Share with <xliff:g example="My buds" id="device_name">%1$s</xliff:g></string> <string name="audio_sharing_share_with_button_label">Share with <xliff:g example="My buds" id="device_name">%1$s</xliff:g></string>
<!-- Text for audio sharing close button [CHAR LIMIT=none]--> <!-- Text for audio sharing close button [CHAR LIMIT=none]-->
<string name="audio_sharing_close_button_label">Close</string> <string name="audio_sharing_close_button_label">Close</string>
<!-- Content for audio sharing share dialog with no device, ask users to connect device [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no second device, ask users to connect device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_connect_device_content">Connect another pair of compatible headphones, or share your stream\'s name and password with the other person</string> <string name="audio_sharing_dialog_connect_device_content">Connect another pair of compatible headphones, or share your stream\'s name and password with the other person</string>
<!-- Content for audio sharing share dialog with no device, ask users to scan qr code [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no second device, ask users to scan qr code [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_qr_code_content">Let others scan this code and listen to your audio\n\nStream name: <xliff:g example="Pixel 8" id="stream_name">%1$s</xliff:g>\nPassword: <xliff:g example="123456" id="password">%2$s</xliff:g></string> <string name="audio_sharing_dialog_qr_code_content">Let others scan this code and listen to your audio\n\nStream name: <xliff:g example="Pixel 8" id="stream_name">%1$s</xliff:g>\nPassword: <xliff:g example="123456" id="password">%2$s</xliff:g></string>
<!-- Content for audio sharing share dialog with no device, ask users to pair new device [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no second device and no password, ask users to scan qr code [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_qr_code_content_no_password">Let others scan this code and listen to your audio\n\nStream name: <xliff:g example="Pixel 8" id="stream_name">%1$s</xliff:g></string>
<!-- Content for audio sharing share dialog with no second device, ask users to pair new device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_pair_new_device_content">or pair another set of compatible headphones</string> <string name="audio_sharing_dialog_pair_new_device_content">or pair another set of compatible headphones</string>
<!-- Content for audio sharing share dialog with no device, ask users to pair device [CHAR LIMIT=none]--> <!-- Content for audio sharing share dialog with no second device, ask users to pair device [CHAR LIMIT=none]-->
<string name="audio_sharing_dialog_pair_device_content">Pair another set of compatible headphones, or share your audio stream QR code with the other person</string> <string name="audio_sharing_dialog_pair_device_content">Pair another set of compatible headphones, or share your audio stream QR code with the other person</string>
<!-- Text for sharing audio sharing state [CHAR LIMIT=none]--> <!-- Text for sharing audio sharing state [CHAR LIMIT=none]-->
<string name="audio_sharing_sharing_label">Sharing audio</string> <string name="audio_sharing_sharing_label">Sharing audio</string>

View File

@@ -26,17 +26,6 @@
settings:allowDividerBelow="true" settings:allowDividerBelow="true"
settings:controller="com.android.settings.slices.SlicePreferenceController" /> settings:controller="com.android.settings.slices.SlicePreferenceController" />
<PreferenceCategory
android:key="audio_sharing_device_list"
android:title="@string/audio_sharing_device_group_title"
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController">
</PreferenceCategory>
<PreferenceCategory
android:key="temp_bond_device_list"
android:title="@string/connected_device_temp_bond_device_title"
settings:controller="com.android.settings.connecteddevice.audiosharing.TemporaryBondDeviceGroupController" />
<Preference <Preference
android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment" android:fragment="com.android.settings.connecteddevice.audiosharing.AudioSharingDashboardFragment"
android:icon="@drawable/ic_bt_le_audio_sharing" android:icon="@drawable/ic_bt_le_audio_sharing"
@@ -45,6 +34,12 @@
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController" settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingPreferenceController"
settings:searchable="false" /> settings:searchable="false" />
<PreferenceCategory
android:key="audio_sharing_device_list"
android:title="@string/audio_sharing_device_group_title"
settings:controller="com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController">
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="available_device_list" android:key="available_device_list"
android:title="@string/connected_device_media_device_title" android:title="@string/connected_device_media_device_title"

View File

@@ -31,6 +31,13 @@
<com.android.settingslib.widget.LayoutPreference <com.android.settingslib.widget.LayoutPreference
android:key="languages_picker" android:key="languages_picker"
android:layout="@layout/locale_order_list" /> android:layout="@layout/locale_order_list" />
<Preference
android:key="add_a_language"
android:title="@string/add_a_language"
android:icon="@drawable/ic_add_24dp"
settings:isPreferenceVisible="false"
settings:fragment="com.android.settings.localepicker.SystemLocalePickerFragment"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -22,7 +22,6 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.AsyncTask;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -139,13 +138,8 @@ public class ApprovalPreferenceController extends BasePreferenceController {
public void disable(final ComponentName cn) { public void disable(final ComponentName cn) {
logSpecialPermissionChange(true, cn.getPackageName()); logSpecialPermissionChange(true, cn.getPackageName());
mNm.setNotificationListenerAccessGranted(cn, false); mNm.setNotificationListenerAccessGranted(cn, false);
if (!mNm.isNotificationPolicyAccessGrantedForPackage( if (!mNm.isNotificationPolicyAccessGrantedForPackage(cn.getPackageName())) {
cn.getPackageName())) { mNm.removeAutomaticZenRules(cn.getPackageName(), /* fromUser= */ true);
if (android.app.Flags.modesApi()) {
mNm.removeAutomaticZenRules(cn.getPackageName(), /* fromUser= */ true);
} else {
mNm.removeAutomaticZenRules(cn.getPackageName());
}
} }
} }

View File

@@ -56,7 +56,7 @@ public class FriendlyWarningDialogFragment extends InstrumentedDialogFragment {
NotificationAccessDetails parent = (NotificationAccessDetails) getTargetFragment(); NotificationAccessDetails parent = (NotificationAccessDetails) getTargetFragment();
final String summary = getResources().getString( final String summary = getResources().getString(
Flags.modesApi() && Flags.modesUi() Flags.modesUi()
? R.string.notification_listener_disable_modes_warning_summary ? R.string.notification_listener_disable_modes_warning_summary
: R.string.notification_listener_disable_warning_summary, : R.string.notification_listener_disable_warning_summary,
label); label);

View File

@@ -98,7 +98,7 @@ public class ScaryWarningDialogFragment extends InstrumentedDialogFragment {
((TextView) content.findViewById(R.id.prompt)).setText(prompt); ((TextView) content.findViewById(R.id.prompt)).setText(prompt);
((TextView) content.findViewById(R.id.settings_description)).setText( ((TextView) content.findViewById(R.id.settings_description)).setText(
Flags.modesApi() && Flags.modesUi() Flags.modesUi()
? R.string.nls_feature_modes_settings_summary ? R.string.nls_feature_modes_settings_summary
: R.string.nls_feature_settings_summary); : R.string.nls_feature_settings_summary);

View File

@@ -59,12 +59,12 @@ public class FriendlyWarningDialogFragment extends InstrumentedDialogFragment {
final String label = args.getString(KEY_LABEL); final String label = args.getString(KEY_LABEL);
final String title = getResources().getString( final String title = getResources().getString(
Flags.modesApi() && Flags.modesUi() Flags.modesUi()
? R.string.zen_modes_access_revoke_warning_dialog_title ? R.string.zen_modes_access_revoke_warning_dialog_title
: R.string.zen_access_revoke_warning_dialog_title, : R.string.zen_access_revoke_warning_dialog_title,
label); label);
final String summary = getResources() final String summary = getResources()
.getString(Flags.modesApi() && Flags.modesUi() .getString(Flags.modesUi()
? R.string.zen_modes_access_revoke_warning_dialog_summary ? R.string.zen_modes_access_revoke_warning_dialog_summary
: R.string.zen_access_revoke_warning_dialog_summary); : R.string.zen_access_revoke_warning_dialog_summary);

View File

@@ -57,12 +57,12 @@ public class ScaryWarningDialogFragment extends InstrumentedDialogFragment {
final String label = args.getString(KEY_LABEL); final String label = args.getString(KEY_LABEL);
final String title = getResources().getString( final String title = getResources().getString(
Flags.modesApi() && Flags.modesUi() Flags.modesUi()
? R.string.zen_modes_access_warning_dialog_title ? R.string.zen_modes_access_warning_dialog_title
: R.string.zen_access_warning_dialog_title, : R.string.zen_access_warning_dialog_title,
label); label);
final String summary = getResources() final String summary = getResources()
.getString(Flags.modesApi() && Flags.modesUi() .getString(Flags.modesUi()
? R.string.zen_modes_access_warning_dialog_summary ? R.string.zen_modes_access_warning_dialog_summary
: R.string.zen_access_warning_dialog_summary); : R.string.zen_access_warning_dialog_summary);

View File

@@ -56,7 +56,7 @@ public class ZenAccessController extends BasePreferenceController {
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
Preference preference = screen.findPreference(getPreferenceKey()); Preference preference = screen.findPreference(getPreferenceKey());
if (preference != null) { if (preference != null) {
preference.setTitle(Flags.modesApi() && Flags.modesUi() preference.setTitle(Flags.modesUi()
? R.string.manage_zen_modes_access_title ? R.string.manage_zen_modes_access_title
: R.string.manage_zen_access_title); : R.string.manage_zen_access_title);
} }
@@ -116,11 +116,7 @@ public class ZenAccessController extends BasePreferenceController {
public static void deleteRules(final Context context, final String pkg) { public static void deleteRules(final Context context, final String pkg) {
final NotificationManager mgr = context.getSystemService(NotificationManager.class); final NotificationManager mgr = context.getSystemService(NotificationManager.class);
if (android.app.Flags.modesApi()) { mgr.removeAutomaticZenRules(pkg, /* fromUser= */ true);
mgr.removeAutomaticZenRules(pkg, /* fromUser= */ true);
} else {
mgr.removeAutomaticZenRules(pkg);
}
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -51,7 +51,7 @@ public class ZenAccessDetails extends AppInfoWithHeader implements
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
requireActivity().setTitle(Flags.modesApi() && Flags.modesUi() requireActivity().setTitle(Flags.modesUi()
? R.string.manage_zen_modes_access_title ? R.string.manage_zen_modes_access_title
: R.string.manage_zen_access_title); : R.string.manage_zen_access_title);
} }
@@ -89,7 +89,7 @@ public class ZenAccessDetails extends AppInfoWithHeader implements
preference.setSummary(getString(R.string.zen_access_disabled_package_warning)); preference.setSummary(getString(R.string.zen_access_disabled_package_warning));
return; return;
} }
preference.setTitle(Flags.modesApi() && Flags.modesUi() preference.setTitle(Flags.modesUi()
? R.string.zen_modes_access_detail_switch ? R.string.zen_modes_access_detail_switch
: R.string.zen_access_detail_switch); : R.string.zen_access_detail_switch);
preference.setChecked(ZenAccessController.hasAccess(context, mPackageName)); preference.setChecked(ZenAccessController.hasAccess(context, mPackageName));

View File

@@ -26,7 +26,6 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
/** Controller to maintain available media Bluetooth devices */ /** Controller to maintain available media Bluetooth devices */
@@ -61,14 +60,6 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater
@Override @Override
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
// If the device is temporary bond, it shouldn't be shown here.
if (Flags.enableTemporaryBondDevicesUi()
&& BluetoothUtils.isTemporaryBondDevice(cachedDevice.getDevice())) {
Log.d(TAG,
"isFilterMatched() Filter out temporary bond device " + cachedDevice.getName());
return false;
}
final int currentAudioProfile; final int currentAudioProfile;
if (mAudioMode == AudioManager.MODE_RINGTONE if (mAudioMode == AudioManager.MODE_RINGTONE

View File

@@ -57,14 +57,6 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
@Override @Override
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
// If the device is temporary bond, it shouldn't be shown here.
if (Flags.enableTemporaryBondDevicesUi()
&& BluetoothUtils.isTemporaryBondDevice(cachedDevice.getDevice())) {
Log.d(TAG,
"isFilterMatched() Filter out temporary bond device " + cachedDevice.getName());
return false;
}
final int currentAudioProfile; final int currentAudioProfile;
if (mAudioMode == AudioManager.MODE_RINGTONE if (mAudioMode == AudioManager.MODE_RINGTONE

View File

@@ -27,7 +27,6 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController; import com.android.settings.connecteddevice.audiosharing.AudioSharingDevicePreferenceController;
import com.android.settings.connecteddevice.audiosharing.TemporaryBondDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SurveyFeatureProvider; import com.android.settings.overlay.SurveyFeatureProvider;
@@ -35,7 +34,6 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.slices.SlicePreferenceController; import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils; import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
@@ -84,9 +82,6 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
} }
if (BluetoothUtils.isAudioSharingUIAvailable(context)) { if (BluetoothUtils.isAudioSharingUIAvailable(context)) {
use(AudioSharingDevicePreferenceController.class).init(this); use(AudioSharingDevicePreferenceController.class).init(this);
if (Flags.enableTemporaryBondDevicesUi()) {
use(TemporaryBondDeviceGroupController.class).init(this);
}
} }
use(AvailableMediaDeviceGroupController.class).init(this); use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this);

View File

@@ -29,7 +29,6 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater
@@ -52,14 +51,6 @@ public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater
@Override @Override
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) { public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
// If the device is temporary bond, it shouldn't be shown here.
if (Flags.enableTemporaryBondDevicesUi()
&& BluetoothUtils.isTemporaryBondDevice(cachedDevice.getDevice())) {
Log.d(TAG,
"isFilterMatched() Filter out temporary bond device " + cachedDevice.getName());
return false;
}
boolean isFilterMatched = false; boolean isFilterMatched = false;
if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) { if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) {
// If device is LE audio device and has a broadcast source, // If device is LE audio device and has a broadcast source,

View File

@@ -67,7 +67,6 @@ import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/** PreferenceController to control the dialog to choose the active device for calls and alarms */ /** PreferenceController to control the dialog to choose the active device for calls and alarms */
public class AudioSharingCallAudioPreferenceController extends AudioSharingBasePreferenceController public class AudioSharingCallAudioPreferenceController extends AudioSharingBasePreferenceController
@@ -404,21 +403,11 @@ public class AudioSharingCallAudioPreferenceController extends AudioSharingBaseP
private void updateDeviceItemsInSharingSession() { private void updateDeviceItemsInSharingSession() {
mGroupedConnectedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(mBtManager); mGroupedConnectedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(mBtManager);
if (Flags.enableTemporaryBondDevicesUi()) {
mGroupedConnectedDevices =
mGroupedConnectedDevices.entrySet().stream()
.filter(entry -> !anyTemporaryBondDevice(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
mDeviceItemsInSharingSession = mDeviceItemsInSharingSession =
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem( AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ true); mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ true);
} }
private boolean anyTemporaryBondDevice(List<BluetoothDevice> connectedDevices) {
return connectedDevices.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice);
}
@Nullable @Nullable
private Pair<Integer, AudioSharingDeviceItem> getActiveItemWithIndex() { private Pair<Integer, AudioSharingDeviceItem> getActiveItemWithIndex() {
List<AudioSharingDeviceItem> deviceItems = new ArrayList<>(mDeviceItemsInSharingSession); List<AudioSharingDeviceItem> deviceItems = new ArrayList<>(mDeviceItemsInSharingSession);

View File

@@ -186,14 +186,17 @@ public class AudioSharingDialogFragment extends InstrumentedDialogFragment {
Drawable qrCodeDrawable = metadata == null ? null : getQrCodeDrawable(metadata, Drawable qrCodeDrawable = metadata == null ? null : getQrCodeDrawable(metadata,
getContext()).orElse(null); getContext()).orElse(null);
if (qrCodeDrawable != null) { if (qrCodeDrawable != null) {
String broadcastName =
metadata.getBroadcastName() == null ? "" : metadata.getBroadcastName();
boolean hasPassword = metadata.getBroadcastCode() != null
&& metadata.getBroadcastCode().length > 0;
String message = hasPassword ? getString(
R.string.audio_sharing_dialog_qr_code_content, broadcastName,
new String(metadata.getBroadcastCode(), StandardCharsets.UTF_8)) :
getString(R.string.audio_sharing_dialog_qr_code_content_no_password,
broadcastName);
builder.setCustomImage(qrCodeDrawable) builder.setCustomImage(qrCodeDrawable)
.setCustomMessage( .setCustomMessage(message)
getString(
R.string.audio_sharing_dialog_qr_code_content,
metadata.getBroadcastName(),
new String(
metadata.getBroadcastCode(),
StandardCharsets.UTF_8)))
.setCustomMessage2(R.string.audio_sharing_dialog_pair_new_device_content) .setCustomMessage2(R.string.audio_sharing_dialog_pair_new_device_content)
.setCustomNegativeButton(R.string.audio_streams_dialog_close, .setCustomNegativeButton(R.string.audio_streams_dialog_close,
v -> onCancelClick()); v -> onCancelClick());

View File

@@ -1,170 +0,0 @@
/*
* 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.connecteddevice.audiosharing;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
/**
* Controller to maintain the {@link androidx.preference.PreferenceGroup} for all connected
* temporary bond devices. It uses {@link DevicePreferenceCallback} to add/remove
* {@link Preference}
*/
public class TemporaryBondDeviceGroupController extends BasePreferenceController implements
DefaultLifecycleObserver, DevicePreferenceCallback, BluetoothCallback {
private static final String TAG = "TemporaryBondDeviceGroupController";
private static final String KEY = "temp_bond_device_list";
@Nullable
private final BluetoothEventManager mEventManager;
@Nullable
private PreferenceGroup mPreferenceGroup;
@Nullable
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
public TemporaryBondDeviceGroupController(@NonNull Context context) {
super(context, KEY);
LocalBluetoothManager btManager = Utils.getLocalBtManager(mContext);
mEventManager = btManager == null ? null : btManager.getEventManager();
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
if (!isAvailable()) {
Log.d(TAG, "Skip onStart(), feature is not supported.");
return;
}
if (mEventManager == null) {
Log.d(TAG, "onStart() Bluetooth is not supported on this device");
return;
}
var unused = ThreadUtils.postOnBackgroundThread(() -> {
mEventManager.registerCallback(this);
if (mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.registerCallback();
mBluetoothDeviceUpdater.refreshPreference();
}
});
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
var unused = ThreadUtils.postOnBackgroundThread(() -> {
if (mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.unregisterCallback();
}
if (mEventManager != null) {
mEventManager.unregisterCallback(this);
return;
}
Log.d(TAG, "onStop() Bluetooth is not supported on this device");
});
}
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceGroup = screen.findPreference(KEY);
if (mPreferenceGroup != null) {
mPreferenceGroup.setVisible(false);
}
if (isAvailable() && mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
mBluetoothDeviceUpdater.forceUpdate();
}
}
@Override
public void onDeviceAdded(@NonNull Preference preference) {
if (mPreferenceGroup != null) {
mPreferenceGroup.addPreference(preference);
Log.d(TAG, "Temporary bond device added");
if (mPreferenceGroup.getPreferenceCount() == 1) {
mPreferenceGroup.setVisible(true);
}
}
}
@Override
public void onDeviceRemoved(@NonNull Preference preference) {
if (mPreferenceGroup != null) {
mPreferenceGroup.removePreference(preference);
Log.d(TAG, "Temporary bond device removed");
if (mPreferenceGroup.getPreferenceCount() == 0) {
mPreferenceGroup.setVisible(false);
}
}
}
@Override
public int getAvailabilityStatus() {
return (BluetoothUtils.isAudioSharingUIAvailable(mContext)
&& mBluetoothDeviceUpdater != null && Flags.enableTemporaryBondDevicesUi())
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
public String getPreferenceKey() {
return KEY;
}
/**
* Initialize the controller.
*
* @param fragment The fragment to provide the context and metrics category for {@link
* TemporaryBondDeviceGroupUpdater} and provide the host for dialogs.
*/
public void init(@NonNull DashboardFragment fragment) {
mBluetoothDeviceUpdater = new TemporaryBondDeviceGroupUpdater(fragment.getContext(),
TemporaryBondDeviceGroupController.this,
fragment.getMetricsCategory());
}
@VisibleForTesting
void setBluetoothDeviceUpdater(@Nullable BluetoothDeviceUpdater bluetoothDeviceUpdater) {
mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
}
@VisibleForTesting
void setPreferenceGroup(@Nullable PreferenceGroup preferenceGroup) {
mPreferenceGroup = preferenceGroup;
}
}

View File

@@ -1,74 +0,0 @@
/*
* 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.connecteddevice.audiosharing;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.flags.Flags;
/** Maintain and update connected temporary bond bluetooth devices */
public class TemporaryBondDeviceGroupUpdater extends BluetoothDeviceUpdater {
private static final String TAG = "TemporaryBondDeviceGroupUpdater";
private static final String PREF_KEY_PREFIX = "temp_bond_bt_";
public TemporaryBondDeviceGroupUpdater(
@NonNull Context context,
@NonNull DevicePreferenceCallback devicePreferenceCallback,
int metricsCategory) {
super(context, devicePreferenceCallback, metricsCategory);
}
@Override
public boolean isFilterMatched(@NonNull CachedBluetoothDevice cachedDevice) {
// Only connected temporary bond device should be shown in this section when Audio
// sharing UI is available.
boolean isFilterMatched = Flags.enableTemporaryBondDevicesUi()
&& BluetoothUtils.isTemporaryBondDevice(cachedDevice.getDevice())
&& isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)
&& BluetoothUtils.isAudioSharingUIAvailable(mContext);
Log.d(
TAG,
"isFilterMatched() device : "
+ cachedDevice.getName()
+ ", isFilterMatched : "
+ isFilterMatched);
return isFilterMatched;
}
@Override
protected String getPreferenceKeyPrefix() {
return PREF_KEY_PREFIX;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected void update(CachedBluetoothDevice cachedBluetoothDevice) {
super.update(cachedBluetoothDevice);
Log.d(TAG, "Map : " + mPreferenceMap);
}
}

View File

@@ -59,6 +59,7 @@ import com.android.settingslib.widget.TwoTargetPreference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
/** /**
* The Settings screen for External Displays configuration and connection management. * The Settings screen for External Displays configuration and connection management.
@@ -85,8 +86,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
BUILTIN_DISPLAY_LIST(70, "builtin_display_list_preference", BUILTIN_DISPLAY_LIST(70, "builtin_display_list_preference",
R.string.builtin_display_settings_category), R.string.builtin_display_settings_category),
DISPLAYS_LIST(80, "displays_list_preference", null),
// If shown, footer should appear below everything. // If shown, footer should appear below everything.
FOOTER(90, "footer_preference", null); FOOTER(90, "footer_preference", null);
@@ -333,15 +332,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
return args != null ? args.getInt(DISPLAY_ID_ARG, INVALID_DISPLAY) : INVALID_DISPLAY; return args != null ? args.getInt(DISPLAY_ID_ARG, INVALID_DISPLAY) : INVALID_DISPLAY;
} }
@NonNull
private PreferenceCategory getDisplaysListPreference(@NonNull Context context) {
if (mDisplaysPreference == null) {
mDisplaysPreference = new PreferenceCategory(context);
PrefBasics.DISPLAYS_LIST.apply(mDisplaysPreference);
}
return mDisplaysPreference;
}
@NonNull @NonNull
private PreferenceCategory getBuiltinDisplayListPreference(@NonNull Context context) { private PreferenceCategory getBuiltinDisplayListPreference(@NonNull Context context) {
if (mBuiltinDisplayPreference == null) { if (mBuiltinDisplayPreference == null) {
@@ -455,6 +445,26 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE)); EXTERNAL_DISPLAY_NOT_FOUND_FOOTER_RESOURCE));
} }
private static PreferenceCategory getCategoryForDisplay(@NonNull Display display,
@NonNull PrefRefresh screen, @NonNull Context context) {
// The rest of the settings are in a category with the display name as the title.
String categoryKey = "expanded_display_items_" + display.getDisplayId();
var category = (PreferenceCategory) screen.findUnusedPreference(categoryKey);
if (category != null) {
screen.addPreference(category);
} else {
category = new PreferenceCategory(context);
screen.addPreference(category);
category.setPersistent(false);
category.setKey(categoryKey);
category.setTitle(display.getName());
category.setOrder(PrefBasics.BUILTIN_DISPLAY_LIST.order + 1);
}
return category;
}
private void showDisplaySettings(@NonNull Display display, @NonNull PrefRefresh screen, private void showDisplaySettings(@NonNull Display display, @NonNull PrefRefresh screen,
@NonNull Context context) { @NonNull Context context) {
final var isEnabled = mInjector != null && mInjector.isDisplayEnabled(display); final var isEnabled = mInjector != null && mInjector.isDisplayEnabled(display);
@@ -469,8 +479,18 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
if (!isTopologyPaneEnabled(mInjector)) { if (!isTopologyPaneEnabled(mInjector)) {
screen.addPreference(updateIllustrationImage(context, displayRotation)); screen.addPreference(updateIllustrationImage(context, displayRotation));
} }
screen.addPreference(updateResolutionPreference(context, display));
screen.addPreference(updateRotationPreference(context, display, displayRotation)); Consumer<Preference> adder;
if (isTopologyPaneEnabled(mInjector)) {
adder = getCategoryForDisplay(display, screen, context)::addPreference;
// The category may have already been populated if it was retrieved from the PrefRefresh
// backup, but we still need to update resolution and rotation items.
} else {
adder = screen::addPreference;
}
adder.accept(updateResolutionPreference(context, display));
adder.accept(updateRotationPreference(context, display, displayRotation));
if (isResolutionSettingEnabled(mInjector)) { if (isResolutionSettingEnabled(mInjector)) {
// Do not show the footer about changing resolution affecting apps. This is not in the // Do not show the footer about changing resolution affecting apps. This is not in the
// UX design for v2, and there is no good place to put it, since (a) if it is on the // UX design for v2, and there is no good place to put it, since (a) if it is on the
@@ -483,12 +503,12 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
// TODO(b/352648432): probably remove footer once the pane and rest of v2 UI is in // TODO(b/352648432): probably remove footer once the pane and rest of v2 UI is in
// place. // place.
if (!isTopologyPaneEnabled(mInjector)) { if (!isTopologyPaneEnabled(mInjector)) {
screen.addPreference(updateFooterPreference(context, adder.accept(updateFooterPreference(context,
EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE)); EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE));
} }
} }
if (isDisplaySizeSettingEnabled(mInjector)) { if (isDisplaySizeSettingEnabled(mInjector)) {
screen.addPreference(updateSizePreference(context)); adder.accept(updateSizePreference(context));
} }
} }
@@ -508,23 +528,28 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
private void showDisplaysList(@NonNull List<Display> displaysToShow, private void showDisplaysList(@NonNull List<Display> displaysToShow,
@NonNull PrefRefresh screen, @NonNull Context context) { @NonNull PrefRefresh screen, @NonNull Context context) {
maybeAddV2Components(context, screen); maybeAddV2Components(context, screen);
var displayGroupPref = getDisplaysListPreference(context); int order = PrefBasics.BUILTIN_DISPLAY_LIST.order;
if (!displaysToShow.isEmpty()) { for (var display : displaysToShow) {
screen.addPreference(displayGroupPref); var pref = getDisplayPreference(context, display, screen, ++order);
} pref.setSummary(display.getMode().getPhysicalWidth() + " x "
try (var groupCleanable = new PrefRefresh(displayGroupPref)) { + display.getMode().getPhysicalHeight());
for (var display : displaysToShow) {
var pref = getDisplayPreference(context, display, groupCleanable);
pref.setSummary(display.getMode().getPhysicalWidth() + " x "
+ display.getMode().getPhysicalHeight());
}
} }
} }
@VisibleForTesting
static String displayListDisplayCategoryKey(int displayId) {
return "display_list_display_category_" + displayId;
}
@VisibleForTesting
static String resolutionRotationPreferenceKey(int displayId) {
return "display_id_" + displayId;
}
private Preference getDisplayPreference(@NonNull Context context, private Preference getDisplayPreference(@NonNull Context context,
@NonNull Display display, @NonNull PrefRefresh groupCleanable) { @NonNull Display display, @NonNull PrefRefresh groupCleanable, int categoryOrder) {
var itemKey = "display_id_" + display.getDisplayId(); var itemKey = resolutionRotationPreferenceKey(display.getDisplayId());
var categoryKey = itemKey + "_category"; var categoryKey = displayListDisplayCategoryKey(display.getDisplayId());
var category = (PreferenceCategory) groupCleanable.findUnusedPreference(categoryKey); var category = (PreferenceCategory) groupCleanable.findUnusedPreference(categoryKey);
if (category != null) { if (category != null) {
@@ -534,6 +559,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
category = new PreferenceCategory(context); category = new PreferenceCategory(context);
category.setPersistent(false); category.setPersistent(false);
category.setKey(categoryKey); category.setKey(categoryKey);
category.setOrder(categoryOrder);
// Must add the category to the hierarchy before adding its descendants. Otherwise // Must add the category to the hierarchy before adding its descendants. Otherwise
// the category will not have a preference manager, which causes an exception when a // the category will not have a preference manager, which causes an exception when a
// child is added to it. // child is added to it.

View File

@@ -16,6 +16,7 @@
package com.android.settings.development; package com.android.settings.development;
import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController.A2DP_OFFLOAD_SUPPORTED_PROPERTY;
import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController.A2DP_OFFLOAD_DISABLED_PROPERTY; import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController.A2DP_OFFLOAD_DISABLED_PROPERTY;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
@@ -105,13 +106,14 @@ public class BluetoothLeAudioHwOffloadPreferenceController
(mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED); (mBluetoothAdapter.isLeAudioSupported() == BluetoothStatusCodes.FEATURE_SUPPORTED);
final boolean leAudioOffloadSupported = final boolean leAudioOffloadSupported =
SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false); SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, false);
final boolean a2dpOffloadDisabled = final boolean a2dpOffloadSupported =
SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false); SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
if (leAudioEnabled && leAudioOffloadSupported && !a2dpOffloadDisabled) {
((TwoStatePreference) mPreference).setChecked(true); if(!leAudioEnabled || !leAudioOffloadSupported || !a2dpOffloadSupported) {
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, "true");
} else {
mPreference.setEnabled(false); mPreference.setEnabled(false);
} else {
((TwoStatePreference) mPreference).setChecked(false);
SystemProperties.set(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, "false");
} }
} }

View File

@@ -98,7 +98,7 @@ public class DesktopExperiencePreferenceController extends DeveloperOptionsPrefe
@Override @Override
public CharSequence getSummary() { public CharSequence getSummary() {
if (DesktopModeStatus.isInternalDisplayEligibleToHostDesktops(mContext) if (DesktopModeStatus.isDeviceEligibleForDesktopMode(mContext)
&& !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()) { && !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()) {
return mContext.getString( return mContext.getString(
R.string.enable_desktop_experience_features_summary_with_desktop); R.string.enable_desktop_experience_features_summary_with_desktop);

View File

@@ -17,6 +17,7 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import android.content.Context; import android.content.Context;
import android.os.UserManager;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@@ -30,6 +31,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.SubscriptionUtil;
import com.android.settingslib.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -51,8 +53,13 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return SubscriptionUtil.isSimHardwareVisible(mContext) ? if (!SubscriptionUtil.isSimHardwareVisible(mContext) || Utils.isWifiOnly(mContext)) {
AVAILABLE : UNSUPPORTED_ON_DEVICE; return UNSUPPORTED_ON_DEVICE;
}
if (!mContext.getSystemService(UserManager.class).isAdminUser()) {
return DISABLED_FOR_USER;
}
return AVAILABLE;
} }
@Override @Override

View File

@@ -93,10 +93,10 @@ public class PowerUsageTimeController extends BasePreferenceController {
|| (summaryTimeMs == 0 && !TextUtils.equals(anomalyHintKey, preference.getKey()))) { || (summaryTimeMs == 0 && !TextUtils.equals(anomalyHintKey, preference.getKey()))) {
return false; return false;
} }
preference.setTimeTitle(mContext.getString(titleResId)); preference.setTitle(mContext.getString(titleResId));
preference.setTimeSummary(getPowerUsageTimeInfo(summaryTimeMs)); preference.setSummary(getPowerUsageTimeInfo(summaryTimeMs));
if (TextUtils.equals(anomalyHintKey, preference.getKey())) { if (TextUtils.equals(anomalyHintKey, preference.getKey())) {
preference.setAnomalyHint(anomalyHintText); preference.setHint(anomalyHintText);
} }
preference.setVisible(true); preference.setVisible(true);
return true; return true;

View File

@@ -17,74 +17,17 @@
package com.android.settings.fuelgauge; package com.android.settings.fuelgauge;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting; import com.android.settingslib.widget.GroupSectionDividerMixin;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
/** Custom preference for displaying the app power usage time. */ /** Custom preference for displaying the app power usage time. */
public class PowerUsageTimePreference extends Preference { public class PowerUsageTimePreference extends WarningFramePreference implements
GroupSectionDividerMixin {
private static final String TAG = "PowerUsageTimePreference"; private static final String TAG = "PowerUsageTimePreference";
@VisibleForTesting CharSequence mTimeTitle;
@VisibleForTesting CharSequence mTimeSummary;
@VisibleForTesting CharSequence mAnomalyHintText;
public PowerUsageTimePreference(Context context, AttributeSet attrs) { public PowerUsageTimePreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
setLayoutResource(R.layout.power_usage_time); setSelectable(false);
}
void setTimeTitle(CharSequence timeTitle) {
if (!TextUtils.equals(mTimeTitle, timeTitle)) {
mTimeTitle = timeTitle;
notifyChanged();
}
}
void setTimeSummary(CharSequence timeSummary) {
if (!TextUtils.equals(mTimeSummary, timeSummary)) {
mTimeSummary = timeSummary;
notifyChanged();
}
}
void setAnomalyHint(CharSequence anomalyHintText) {
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
mAnomalyHintText = anomalyHintText;
notifyChanged();
}
}
private void showAnomalyHint(PreferenceViewHolder view) {
if (TextUtils.isEmpty(mAnomalyHintText)) {
return;
}
final View anomalyHintView = view.findViewById(R.id.anomaly_hints);
if (anomalyHintView == null) {
return;
}
final TextView warningInfo = anomalyHintView.findViewById(R.id.warning_info);
if (warningInfo == null) {
return;
}
warningInfo.setText(mAnomalyHintText);
anomalyHintView.setVisibility(View.VISIBLE);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
((TextView) view.findViewById(R.id.time_title)).setText(mTimeTitle);
((TextView) view.findViewById(R.id.time_summary)).setText(mTimeSummary);
showAnomalyHint(view);
} }
} }

View File

@@ -0,0 +1,97 @@
/*
* 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.fuelgauge;
import android.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settingslib.Utils;
import com.android.settingslib.widget.SettingsThemeHelper;
/**
* Custom preference for displaying the {@link Preference} with an optional hint chip.
*/
public class WarningFramePreference extends Preference {
private final int mTitleColorNormal;
private final int mSummaryColorNormal;
private final int mWarningChipBackgroundResId;
private final boolean mIsExpressiveTheme;
@Nullable private CharSequence mHintText;
public WarningFramePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mIsExpressiveTheme = SettingsThemeHelper.isExpressiveTheme(context);
int layoutResId =
mIsExpressiveTheme
? R.layout.expressive_warning_frame_preference
: R.layout.warning_frame_preference;
setLayoutResource(layoutResId);
mWarningChipBackgroundResId =
mIsExpressiveTheme
? R.drawable.expressive_battery_hints_chip_bg_ripple
: R.drawable.battery_hints_chip_bg_ripple;
mTitleColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
mSummaryColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
}
/** Sets the text of hint to show. */
public void setHint(@Nullable CharSequence hintText) {
if (!TextUtils.equals(mHintText, hintText)) {
mHintText = hintText;
notifyChanged();
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
if (mIsExpressiveTheme) {
final View preferenceFrame = view.findViewById(R.id.preference_frame);
preferenceFrame.setBackground(null);
preferenceFrame.setPadding(0, 0, 0, 0);
}
final View warningChipFrame = view.findViewById(R.id.warning_chip_frame);
warningChipFrame
.findViewById(R.id.warning_padding_placeholder)
.setVisibility(getIcon() != null ? View.VISIBLE : View.GONE);
if (!TextUtils.isEmpty(mHintText)) {
((TextView) warningChipFrame.findViewById(R.id.warning_info)).setText(mHintText);
warningChipFrame.setVisibility(View.VISIBLE);
warningChipFrame
.findViewById(R.id.warning_chip)
.setBackgroundResource(mWarningChipBackgroundResId);
} else {
warningChipFrame.setVisibility(View.GONE);
}
((TextView) view.findViewById(android.R.id.title)).setTextColor(mTitleColorNormal);
((TextView) view.findViewById(android.R.id.summary)).setTextColor(mSummaryColorNormal);
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2023 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.fuelgauge.batteryusage;
import android.annotation.Nullable;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
class AnomalyAppItemPreference extends PowerGaugePreference {
private static final String TAG = "AnomalyAppItemPreference";
private CharSequence mAnomalyHintText;
AnomalyAppItemPreference(Context context) {
super(context, /* attrs */ null);
setLayoutResource(R.layout.anomaly_app_item_preference);
}
void setAnomalyHint(@Nullable CharSequence anomalyHintText) {
if (!TextUtils.equals(mAnomalyHintText, anomalyHintText)) {
mAnomalyHintText = anomalyHintText;
notifyChanged();
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder viewHolder) {
super.onBindViewHolder(viewHolder);
final LinearLayout warningChipView =
(LinearLayout) viewHolder.findViewById(R.id.warning_chip);
if (!TextUtils.isEmpty(mAnomalyHintText)) {
((TextView) warningChipView.findViewById(R.id.warning_info)).setText(mAnomalyHintText);
warningChipView.setVisibility(View.VISIBLE);
} else {
warningChipView.setVisibility(View.GONE);
}
}
}

View File

@@ -381,15 +381,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
continue; continue;
} }
final String prefKey = entry.getKey(); final String prefKey = entry.getKey();
AnomalyAppItemPreference preference = mRootPreferenceGroup.findPreference(prefKey); PowerGaugePreference preference = mRootPreferenceGroup.findPreference(prefKey);
if (preference != null) { if (preference != null) {
isAdded = true; isAdded = true;
} else { } else {
preference = (AnomalyAppItemPreference) mPreferenceCache.get(prefKey); preference = (PowerGaugePreference) mPreferenceCache.get(prefKey);
} }
// Creates new instance if cached preference is not found. // Creates new instance if cached preference is not found.
if (preference == null) { if (preference == null) {
preference = new AnomalyAppItemPreference(mPrefContext); preference = new PowerGaugePreference(mPrefContext);
preference.setKey(prefKey); preference.setKey(prefKey);
mPreferenceCache.put(prefKey, preference); mPreferenceCache.put(prefKey, preference);
} }
@@ -398,7 +398,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
preference.setOrder(++preferenceOrder); preference.setOrder(++preferenceOrder);
preference.setSingleLineTitle(true); preference.setSingleLineTitle(true);
// Updates App item preference style // Updates App item preference style
preference.setAnomalyHint(isAnomalyBatteryDiffEntry(entry) ? mAnomalyHintString : null); preference.setHint(isAnomalyBatteryDiffEntry(entry) ? mAnomalyHintString : null);
// Sets the BatteryDiffEntry to preference for launching detailed page. // Sets the BatteryDiffEntry to preference for launching detailed page.
preference.setBatteryDiffEntry(entry); preference.setBatteryDiffEntry(entry);
preference.setSelectable(entry.validForRestriction()); preference.setSelectable(entry.validForRestriction());

View File

@@ -28,7 +28,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settingslib.widget.AppPreference; import com.android.settings.fuelgauge.WarningFramePreference;
/** /**
* Custom preference for displaying battery usage info as a bar and an icon on the left for the * Custom preference for displaying battery usage info as a bar and an icon on the left for the
@@ -37,7 +37,7 @@ import com.android.settingslib.widget.AppPreference;
* <p>The battery usage info could be usage percentage or usage time. The preference won't show any * <p>The battery usage info could be usage percentage or usage time. The preference won't show any
* icon if it is null. * icon if it is null.
*/ */
public class PowerGaugePreference extends AppPreference { public class PowerGaugePreference extends WarningFramePreference {
// Please see go/battery-usage-app-list-alpha // Please see go/battery-usage-app-list-alpha
private static final float SELECTABLE_ALPHA = 1f; private static final float SELECTABLE_ALPHA = 1f;
@@ -51,7 +51,6 @@ public class PowerGaugePreference extends AppPreference {
private CharSequence mContentDescription; private CharSequence mContentDescription;
private CharSequence mProgress; private CharSequence mProgress;
private CharSequence mProgressContentDescription; private CharSequence mProgressContentDescription;
private boolean mShowAnomalyIcon;
public PowerGaugePreference( public PowerGaugePreference(
Context context, Drawable icon, CharSequence contentDescription, BatteryEntry info) { Context context, Drawable icon, CharSequence contentDescription, BatteryEntry info) {
@@ -79,7 +78,6 @@ public class PowerGaugePreference extends AppPreference {
setWidgetLayoutResource(R.layout.preference_widget_summary); setWidgetLayoutResource(R.layout.preference_widget_summary);
mInfo = info; mInfo = info;
mContentDescription = contentDescription; mContentDescription = contentDescription;
mShowAnomalyIcon = false;
mTitleColorNormal = mTitleColorNormal =
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary); Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
} }
@@ -108,17 +106,6 @@ public class PowerGaugePreference extends AppPreference {
return mProgress.toString(); return mProgress.toString();
} }
/** Sets whether to show anomaly icon */
public void shouldShowAnomalyIcon(boolean showAnomalyIcon) {
mShowAnomalyIcon = showAnomalyIcon;
notifyChanged();
}
/** Gets whether to show anomaly icon */
public boolean showAnomalyIcon() {
return mShowAnomalyIcon;
}
public void setBatteryDiffEntry(BatteryDiffEntry entry) { public void setBatteryDiffEntry(BatteryDiffEntry entry) {
mBatteryDiffEntry = entry; mBatteryDiffEntry = entry;
} }
@@ -149,12 +136,6 @@ public class PowerGaugePreference extends AppPreference {
if (!TextUtils.isEmpty(mProgressContentDescription)) { if (!TextUtils.isEmpty(mProgressContentDescription)) {
subtitle.setContentDescription(mProgressContentDescription); subtitle.setContentDescription(mProgressContentDescription);
} }
if (mShowAnomalyIcon) {
subtitle.setCompoundDrawablesRelativeWithIntrinsicBounds(
R.drawable.ic_warning_24dp, 0, 0, 0);
} else {
subtitle.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
}
if (mContentDescription != null) { if (mContentDescription != null) {
final TextView titleView = (TextView) view.findViewById(android.R.id.title); final TextView titleView = (TextView) view.findViewById(android.R.id.title);
titleView.setContentDescription(mContentDescription); titleView.setContentDescription(mContentDescription);

View File

@@ -16,7 +16,6 @@
package com.android.settings.homepage.contextualcards.conditional; package com.android.settings.homepage.contextualcards.conditional;
import android.app.Flags;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -87,12 +86,8 @@ public class DndConditionCardController implements ConditionalCardController {
@Override @Override
public void onActionClick() { public void onActionClick() {
if (Flags.modesApi()) { mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG,
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG, /* fromUser= */ true);
/* fromUser= */ true);
} else {
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG);
}
} }
@Override @Override

View File

@@ -29,19 +29,20 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher; import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import com.android.internal.app.LocaleStore; import com.android.internal.app.LocaleStore;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.CustomDialogHelper;
/** /**
* Create a dialog for system locale events. * Create a dialog for system locale events.
@@ -58,7 +59,6 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
static final String ARG_SHOW_DIALOG = "arg_show_dialog"; static final String ARG_SHOW_DIALOG = "arg_show_dialog";
private boolean mShouldKeepDialog; private boolean mShouldKeepDialog;
private AlertDialog mAlertDialog;
private OnBackInvokedDispatcher mBackDispatcher; private OnBackInvokedDispatcher mBackDispatcher;
private OnBackInvokedCallback mBackCallback = () -> { private OnBackInvokedCallback mBackCallback = () -> {
@@ -106,45 +106,53 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment(); LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment();
LocaleDialogController controller = getLocaleDialogController(getContext(), this, LocaleDialogController controller = getLocaleDialogController(getContext(), this,
parentFragment); parentFragment);
LocaleDialogController.DialogContent dialogContent = controller.getDialogContent(); Dialog dialog = createDialog(getContext(), controller);
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate( dialog.setCanceledOnTouchOutside(false);
R.layout.locale_dialog, null); getOnBackInvokedDispatcher(dialog).registerOnBackInvokedCallback(PRIORITY_DEFAULT,
setDialogTitle(viewGroup, dialogContent.mTitle); mBackCallback);
setDialogMessage(viewGroup, dialogContent.mMessage); dialog.setOnDismissListener(dialogInterface -> {
getOnBackInvokedDispatcher(dialog).unregisterOnBackInvokedCallback(
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()) mBackCallback);
.setView(viewGroup);
if (!dialogContent.mPositiveButton.isEmpty()) {
builder.setPositiveButton(dialogContent.mPositiveButton, controller);
}
if (!dialogContent.mNegativeButton.isEmpty()) {
builder.setNegativeButton(dialogContent.mNegativeButton, controller);
}
mAlertDialog = builder.create();
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(PRIORITY_DEFAULT, mBackCallback);
mAlertDialog.setCanceledOnTouchOutside(false);
mAlertDialog.setOnDismissListener(dialogInterface -> {
mAlertDialog.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
mBackCallback);
}); });
return mAlertDialog; return dialog;
} }
private static void setDialogTitle(View root, String content) { private Dialog createDialog(Context context, LocaleDialogController controller) {
TextView titleView = root.findViewById(R.id.dialog_title); CustomDialogHelper dialogHelper = new CustomDialogHelper(context);
if (titleView == null) { LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
return; dialogHelper.setIcon(context.getDrawable(R.drawable.ic_settings_language_32dp))
.setTitle(dialogContent.mTitle)
.setMessage(dialogContent.mMessage)
.setIconPadding(0,
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_icon_padding),
0, 0)
.setTitlePadding(0,
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_title_padding),
0,
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_title_padding))
.setMessagePadding(context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_message_padding_left_right), 0,
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_message_padding_left_right),
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_message_padding_bottom))
.setPositiveButton(dialogContent.mPositiveButton,
view -> {
controller.onClick(dialogHelper.getDialog(),
DialogInterface.BUTTON_POSITIVE);
dialogHelper.getDialog().dismiss();
});
if (dialogContent.mNegativeButton != 0) {
dialogHelper.setBackButton(dialogContent.mNegativeButton, view -> {
controller.onClick(dialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE);
dialogHelper.getDialog().dismiss();
});
} }
titleView.setText(content); return dialogHelper.getDialog();
}
private static void setDialogMessage(View root, String content) {
TextView textView = root.findViewById(R.id.dialog_msg);
if (textView == null) {
return;
}
textView.setText(content);
} }
@VisibleForTesting @VisibleForTesting
@@ -158,11 +166,11 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
} }
@VisibleForTesting @VisibleForTesting
public OnBackInvokedDispatcher getOnBackInvokedDispatcher() { public @NonNull OnBackInvokedDispatcher getOnBackInvokedDispatcher(@NonNull Dialog dialog) {
if (mBackDispatcher != null) { if (mBackDispatcher != null) {
return mBackDispatcher; return mBackDispatcher;
} else { } else {
return mAlertDialog.getOnBackInvokedDispatcher(); return dialog.getOnBackInvokedDispatcher();
} }
} }
@@ -223,15 +231,15 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
R.string.title_change_system_locale), mLocaleInfo.getFullNameNative()); R.string.title_change_system_locale), mLocaleInfo.getFullNameNative());
dialogContent.mMessage = mContext.getString( dialogContent.mMessage = mContext.getString(
R.string.desc_notice_device_locale_settings_change); R.string.desc_notice_device_locale_settings_change);
dialogContent.mPositiveButton = mContext.getString( dialogContent.mPositiveButton =
R.string.button_label_confirmation_of_system_locale_change); R.string.button_label_confirmation_of_system_locale_change;
dialogContent.mNegativeButton = mContext.getString(R.string.cancel); dialogContent.mNegativeButton = R.string.cancel;
break; break;
case DIALOG_NOT_AVAILABLE_LOCALE: case DIALOG_NOT_AVAILABLE_LOCALE:
dialogContent.mTitle = String.format(mContext.getString( dialogContent.mTitle = String.format(mContext.getString(
R.string.title_unavailable_locale), mLocaleInfo.getFullNameNative()); R.string.title_unavailable_locale), mLocaleInfo.getFullNameNative());
dialogContent.mMessage = mContext.getString(R.string.desc_unavailable_locale); dialogContent.mMessage = mContext.getString(R.string.desc_unavailable_locale);
dialogContent.mPositiveButton = mContext.getString(R.string.okay); dialogContent.mPositiveButton = R.string.okay;
break; break;
case DIALOG_ADD_SYSTEM_LOCALE: case DIALOG_ADD_SYSTEM_LOCALE:
dialogContent.mTitle = String.format(mContext.getString( dialogContent.mTitle = String.format(mContext.getString(
@@ -239,8 +247,8 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
mLocaleInfo.getFullNameNative()); mLocaleInfo.getFullNameNative());
dialogContent.mMessage = mContext.getString( dialogContent.mMessage = mContext.getString(
R.string.desc_system_locale_addition); R.string.desc_system_locale_addition);
dialogContent.mPositiveButton = mContext.getString(R.string.add); dialogContent.mPositiveButton = R.string.add;
dialogContent.mNegativeButton = mContext.getString(R.string.cancel); dialogContent.mNegativeButton = R.string.cancel;
break; break;
default: default:
break; break;
@@ -252,8 +260,8 @@ public class LocaleDialogFragment extends InstrumentedDialogFragment {
static class DialogContent { static class DialogContent {
String mTitle = ""; String mTitle = "";
String mMessage = ""; String mMessage = "";
String mPositiveButton = ""; int mPositiveButton = 0;
String mNegativeButton = ""; int mNegativeButton = 0;
} }
} }
} }

View File

@@ -43,9 +43,10 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -53,10 +54,12 @@ import com.android.internal.app.LocalePicker;
import com.android.internal.app.LocaleStore; import com.android.internal.app.LocaleStore;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment; import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.flags.Flags;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.utils.CustomDialogHelper;
import com.android.settingslib.utils.StringUtil; import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.widget.LayoutPreference; import com.android.settingslib.widget.LayoutPreference;
@@ -69,6 +72,8 @@ import java.util.Locale;
*/ */
@SearchIndexable @SearchIndexable
public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener { public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener {
public static final int REQUEST_LOCALE_PICKER = 0;
protected static final String INTENT_LOCALE_KEY = "localeInfo"; protected static final String INTENT_LOCALE_KEY = "localeInfo";
protected static final String EXTRA_SYSTEM_LOCALE_DIALOG_TYPE = "system_locale_dialog_type"; protected static final String EXTRA_SYSTEM_LOCALE_DIALOG_TYPE = "system_locale_dialog_type";
protected static final String EXTRA_RESULT_LOCALE = "result_locale"; protected static final String EXTRA_RESULT_LOCALE = "result_locale";
@@ -81,16 +86,16 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
private static final String INDEX_KEY_ADD_LANGUAGE = "add_language"; private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
private static final String KEY_LANGUAGES_PICKER = "languages_picker"; private static final String KEY_LANGUAGES_PICKER = "languages_picker";
private static final String KEY_CATEGORY_TERMS_OF_ADDRESS = "key_category_terms_of_address"; private static final String KEY_CATEGORY_TERMS_OF_ADDRESS = "key_category_terms_of_address";
private static final String KEY_ADD_A_LANGUAGE = "add_a_language";
private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default"; private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale"; private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
private static final String TAG_DIALOG_ADD_SYSTEM_LOCALE = "dialog_add_system_locale"; private static final String TAG_DIALOG_ADD_SYSTEM_LOCALE = "dialog_add_system_locale";
private static final int MENU_ID_REMOVE = Menu.FIRST + 1; private static final int MENU_ID_REMOVE = Menu.FIRST + 1;
private static final int REQUEST_LOCALE_PICKER = 0;
private LocaleDragAndDropAdapter mAdapter; private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu; private Menu mMenu;
private View mAddLanguage; private View mAddLanguage;
private AlertDialog mSuggestionDialog = null; private Preference mAddLanguagePreference;
private boolean mRemoveMode; private boolean mRemoveMode;
private boolean mShowingRemoveDialog; private boolean mShowingRemoveDialog;
private boolean mLocaleAdditionMode = false; private boolean mLocaleAdditionMode = false;
@@ -281,7 +286,11 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
private void setRemoveMode(boolean mRemoveMode) { private void setRemoveMode(boolean mRemoveMode) {
this.mRemoveMode = mRemoveMode; this.mRemoveMode = mRemoveMode;
mAdapter.setRemoveMode(mRemoveMode); mAdapter.setRemoveMode(mRemoveMode);
mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE); if (Flags.settingsExpressiveDesignEnabled()) {
mAddLanguagePreference.setVisible(!mRemoveMode);
} else {
mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE);
}
updateVisibilityOfRemoveMenu(); updateVisibilityOfRemoveMenu();
} }
@@ -330,7 +339,6 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
private void showDialogForAddedLocale() { private void showDialogForAddedLocale() {
Log.d(TAG, "show confirmation dialog"); Log.d(TAG, "show confirmation dialog");
Intent intent = this.getIntent(); Intent intent = this.getIntent();
String dialogType = intent.getStringExtra(EXTRA_SYSTEM_LOCALE_DIALOG_TYPE);
String appLocaleTag = intent.getStringExtra(EXTRA_APP_LOCALE); String appLocaleTag = intent.getStringExtra(EXTRA_APP_LOCALE);
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo( LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(
@@ -344,17 +352,6 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
localeDialogFragment.show(mFragmentManager, TAG_DIALOG_ADD_SYSTEM_LOCALE); localeDialogFragment.show(mFragmentManager, TAG_DIALOG_ADD_SYSTEM_LOCALE);
} }
private void customizeLayout(AlertDialog.Builder dialogBuilder, String language) {
View dialogView = getLocaleDialogView();
dialogBuilder.setView(dialogView);
TextView title = dialogView.findViewById(R.id.dialog_title);
title.setText(
String.format(getContext().getResources().getString(
R.string.title_system_locale_addition), language));
TextView message = dialogView.findViewById(R.id.dialog_msg);
message.setText(R.string.desc_system_locale_addition);
}
protected View getLocaleDialogView() { protected View getLocaleDialogView() {
LayoutInflater inflater = this.getLayoutInflater(); LayoutInflater inflater = this.getLayoutInflater();
return inflater.inflate(R.layout.locale_dialog, null); return inflater.inflate(R.layout.locale_dialog, null);
@@ -374,25 +371,33 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
return; return;
} }
int messagePaddingLeftRight = getContext().getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_message_padding_left_right);
int messagePaddingBottom = getContext().getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_message_padding_bottom);
// All locales selected, warning dialog, can't remove them all // All locales selected, warning dialog, can't remove them all
if (checkedCount == mAdapter.getItemCount()) { if (checkedCount == mAdapter.getItemCount()) {
mShowingRemoveDialog = true; mShowingRemoveDialog = true;
new AlertDialog.Builder(getActivity())
.setTitle(R.string.dlg_remove_locales_error_title) CustomDialogHelper dialogHelper = createRegionDialog(getContext(),
.setMessage(R.string.dlg_remove_locales_error_message) getContext().getString(R.string.dlg_remove_locales_error_title));
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { dialogHelper.setMessage(R.string.dlg_remove_locales_error_message)
@Override .setMessagePadding(messagePaddingLeftRight, 0, messagePaddingLeftRight,
public void onClick(DialogInterface dialog, int which) { messagePaddingBottom)
} .setPositiveButton(android.R.string.ok,
}) view -> {
.setOnDismissListener(new DialogInterface.OnDismissListener() { dialogHelper.getDialog().dismiss();
@Override })
public void onDismiss(DialogInterface dialog) { .setBackButton(R.string.cancel, view -> {
mShowingRemoveDialog = false; dialogHelper.getDialog().dismiss();
} });
}) dialogHelper.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
.create() @Override
.show(); public void onDismiss(@NonNull DialogInterface dialog) {
mShowingRemoveDialog = false;
}
});
dialogHelper.getDialog().show();
return; return;
} }
@@ -400,54 +405,63 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
R.string.dlg_remove_locales_title); R.string.dlg_remove_locales_title);
mShowingRemoveDialog = true; mShowingRemoveDialog = true;
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); CustomDialogHelper dialogHelper = createRegionDialog(getContext(), title);
if (mAdapter.isFirstLocaleChecked()) { if (mAdapter.isFirstLocaleChecked()) {
builder.setMessage(R.string.dlg_remove_locales_message); dialogHelper.setMessage(R.string.dlg_remove_locales_message)
.setMessagePadding(messagePaddingLeftRight, 0, messagePaddingLeftRight,
messagePaddingBottom);
} }
builder.setTitle(title) dialogHelper.setPositiveButton(R.string.locale_remove_menu,
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { view -> {
@Override // This is a sensitive area to change.
public void onClick(DialogInterface dialog, int which) { // removeChecked() triggers a system update and "kills" the frame.
setRemoveMode(false); // This means that saveState + restoreState are called before
} // setRemoveMode is called.
}) // So we want that mRemoveMode and dialog status have the right
.setPositiveButton(R.string.locale_remove_menu, // values
new DialogInterface.OnClickListener() { // before that save.
@Override // We can't just call setRemoveMode(false) before calling
public void onClick(DialogInterface dialog, int which) { // removeCheched
// This is a sensitive area to change. // because that unchecks all items and removeChecked would have
// removeChecked() triggers a system update and "kills" the frame. // nothing
// This means that saveState + restoreState are called before // to remove.
// setRemoveMode is called. mRemoveMode = false;
// So we want that mRemoveMode and dialog status have the right mShowingRemoveDialog = false;
// values LocaleStore.LocaleInfo firstLocale =
// before that save. mAdapter.getFeedItemList().get(0);
// We can't just call setRemoveMode(false) before calling mAdapter.removeChecked();
// removeCheched boolean isFirstRemoved =
// because that unchecks all items and removeChecked would have firstLocale != mAdapter.getFeedItemList().get(0);
// nothing showConfirmDialog(isFirstRemoved, isFirstRemoved ? firstLocale
// to remove. : mAdapter.getFeedItemList().get(0));
mRemoveMode = false; setRemoveMode(false);
mShowingRemoveDialog = false; dialogHelper.getDialog().dismiss();
LocaleStore.LocaleInfo firstLocale =
mAdapter.getFeedItemList().get(0);
mAdapter.removeChecked();
boolean isFirstRemoved =
firstLocale != mAdapter.getFeedItemList().get(0);
showConfirmDialog(isFirstRemoved, isFirstRemoved ? firstLocale
: mAdapter.getFeedItemList().get(0));
setRemoveMode(false);
}
}) })
.setOnDismissListener(new DialogInterface.OnDismissListener() { .setBackButton(R.string.cancel, view -> {
@Override setRemoveMode(false);
public void onDismiss(DialogInterface dialog) { dialogHelper.getDialog().dismiss();
mShowingRemoveDialog = false; });
} dialogHelper.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
}) @Override
.create() public void onDismiss(@NonNull DialogInterface dialog) {
.show(); mShowingRemoveDialog = false;
}
});
dialogHelper.getDialog().show();
}
private CustomDialogHelper createRegionDialog(Context context, String title) {
CustomDialogHelper dialogHelper = new CustomDialogHelper(context);
dialogHelper.setIcon(context.getDrawable(R.drawable.ic_settings_language_32dp))
.setTitle(title)
.setIconPadding(0, context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_icon_padding), 0, 0)
.setTitlePadding(0, context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_title_padding), 0,
context.getResources().getDimensionPixelSize(
R.dimen.locale_picker_dialog_title_padding));
return dialogHelper;
} }
@Override @Override
@@ -483,20 +497,23 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
list.setAdapter(mAdapter); list.setAdapter(mAdapter);
list.setOnTouchListener(this); list.setOnTouchListener(this);
list.requestFocus(); list.requestFocus();
if (Flags.settingsExpressiveDesignEnabled()) {
mAddLanguagePreference = getPreferenceScreen().findPreference(KEY_ADD_A_LANGUAGE);
} else {
mAddLanguage = layout.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(@NonNull View v) {
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.logSettingsTileClick(INDEX_KEY_ADD_LANGUAGE, getMetricsCategory());
mAddLanguage = layout.findViewById(R.id.add_language); final Intent intent = new Intent(getActivity(),
mAddLanguage.setOnClickListener(new View.OnClickListener() { LocalePickerWithRegionActivity.class);
@Override intent.putExtras(getActivity().getIntent().getExtras());
public void onClick(View v) { startActivityForResult(intent, REQUEST_LOCALE_PICKER);
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider() }
.logSettingsTileClick(INDEX_KEY_ADD_LANGUAGE, getMetricsCategory()); });
}
final Intent intent = new Intent(getActivity(),
LocalePickerWithRegionActivity.class);
intent.putExtras(getActivity().getIntent().getExtras());
startActivityForResult(intent, REQUEST_LOCALE_PICKER);
}
});
} }
@Override @Override

View File

@@ -75,9 +75,6 @@ public abstract class LocalePickerBaseListPreferenceController extends
public LocalePickerBaseListPreferenceController(@NonNull Context context, public LocalePickerBaseListPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) { @NonNull String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
mLocaleList = getLocaleCollectorController(context).getSupportedLocaleList(null,
false, false);
mLocaleOptions = new ArrayList<>(mLocaleList.size());
mPreferences = new ArrayMap<>(); mPreferences = new ArrayMap<>();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
} }
@@ -246,7 +243,7 @@ public abstract class LocalePickerBaseListPreferenceController extends
private void setupLocaleList() { private void setupLocaleList() {
mLocaleList = getLocaleCollectorController(mContext).getSupportedLocaleList( mLocaleList = getLocaleCollectorController(mContext).getSupportedLocaleList(
mParentLocale, false, mIsCountryMode); mParentLocale, false, mIsCountryMode);
mLocaleOptions.clear(); mLocaleOptions = new ArrayList<>(mLocaleList.size());
} }
private List<LocaleStore.LocaleInfo> getSortedLocaleList( private List<LocaleStore.LocaleInfo> getSortedLocaleList(
@@ -262,7 +259,9 @@ public abstract class LocalePickerBaseListPreferenceController extends
boolean shouldShowLocaleEditor = shouldShowLocaleEditor(localeInfo); boolean shouldShowLocaleEditor = shouldShowLocaleEditor(localeInfo);
if (shouldShowLocaleEditor) { if (shouldShowLocaleEditor) {
List<LocaleStore.LocaleInfo> feedItemList = getUserLocaleList(); List<LocaleStore.LocaleInfo> feedItemList = getUserLocaleList();
feedItemList.add(localeInfo); for (LocaleStore.LocaleInfo locale : mLocaleList) {
feedItemList.add(locale);
}
LocaleList localeList = new LocaleList(feedItemList.stream() LocaleList localeList = new LocaleList(feedItemList.stream()
.map(LocaleStore.LocaleInfo::getLocale) .map(LocaleStore.LocaleInfo::getLocale)
.toArray(Locale[]::new)); .toArray(Locale[]::new));

View File

@@ -23,14 +23,12 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivitySettingsManager; import android.net.ConnectivitySettingsManager;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.provider.Settings;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
@@ -55,6 +53,7 @@ import com.android.settingslib.HelpUtils;
import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.material.textfield.TextInputLayout;
import com.google.common.net.InternetDomainName; import com.google.common.net.InternetDomainName;
import java.util.HashMap; import java.util.HashMap;
@@ -64,7 +63,7 @@ import java.util.Map;
* Dialog to set the Private DNS * Dialog to set the Private DNS
*/ */
public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat implements public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat implements
DialogInterface.OnClickListener, RadioGroup.OnCheckedChangeListener, TextWatcher { RadioGroup.OnCheckedChangeListener, TextWatcher {
public static final String ANNOTATION_URL = "url"; public static final String ANNOTATION_URL = "url";
@@ -80,16 +79,9 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat
} }
@VisibleForTesting @VisibleForTesting
static final String MODE_KEY = Settings.Global.PRIVATE_DNS_MODE; TextInputLayout mHostnameLayout;
@VisibleForTesting @VisibleForTesting
static final String HOSTNAME_KEY = Settings.Global.PRIVATE_DNS_SPECIFIER; EditText mHostnameText;
public static String getHostnameFromSettings(ContentResolver cr) {
return Settings.Global.getString(cr, HOSTNAME_KEY);
}
@VisibleForTesting
EditText mEditText;
@VisibleForTesting @VisibleForTesting
RadioGroup mRadioGroup; RadioGroup mRadioGroup;
@VisibleForTesting @VisibleForTesting
@@ -136,22 +128,17 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat
// by the controller. // by the controller.
holder.itemView.setEnabled(true); holder.itemView.setEnabled(true);
} }
setSaveButtonListener();
} }
@Override @Override
protected void onBindDialogView(View view) { protected void onBindDialogView(View view) {
final Context context = getContext(); final Context context = getContext();
final ContentResolver contentResolver = context.getContentResolver();
mMode = ConnectivitySettingsManager.getPrivateDnsMode(context); mMode = ConnectivitySettingsManager.getPrivateDnsMode(context);
mEditText = view.findViewById(R.id.private_dns_mode_provider_hostname);
mEditText.addTextChangedListener(this);
mEditText.setText(getHostnameFromSettings(contentResolver));
mRadioGroup = view.findViewById(R.id.private_dns_radio_group); mRadioGroup = view.findViewById(R.id.private_dns_radio_group);
mRadioGroup.setOnCheckedChangeListener(this);
mRadioGroup.check(PRIVATE_DNS_MAP.getOrDefault(mMode, R.id.private_dns_mode_opportunistic)); mRadioGroup.check(PRIVATE_DNS_MAP.getOrDefault(mMode, R.id.private_dns_mode_opportunistic));
mRadioGroup.setOnCheckedChangeListener(this);
// Initial radio button text // Initial radio button text
final RadioButton offRadioButton = view.findViewById(R.id.private_dns_mode_off); final RadioButton offRadioButton = view.findViewById(R.id.private_dns_mode_off);
@@ -163,6 +150,13 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat
final RadioButton providerRadioButton = view.findViewById(R.id.private_dns_mode_provider); final RadioButton providerRadioButton = view.findViewById(R.id.private_dns_mode_provider);
providerRadioButton.setText(com.android.settingslib.R.string.private_dns_mode_provider); providerRadioButton.setText(com.android.settingslib.R.string.private_dns_mode_provider);
mHostnameLayout = view.findViewById(R.id.private_dns_mode_provider_hostname_layout);
mHostnameText = view.findViewById(R.id.private_dns_mode_provider_hostname);
if (mHostnameText != null) {
mHostnameText.setText(ConnectivitySettingsManager.getPrivateDnsHostname(context));
mHostnameText.addTextChangedListener(this);
}
final TextView helpTextView = view.findViewById(R.id.private_dns_help_info); final TextView helpTextView = view.findViewById(R.id.private_dns_help_info);
helpTextView.setMovementMethod(LinkMovementMethod.getInstance()); helpTextView.setMovementMethod(LinkMovementMethod.getInstance());
final Intent helpIntent = HelpUtils.getHelpIntent(context, final Intent helpIntent = HelpUtils.getHelpIntent(context,
@@ -176,22 +170,8 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat
} else { } else {
helpTextView.setText(""); helpTextView.setText("");
} }
}
@Override updateDialogInfo();
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
final Context context = getContext();
if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {
// Only clickable if hostname is valid, so we could save it safely
ConnectivitySettingsManager.setPrivateDnsHostname(context,
mEditText.getText().toString());
}
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(context,
SettingsEnums.ACTION_PRIVATE_DNS_MODE, mMode);
ConnectivitySettingsManager.setPrivateDnsMode(context, mMode);
}
} }
@Override @Override
@@ -241,24 +221,58 @@ public class PrivateDnsModeDialogPreference extends CustomDialogPreferenceCompat
return getEnforcedAdmin() != null; return getEnforcedAdmin() != null;
} }
private Button getSaveButton() {
final AlertDialog dialog = (AlertDialog) getDialog();
if (dialog == null) {
return null;
}
return dialog.getButton(DialogInterface.BUTTON_POSITIVE);
}
private void updateDialogInfo() { private void updateDialogInfo() {
final boolean modeProvider = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mMode; final boolean modeProvider = PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mMode;
if (mEditText != null) { if (mHostnameLayout != null) {
mEditText.setEnabled(modeProvider); mHostnameLayout.setEnabled(modeProvider);
} mHostnameLayout.setErrorEnabled(false);
final Button saveButton = getSaveButton();
if (saveButton != null) {
saveButton.setEnabled(modeProvider
? InternetDomainName.isValid(mEditText.getText().toString())
: true);
} }
} }
private void setSaveButtonListener() {
View.OnClickListener onClickListener = v -> doSaveButton();
DialogInterface.OnShowListener onShowListener = dialog -> {
if (dialog == null) {
Log.e(TAG, "The DialogInterface is null!");
return;
}
Button saveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
if (saveButton == null) {
Log.e(TAG, "Can't get the save button!");
return;
}
saveButton.setOnClickListener(onClickListener);
};
setOnShowListener(onShowListener);
}
@VisibleForTesting
void doSaveButton() {
Context context = getContext();
if (mMode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) {
if (mHostnameLayout == null || mHostnameText == null) {
Log.e(TAG, "Can't find hostname resources!");
return;
}
if (mHostnameText.getText().isEmpty()) {
mHostnameLayout.setError(context.getString(R.string.private_dns_field_require));
Log.w(TAG, "The hostname is empty!");
return;
}
if (!InternetDomainName.isValid(mHostnameText.getText().toString())) {
mHostnameLayout.setError(context.getString(R.string.private_dns_hostname_invalid));
Log.w(TAG, "The hostname is invalid!");
return;
}
ConnectivitySettingsManager.setPrivateDnsHostname(context,
mHostnameText.getText().toString());
}
ConnectivitySettingsManager.setPrivateDnsMode(context, mMode);
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(context, SettingsEnums.ACTION_PRIVATE_DNS_MODE, mMode);
getDialog().dismiss();
}
} }

View File

@@ -135,7 +135,7 @@ public class PrivateDnsPreferenceController extends BasePreferenceController
com.android.settingslib.R.string.private_dns_mode_opportunistic); com.android.settingslib.R.string.private_dns_mode_opportunistic);
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
return dnsesResolved return dnsesResolved
? PrivateDnsModeDialogPreference.getHostnameFromSettings(cr) ? ConnectivitySettingsManager.getPrivateDnsHostname(mContext)
: res.getString( : res.getString(
com.android.settingslib.R.string.private_dns_mode_provider_failure); com.android.settingslib.R.string.private_dns_mode_provider_failure);
} }

View File

@@ -107,8 +107,8 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
} }
final PersistableBundle carrierConfig = getCarrierConfigForSubId(subId); final PersistableBundle carrierConfig = getCarrierConfigForSubId(subId);
if ((carrierConfig == null) if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig) ||
|| carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL)) { carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL)) {
return CONDITIONALLY_UNAVAILABLE; return CONDITIONALLY_UNAVAILABLE;
} }

View File

@@ -25,6 +25,8 @@ import com.android.settings.R
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.framework.common.userManager
import com.android.settingslib.Utils
/** Preference controller for "Phone number" */ /** Preference controller for "Phone number" */
class MobileNetworkPhoneNumberPreferenceController class MobileNetworkPhoneNumberPreferenceController
@@ -41,13 +43,14 @@ constructor(
mSubId = subId mSubId = subId
} }
override fun getAvailabilityStatus(subId: Int): Int = override fun getAvailabilityStatus(subId: Int): Int = when {
when { !Flags.isDualSimOnboardingEnabled()
!Flags.isDualSimOnboardingEnabled() -> CONDITIONALLY_UNAVAILABLE || !SubscriptionManager.isValidSubscriptionId(subId)
SubscriptionManager.isValidSubscriptionId(subId) && || !SubscriptionUtil.isSimHardwareVisible(mContext)
SubscriptionUtil.isSimHardwareVisible(mContext) -> AVAILABLE || Utils.isWifiOnly(mContext) -> CONDITIONALLY_UNAVAILABLE
else -> CONDITIONALLY_UNAVAILABLE !mContext.userManager.isAdminUser -> DISABLED_FOR_USER
} else -> AVAILABLE
}
override fun displayPreference(screen: PreferenceScreen) { override fun displayPreference(screen: PreferenceScreen) {
super.displayPreference(screen) super.displayPreference(screen)

View File

@@ -59,7 +59,7 @@ abstract class AbstractZenModeHeaderController extends AbstractZenModePreference
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return Flags.modesApi() && Flags.modesUi(); return Flags.modesUi();
} }
protected void setUpHeader(PreferenceScreen screen, int iconSizePx) { protected void setUpHeader(PreferenceScreen screen, int iconSizePx) {

View File

@@ -43,7 +43,7 @@ class ZenSettingsObserver extends ContentObserver {
} }
void register() { void register() {
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this); mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false,
this); this);
@@ -51,7 +51,7 @@ class ZenSettingsObserver extends ContentObserver {
} }
void unregister() { void unregister() {
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
mContext.getContentResolver().unregisterContentObserver(this); mContext.getContentResolver().unregisterContentObserver(this);
} }
} }

View File

@@ -167,7 +167,7 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
mMetricsFeatureProvider.action(mContext, mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
AutomaticZenRule rule; AutomaticZenRule rule;
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
rule = new AutomaticZenRule.Builder(ruleName, mRuleInfo.defaultConditionId) rule = new AutomaticZenRule.Builder(ruleName, mRuleInfo.defaultConditionId)
.setType(mRuleInfo.type) .setType(mRuleInfo.type)
.setOwner(mRuleInfo.serviceComponent) .setOwner(mRuleInfo.serviceComponent)

View File

@@ -76,7 +76,7 @@ public class ZenAccessSettings extends EmptyTextSettings implements
@Override @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
setEmptyText(Flags.modesApi() && Flags.modesUi() setEmptyText(Flags.modesUi()
? R.string.zen_modes_access_empty_text ? R.string.zen_modes_access_empty_text
: R.string.zen_access_empty_text); : R.string.zen_access_empty_text);
} }
@@ -89,7 +89,7 @@ public class ZenAccessSettings extends EmptyTextSettings implements
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
requireActivity().setTitle(Flags.modesApi() && Flags.modesUi() requireActivity().setTitle(Flags.modesUi()
? R.string.manage_zen_modes_access_title ? R.string.manage_zen_modes_access_title
: R.string.manage_zen_access_title); : R.string.manage_zen_access_title);
reloadList(); reloadList();
@@ -145,7 +145,7 @@ public class ZenAccessSettings extends EmptyTextSettings implements
pref.setOnPreferenceClickListener(preference -> { pref.setOnPreferenceClickListener(preference -> {
AppInfoBase.startAppInfoFragment( AppInfoBase.startAppInfoFragment(
ZenAccessDetails.class /* fragment */, ZenAccessDetails.class /* fragment */,
getString(Flags.modesApi() && Flags.modesUi() getString(Flags.modesUi()
? R.string.manage_zen_modes_access_title ? R.string.manage_zen_modes_access_title
: R.string.manage_zen_access_title), : R.string.manage_zen_access_title),
pkg, pkg,

View File

@@ -95,32 +95,19 @@ public class ZenModeBackend {
} }
protected boolean updateZenRule(String id, AutomaticZenRule rule) { protected boolean updateZenRule(String id, AutomaticZenRule rule) {
if (android.app.Flags.modesApi()) { return mNotificationManager.updateAutomaticZenRule(id, rule, /* fromUser= */ true);
return mNotificationManager.updateAutomaticZenRule(id, rule, /* fromUser= */ true);
} else {
return NotificationManager.from(mContext).updateAutomaticZenRule(id, rule);
}
} }
protected void setZenMode(int zenMode) { protected void setZenMode(int zenMode) {
if (android.app.Flags.modesApi()) { mNotificationManager.setZenMode(zenMode, null, TAG, /* fromUser= */ true);
mNotificationManager.setZenMode(zenMode, null, TAG, /* fromUser= */ true);
} else {
NotificationManager.from(mContext).setZenMode(zenMode, null, TAG);
}
mZenMode = getZenMode(); mZenMode = getZenMode();
} }
protected void setZenModeForDuration(int minutes) { protected void setZenModeForDuration(int minutes) {
Uri conditionId = ZenModeConfig.toTimeCondition(mContext, minutes, Uri conditionId = ZenModeConfig.toTimeCondition(mContext, minutes,
ActivityManager.getCurrentUser(), true).id; ActivityManager.getCurrentUser(), true).id;
if (android.app.Flags.modesApi()) { mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, conditionId, TAG, /* fromUser= */ true);
conditionId, TAG, /* fromUser= */ true);
} else {
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
conditionId, TAG);
}
mZenMode = getZenMode(); mZenMode = getZenMode();
} }
@@ -190,14 +177,9 @@ public class ZenModeBackend {
int priorityConversationSenders) { int priorityConversationSenders) {
mPolicy = new NotificationManager.Policy(priorityCategories, priorityCallSenders, mPolicy = new NotificationManager.Policy(priorityCategories, priorityCallSenders,
priorityMessageSenders, suppressedVisualEffects, priorityConversationSenders); priorityMessageSenders, suppressedVisualEffects, priorityConversationSenders);
if (android.app.Flags.modesApi()) { mNotificationManager.setNotificationPolicy(mPolicy, /* fromUser= */ true);
mNotificationManager.setNotificationPolicy(mPolicy, /* fromUser= */ true);
} else {
mNotificationManager.setNotificationPolicy(mPolicy);
}
} }
private int getNewSuppressedEffects(boolean suppress, int effectType) { private int getNewSuppressedEffects(boolean suppress, int effectType) {
int effects = mPolicy.suppressedVisualEffects; int effects = mPolicy.suppressedVisualEffects;
@@ -373,11 +355,7 @@ public class ZenModeBackend {
} }
public boolean removeZenRule(String ruleId) { public boolean removeZenRule(String ruleId) {
if (android.app.Flags.modesApi()) { return mNotificationManager.removeAutomaticZenRule(ruleId, /* fromUser= */ true);
return mNotificationManager.removeAutomaticZenRule(ruleId, /* fromUser= */ true);
} else {
return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId);
}
} }
public NotificationManager.Policy getConsolidatedPolicy() { public NotificationManager.Policy getConsolidatedPolicy() {
@@ -386,11 +364,7 @@ public class ZenModeBackend {
protected String addZenRule(AutomaticZenRule rule) { protected String addZenRule(AutomaticZenRule rule) {
try { try {
if (android.app.Flags.modesApi()) { return mNotificationManager.addAutomaticZenRule(rule, /* fromUser= */ true);
return mNotificationManager.addAutomaticZenRule(rule, /* fromUser= */ true);
} else {
return NotificationManager.from(mContext).addAutomaticZenRule(rule);
}
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }

View File

@@ -104,16 +104,11 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(ZenCustomRuleSettings.RULE_ID, mId); bundle.putString(ZenCustomRuleSettings.RULE_ID, mId);
// When modes_api flag is on, we skip the radio button screen distinguishing // Skip the radio button screen distinguishing between "default" and
// between "default" and "custom" and take users directly to the custom // "custom" and take users directly to the custom settings screen.
// settings screen. // From ZenRuleCustomPolicyPreferenceController#launchCustomSettings
String destination = ZenCustomRuleSettings.class.getName(); String destination = ZenCustomRuleConfigSettings.class.getName();
int sourceMetricsCategory = 0; int sourceMetricsCategory = SettingsEnums.ZEN_CUSTOM_RULE_SOUND_SETTINGS;
if (Flags.modesApi()) {
// From ZenRuleCustomPolicyPreferenceController#launchCustomSettings
destination = ZenCustomRuleConfigSettings.class.getName();
sourceMetricsCategory = SettingsEnums.ZEN_CUSTOM_RULE_SOUND_SETTINGS;
}
new SubSettingLauncher(mContext) new SubSettingLauncher(mContext)
.setDestination(destination) .setDestination(destination)
.setArguments(bundle) .setArguments(bundle)
@@ -165,7 +160,7 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
protected void updateScheduleRule(ZenModeConfig.ScheduleInfo schedule) { protected void updateScheduleRule(ZenModeConfig.ScheduleInfo schedule) {
mRule.setConditionId(ZenModeConfig.toScheduleConditionId(schedule)); mRule.setConditionId(ZenModeConfig.toScheduleConditionId(schedule));
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
mRule.setTriggerDescription( mRule.setTriggerDescription(
SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, schedule)); SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, schedule));
} }
@@ -174,7 +169,7 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
protected void updateEventRule(ZenModeConfig.EventInfo event) { protected void updateEventRule(ZenModeConfig.EventInfo event) {
mRule.setConditionId(ZenModeConfig.toEventConditionId(event)); mRule.setConditionId(ZenModeConfig.toEventConditionId(event));
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
mRule.setTriggerDescription( mRule.setTriggerDescription(
SystemZenRules.getTriggerDescriptionForScheduleEvent(mContext, event)); SystemZenRules.getTriggerDescriptionForScheduleEvent(mContext, event));
} }

View File

@@ -19,7 +19,6 @@ package com.android.settings.notification.zen;
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
import android.annotation.ColorInt; import android.annotation.ColorInt;
import android.app.Flags;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
@@ -117,12 +116,8 @@ public class ZenModeSliceBuilder {
} else { } else {
zenMode = Settings.Global.ZEN_MODE_OFF; zenMode = Settings.Global.ZEN_MODE_OFF;
} }
if (Flags.modesApi()) { NotificationManager.from(context).setZenMode(zenMode, /* conditionId= */ null, TAG,
NotificationManager.from(context).setZenMode(zenMode, /* conditionId= */ null, TAG, /* fromUser= */ true);
/* fromUser= */ true);
} else {
NotificationManager.from(context).setZenMode(zenMode, null /* conditionId */, TAG);
}
// Do not notifyChange on Uri. The service takes longer to update the current value than it // Do not notifyChange on Uri. The service takes longer to update the current value than it
// does for the Slice to check the current value again. Let {@link SliceBroadcastRelay} // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
// handle it. // handle it.

View File

@@ -19,19 +19,14 @@ package com.android.settings.notification.zen;
import android.app.AutomaticZenRule; import android.app.AutomaticZenRule;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.ActionButtonsPreference; import com.android.settingslib.widget.ActionButtonsPreference;
@@ -87,7 +82,6 @@ public class ZenRuleButtonsPreferenceController extends AbstractZenModePreferenc
mMetricsFeatureProvider.action(mContext, mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK); SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
mRule.setName(ruleName); mRule.setName(ruleName);
mRule.setModified(true);
mBackend.updateZenRule(mId, mRule); mBackend.updateZenRule(mId, mRule);
} }
}); });

View File

@@ -143,8 +143,7 @@ public class ZenRulePreference extends PrimarySwitchPreference {
private String computeRuleSummary(AutomaticZenRule rule) { private String computeRuleSummary(AutomaticZenRule rule) {
if (rule != null) { if (rule != null) {
if (Flags.modesApi() && Flags.modesUi() if (Flags.modesUi() && !TextUtils.isEmpty(rule.getTriggerDescription())) {
&& !TextUtils.isEmpty(rule.getTriggerDescription())) {
return rule.getTriggerDescription(); return rule.getTriggerDescription();
} }

View File

@@ -181,7 +181,7 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
rt.title = mContext.getString(R.string.zen_schedule_rule_type_name); rt.title = mContext.getString(R.string.zen_schedule_rule_type_name);
rt.packageName = ZenModeConfig.getEventConditionProvider().getPackageName(); rt.packageName = ZenModeConfig.getEventConditionProvider().getPackageName();
rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule); rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule);
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
rt.type = AutomaticZenRule.TYPE_SCHEDULE_TIME; rt.type = AutomaticZenRule.TYPE_SCHEDULE_TIME;
rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleTime( rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleTime(
mContext, schedule); mContext, schedule);
@@ -201,7 +201,7 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
rt.title = mContext.getString(R.string.zen_event_rule_type_name); rt.title = mContext.getString(R.string.zen_event_rule_type_name);
rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName(); rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName();
rt.defaultConditionId = ZenModeConfig.toEventConditionId(event); rt.defaultConditionId = ZenModeConfig.toEventConditionId(event);
if (Flags.modesApi() && Flags.modesUi()) { if (Flags.modesUi()) {
rt.type = AutomaticZenRule.TYPE_SCHEDULE_CALENDAR; rt.type = AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleEvent( rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleEvent(
mContext, event); mContext, event);

View File

@@ -560,6 +560,7 @@ public class ChooseLockPassword extends SettingsActivity {
setupPasswordRequirementsView(headerLayout); setupPasswordRequirementsView(headerLayout);
mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity())); mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
mPasswordRestrictionView.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
mPasswordEntry = view.findViewById(R.id.password_entry); mPasswordEntry = view.findViewById(R.id.password_entry);
mPasswordEntry.setOnEditorActionListener(this); mPasswordEntry.setOnEditorActionListener(this);
mPasswordEntry.addTextChangedListener(this); mPasswordEntry.addTextChangedListener(this);
@@ -770,7 +771,7 @@ public class ChooseLockPassword extends SettingsActivity {
// If the stage changed, announce the header for accessibility. This // If the stage changed, announce the header for accessibility. This
// is a no-op when accessibility is disabled. // is a no-op when accessibility is disabled.
if (previousStage != stage) { if (previousStage != stage) {
mLayout.announceForAccessibility(mLayout.getHeaderText()); getActivity().setTitle(mLayout.getHeaderText());
} }
} }

View File

@@ -20,9 +20,9 @@ import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R; import com.android.settings.R;
@@ -66,15 +66,20 @@ public class PasswordRequirementAdapter extends
return mRequirements[position].hashCode(); return mRequirements[position].hashCode();
} }
@Override
public void onViewAttachedToWindow(@NonNull PasswordRequirementViewHolder holder) {
holder.mDescriptionText.announceForAccessibility(holder.mDescriptionText.getText());
}
@Override @Override
public void onBindViewHolder(PasswordRequirementViewHolder holder, int position) { public void onBindViewHolder(PasswordRequirementViewHolder holder, int position) {
final int fontSize = mContext.getResources().getDimensionPixelSize( final int fontSize = mContext.getResources().getDimensionPixelSize(
R.dimen.password_requirement_font_size); R.dimen.password_requirement_font_size);
final String requirement = mRequirements[position];
holder.mDescriptionText.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
holder.mDescriptionText.setStateDescription(requirement);
}
});
holder.mDescriptionText.setText(mRequirements[position]); holder.mDescriptionText.setText(mRequirements[position]);
if (mIsTooShortError) { if (mIsTooShortError) {
holder.mDescriptionText.setTextAppearance(R.style.ScreenLockPasswordHintTextFontStyle); holder.mDescriptionText.setTextAppearance(R.style.ScreenLockPasswordHintTextFontStyle);

View File

@@ -32,7 +32,7 @@ public class ShortcutsUpdateReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) { public void onReceive(@NonNull Context context, @NonNull Intent intent) {
if (!Flags.modesApi() || !Flags.modesUi()) { if (!Flags.modesUi()) {
return; return;
} }

View File

@@ -86,7 +86,7 @@ public class ShortcutsUpdater {
private static ComponentName maybeGetReplacingComponent(Context context, ComponentName cn) { private static ComponentName maybeGetReplacingComponent(Context context, ComponentName cn) {
// ZenModeSettingsActivity is replaced by ModesSettingsActivity and will be deleted // ZenModeSettingsActivity is replaced by ModesSettingsActivity and will be deleted
// soon (so we shouldn't use ZenModeSettingsActivity.class). // soon (so we shouldn't use ZenModeSettingsActivity.class).
if (Flags.modesApi() && Flags.modesUi() if (Flags.modesUi()
&& cn.getClassName().endsWith("Settings$ZenModeSettingsActivity")) { && cn.getClassName().endsWith("Settings$ZenModeSettingsActivity")) {
return new ComponentName(context, Settings.ModesSettingsActivity.class); return new ComponentName(context, Settings.ModesSettingsActivity.class);
} }

View File

@@ -33,7 +33,7 @@ public class TopLevelSoundPreferenceController extends BasePreferenceController
@Override @Override
public void updateState(Preference preference) { public void updateState(Preference preference) {
super.updateState(preference); super.updateState(preference);
preference.setSummary(Flags.modesApi() && Flags.modesUi() preference.setSummary(Flags.modesUi()
? R.string.sound_dashboard_summary ? R.string.sound_dashboard_summary
: R.string.sound_dashboard_summary_with_dnd); : R.string.sound_dashboard_summary_with_dnd);
} }

View File

@@ -68,9 +68,6 @@ public class ConnectedBluetoothDeviceUpdaterTest {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
private static final String TEST_EXCLUSIVE_MANAGER = "com.test.manager"; private static final String TEST_EXCLUSIVE_MANAGER = "com.test.manager";
private static final String TEMP_BOND_METADATA =
"<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
@Rule @Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -408,22 +405,6 @@ public class ConnectedBluetoothDeviceUpdaterTest {
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice); verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
} }
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
public void update_temporaryBondDevice_removePreference() {
setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
.thenReturn(TEMP_BOND_METADATA.getBytes());
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
}
private void setUpDeviceUpdaterWithAudioMode(int audioMode) { private void setUpDeviceUpdaterWithAudioMode(int audioMode) {
mAudioManager.setMode(audioMode); mAudioManager.setMode(audioMode);
mBluetoothDeviceUpdater = spy(new ConnectedBluetoothDeviceUpdater(mContext, mBluetoothDeviceUpdater = spy(new ConnectedBluetoothDeviceUpdater(mContext,

View File

@@ -75,7 +75,6 @@ public class ConnectedDeviceDashboardFragmentTest {
private static final String KEY_AUDIO_SHARING_SETTINGS = private static final String KEY_AUDIO_SHARING_SETTINGS =
"connected_device_audio_sharing_settings"; "connected_device_audio_sharing_settings";
private static final String KEY_ADD_BT_DEVICES = "add_bt_devices"; private static final String KEY_ADD_BT_DEVICES = "add_bt_devices";
private static final String KEY_TEMPORARY_BOND_DEVICES = "temp_bond_device_list";
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui"; private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
@@ -130,8 +129,7 @@ public class ConnectedDeviceDashboardFragmentTest {
KEY_SAVED_DEVICE_SEE_ALL, KEY_SAVED_DEVICE_SEE_ALL,
KEY_FAST_PAIR_DEVICE_SEE_ALL, KEY_FAST_PAIR_DEVICE_SEE_ALL,
KEY_AUDIO_SHARING_DEVICES, KEY_AUDIO_SHARING_DEVICES,
KEY_AUDIO_SHARING_SETTINGS, KEY_AUDIO_SHARING_SETTINGS);
KEY_TEMPORARY_BOND_DEVICES);
} }
@Test @Test

View File

@@ -43,7 +43,6 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.os.Looper; import android.os.Looper;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings; import android.provider.Settings;
import android.view.View; import android.view.View;
@@ -111,11 +110,8 @@ public class AudioSharingCallAudioPreferenceControllerTest {
private static final String PREF_KEY = "calls_and_alarms"; private static final String PREF_KEY = "calls_and_alarms";
private static final String TEST_DEVICE_NAME1 = "test1"; private static final String TEST_DEVICE_NAME1 = "test1";
private static final String TEST_DEVICE_NAME2 = "test2"; private static final String TEST_DEVICE_NAME2 = "test2";
private static final String TEMP_BOND_METADATA =
"<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private static final int TEST_DEVICE_GROUP_ID1 = 1; private static final int TEST_DEVICE_GROUP_ID1 = 1;
private static final int TEST_DEVICE_GROUP_ID2 = 2; private static final int TEST_DEVICE_GROUP_ID2 = 2;
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
private static final String TEST_SETTINGS_KEY = private static final String TEST_SETTINGS_KEY =
"bluetooth_le_broadcast_fallback_active_group_id"; "bluetooth_le_broadcast_fallback_active_group_id";
@@ -447,23 +443,6 @@ public class AudioSharingCallAudioPreferenceControllerTest {
assertThat(mPreference.getSummary().toString()).isEmpty(); assertThat(mPreference.getSummary().toString()).isEmpty();
} }
@Test
@EnableFlags(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
public void displayPreference_hasTemporaryBondDevice_doNotShow() {
Settings.Secure.putInt(mContentResolver, TEST_SETTINGS_KEY, TEST_DEVICE_GROUP_ID1);
when(mCachedDevice1.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
when(mBroadcast.isEnabled(any())).thenReturn(true);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice1, mDevice2));
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mState));
when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)).thenReturn(
TEMP_BOND_METADATA.getBytes());
mController.displayPreference(mScreen);
shadowOf(Looper.getMainLooper()).idle();
assertThat(mController.mGroupedConnectedDevices).hasSize(0);
}
@Test @Test
public void displayPreference_clickToShowCorrectDialog() { public void displayPreference_clickToShowCorrectDialog() {
AlertDialog latestAlertDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); AlertDialog latestAlertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();

View File

@@ -93,8 +93,14 @@ public class AudioSharingDialogFragmentTest {
private static final String METADATA_STR = private static final String METADATA_STR =
"BLUETOOTH:UUID:184F;BN:VGVzdA==;AT:1;AD:00A1A1A1A1A1;BI:1E240;BC:VGVzdENvZGU=;" "BLUETOOTH:UUID:184F;BN:VGVzdA==;AT:1;AD:00A1A1A1A1A1;BI:1E240;BC:VGVzdENvZGU=;"
+ "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;"; + "MD:BgNwVGVzdA==;AS:1;PI:A0;NS:1;BS:3;NB:2;SM:BQNUZXN0BARlbmc=;;";
private static final String METADATA_STR_NO_PASSWORD =
"BLUETOOTH:UUID:184F;BN:SG9ja2V5;AT:0;AD:AABBCC001122;BI:DE51E9;SQ:1;AS:1;PI:FFFF;"
+ "NS:1;BS:1;NB:1;;";
private static final BluetoothLeBroadcastMetadata METADATA = private static final BluetoothLeBroadcastMetadata METADATA =
BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(METADATA_STR); BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(METADATA_STR);
private static final BluetoothLeBroadcastMetadata METADATA_NO_PASSWORD =
BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(
METADATA_STR_NO_PASSWORD);
private Fragment mParent; private Fragment mParent;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
@@ -290,6 +296,50 @@ public class AudioSharingDialogFragmentTest {
assertThat(dialog.isShowing()).isFalse(); assertThat(dialog.isShowing()).isFalse();
} }
@Test
public void onCreateDialog_noExtraConnectedDevice_hasMetadataNoPassword_showCancelButton() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AtomicBoolean isCancelBtnClicked = new AtomicBoolean(false);
AudioSharingDialogFragment.show(
mParent,
new ArrayList<>(),
METADATA_NO_PASSWORD,
new AudioSharingDialogFragment.DialogEventListener() {
@Override
public void onCancelClick() {
isCancelBtnClicked.set(true);
}
},
TEST_EVENT_DATA_LIST);
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
ImageView image = dialog.findViewById(R.id.description_image);
assertThat(image).isNotNull();
TextView text = dialog.findViewById(R.id.description_text);
assertThat(text).isNotNull();
assertThat(METADATA_NO_PASSWORD).isNotNull();
assertThat(text.getText().toString()).isEqualTo(
mParent.getString(R.string.audio_sharing_dialog_qr_code_content_no_password,
METADATA_NO_PASSWORD.getBroadcastName()));
TextView textBottom = dialog.findViewById(R.id.description_text_2);
assertThat(textBottom).isNotNull();
assertThat(textBottom.getText().toString()).isEqualTo(
mParent.getString(R.string.audio_sharing_dialog_pair_new_device_content));
Button cancelBtn = dialog.findViewById(R.id.negative_btn);
assertThat(cancelBtn).isNotNull();
cancelBtn.performClick();
shadowMainLooper().idle();
verify(mFeatureFactory.metricsFeatureProvider)
.action(
any(Context.class),
eq(SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED),
eq(TEST_EVENT_DATA));
assertThat(isCancelBtnClicked.get()).isTrue();
assertThat(dialog.isShowing()).isFalse();
}
@Test @Test
public void onCreateDialog_flagOn_singleExtraConnectedDevice() { public void onCreateDialog_flagOn_singleExtraConnectedDevice() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);

View File

@@ -1,243 +0,0 @@
/*
* 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.connecteddevice.audiosharing;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
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 androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.bluetooth.Utils;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
/** Tests for {@link TemporaryBondDeviceGroupController}. */
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class
})
public class TemporaryBondDeviceGroupControllerTest {
private static final String KEY = "temp_bond_device_list";
private static final String PREFERENCE_KEY_1 = "pref_key_1";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private TemporaryBondDeviceGroupUpdater mBluetoothDeviceUpdater;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceManager mPreferenceManager;
@Mock
private LocalBluetoothManager mLocalBtManager;
@Mock
private BluetoothEventManager mEventManager;
@Mock private PreferenceScreen mScreen;
private PreferenceGroup mPreferenceGroup;
private Context mContext;
private Preference mPreference;
private TemporaryBondDeviceGroupController mTemporaryBondDeviceGroupController;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mPreference = new Preference(mContext);
mPreference.setKey(PREFERENCE_KEY_1);
mPreferenceGroup = spy(new PreferenceCategory(mContext));
when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
when(mScreen.getContext()).thenReturn(mContext);
when(mScreen.findPreference(KEY)).thenReturn(mPreferenceGroup);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
mLocalBtManager = Utils.getLocalBtManager(mContext);
when(mLocalBtManager.getEventManager()).thenReturn(mEventManager);
ShadowBluetoothAdapter shadowBluetoothAdapter = Shadow.extract(
BluetoothAdapter.getDefaultAdapter());
shadowBluetoothAdapter.setEnabled(true);
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mTemporaryBondDeviceGroupController = spy(new TemporaryBondDeviceGroupController(mContext));
mTemporaryBondDeviceGroupController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
mTemporaryBondDeviceGroupController.setPreferenceGroup(mPreferenceGroup);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onStart_flagOff_doNothing() {
mTemporaryBondDeviceGroupController.onStart(mLifecycleOwner);
verify(mEventManager, never()).registerCallback(any(BluetoothCallback.class));
verify(mBluetoothDeviceUpdater, never()).registerCallback();
verify(mBluetoothDeviceUpdater, never()).refreshPreference();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
public void onStart_audioSharingUINotAvailable_doNothing() {
mTemporaryBondDeviceGroupController.onStart(mLifecycleOwner);
verify(mEventManager, never()).registerCallback(any(BluetoothCallback.class));
verify(mBluetoothDeviceUpdater, never()).registerCallback();
verify(mBluetoothDeviceUpdater, never()).refreshPreference();
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI,
Flags.FLAG_ENABLE_LE_AUDIO_SHARING})
public void onStart_registerCallbacks() {
mTemporaryBondDeviceGroupController.onStart(mLifecycleOwner);
verify(mEventManager).registerCallback(any(BluetoothCallback.class));
verify(mBluetoothDeviceUpdater).registerCallback();
verify(mBluetoothDeviceUpdater).refreshPreference();
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI,
Flags.FLAG_ENABLE_LE_AUDIO_SHARING})
public void onStop_unregisterCallbacks() {
mTemporaryBondDeviceGroupController.onStop(mLifecycleOwner);
verify(mEventManager).unregisterCallback(any(BluetoothCallback.class));
verify(mBluetoothDeviceUpdater).unregisterCallback();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void displayPreference_flagOff_doNothing() {
mTemporaryBondDeviceGroupController.displayPreference(mScreen);
assertThat(mPreferenceGroup.isVisible()).isFalse();
verify(mBluetoothDeviceUpdater, never()).forceUpdate();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI)
public void displayPreference_audioSharingUINotAvailable_doNothing() {
mTemporaryBondDeviceGroupController.displayPreference(mScreen);
assertThat(mPreferenceGroup.isVisible()).isFalse();
verify(mBluetoothDeviceUpdater, never()).forceUpdate();
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI,
Flags.FLAG_ENABLE_LE_AUDIO_SHARING})
public void displayPreference_updateDeviceList() {
mTemporaryBondDeviceGroupController.displayPreference(mScreen);
assertThat(mPreferenceGroup.isVisible()).isFalse();
verify(mBluetoothDeviceUpdater).setPrefContext(mContext);
verify(mBluetoothDeviceUpdater).forceUpdate();
}
@Test
public void onDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded() {
mTemporaryBondDeviceGroupController.onDeviceAdded(mPreference);
assertThat(mPreferenceGroup.isVisible()).isTrue();
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
}
@Test
public void onDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved() {
mPreferenceGroup.addPreference(mPreference);
mTemporaryBondDeviceGroupController.onDeviceRemoved(mPreference);
assertThat(mPreferenceGroup.isVisible()).isFalse();
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
}
@Test
public void onDeviceRemoved_notLastRemove_stillVisible() {
mPreferenceGroup.setVisible(true);
mPreferenceGroup.addPreference(mPreference);
mPreferenceGroup.addPreference(new Preference(mContext));
mTemporaryBondDeviceGroupController.onDeviceRemoved(mPreference);
assertThat(mPreferenceGroup.isVisible()).isTrue();
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
}
@Test
public void getPreferenceKey_returnsCorrectKey() {
assertThat(mTemporaryBondDeviceGroupController.getPreferenceKey()).isEqualTo(KEY);
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI,
Flags.FLAG_ENABLE_LE_AUDIO_SHARING})
public void getAvailabilityStatus_returnsAvailable() {
assertThat(mTemporaryBondDeviceGroupController.getAvailabilityStatus()).isEqualTo(
AVAILABLE_UNSEARCHABLE);
}
}

View File

@@ -1,139 +0,0 @@
/*
* 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.bluetooth.Utils;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.flags.Flags;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.Collection;
/** Tests for {@link TemporaryBondDeviceGroupUpdater}. */
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class
})
public class TemporaryBondDeviceGroupUpdaterTest {
private static final String TAG = "TemporaryBondDeviceGroupUpdater";
private static final String PREF_KEY_PREFIX = "temp_bond_bt_";
private static final String TEMP_BOND_METADATA =
"<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DevicePreferenceCallback mDevicePreferenceCallback;
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock
private BluetoothDevice mBluetoothDevice;
@Mock
private LocalBluetoothManager mLocalBtManager;
@Mock
private CachedBluetoothDeviceManager mCachedDeviceManager;
private TemporaryBondDeviceGroupUpdater mDeviceUpdater;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowBluetoothAdapter shadowBluetoothAdapter = Shadow.extract(
BluetoothAdapter.getDefaultAdapter());
shadowBluetoothAdapter.setEnabled(true);
shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
Context context = ApplicationProvider.getApplicationContext();
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
mLocalBtManager = Utils.getLocalBtManager(context);
when(mLocalBtManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
cachedDevices.add(mCachedBluetoothDevice);
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
mDeviceUpdater =
spy(
new TemporaryBondDeviceGroupUpdater(
context, mDevicePreferenceCallback, /* metricsCategory= */ 0));
mDeviceUpdater.setPrefContext(context);
}
@After
public void tearDown() {
ShadowBluetoothUtils.reset();
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI,
Flags.FLAG_ENABLE_LE_AUDIO_SHARING})
public void isFilterMatched_isTemporaryBondDevice_returnsTrue() {
when(mBluetoothDevice.isConnected()).thenReturn(true);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
.thenReturn(TEMP_BOND_METADATA.getBytes());
assertThat(mDeviceUpdater.isFilterMatched(mCachedBluetoothDevice)).isTrue();
}
@Test
public void getLogTag_returnsCorrectTag() {
assertThat(mDeviceUpdater.getLogTag()).isEqualTo(TAG);
}
@Test
public void getPreferenceKey_returnsCorrectKey() {
assertThat(mDeviceUpdater.getPreferenceKeyPrefix()).isEqualTo(PREF_KEY_PREFIX);
}
}

View File

@@ -20,6 +20,8 @@ import static android.bluetooth.BluetoothStatusCodes.FEATURE_SUPPORTED;
import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController
.A2DP_OFFLOAD_DISABLED_PROPERTY; .A2DP_OFFLOAD_DISABLED_PROPERTY;
import static com.android.settings.development.BluetoothA2dpHwOffloadPreferenceController
.A2DP_OFFLOAD_SUPPORTED_PROPERTY;
import static com.android.settings.development.BluetoothLeAudioHwOffloadPreferenceController import static com.android.settings.development.BluetoothLeAudioHwOffloadPreferenceController
.LE_AUDIO_OFFLOAD_DISABLED_PROPERTY; .LE_AUDIO_OFFLOAD_DISABLED_PROPERTY;
import static com.android.settings.development.BluetoothLeAudioHwOffloadPreferenceController import static com.android.settings.development.BluetoothLeAudioHwOffloadPreferenceController
@@ -120,4 +122,17 @@ public class BluetoothLeAudioHwOffloadPreferenceControllerTest {
leAueioDisabled = SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false); leAueioDisabled = SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(leAueioDisabled).isTrue(); assertThat(leAueioDisabled).isTrue();
} }
@Test
public void asDisableDeveloperOption_ResetLEOffloadBasedOnA2dpLeAudioOffloadSupported() {
SystemProperties.set(LE_AUDIO_OFFLOAD_SUPPORTED_PROPERTY, Boolean.toString(true));
SystemProperties.set(A2DP_OFFLOAD_SUPPORTED_PROPERTY, Boolean.toString(true));
SystemProperties.set(
LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, Boolean.toString(true));
mController.onDeveloperOptionsSwitchDisabled();
boolean leAueioDisabled =
SystemProperties.getBoolean(LE_AUDIO_OFFLOAD_DISABLED_PROPERTY, false);
assertThat(leAueioDisabled).isFalse();
}
} }

View File

@@ -102,7 +102,8 @@ public class DesktopExperiencePreferenceControllerTest {
// Set desktop mode available // Set desktop mode available
when(mResources.getBoolean(com.android.internal.R.bool.config_isDesktopModeSupported)) when(mResources.getBoolean(com.android.internal.R.bool.config_isDesktopModeSupported))
.thenReturn(true); .thenReturn(true);
when(mResources.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops)) when(mResources
.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops))
.thenReturn(true); .thenReturn(true);
ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions", ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions",
"false"); "false");

View File

@@ -104,7 +104,8 @@ public class DesktopModePreferenceControllerTest {
// Set desktop mode available // Set desktop mode available
when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)) when(mResources.getBoolean(R.bool.config_isDesktopModeSupported))
.thenReturn(true); .thenReturn(true);
when(mResources.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops)) when(mResources
.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops))
.thenReturn(true); .thenReturn(true);
ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions", ShadowSystemProperties.override("persist.wm.debug.desktop_mode_enforce_device_restrictions",
"false"); "false");

View File

@@ -97,7 +97,8 @@ public class DesktopModeSecondaryDisplayPreferenceControllerTest {
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mController.displayPreference(mScreen); mController.displayPreference(mScreen);
when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)).thenReturn(false); when(mResources.getBoolean(R.bool.config_isDesktopModeSupported)).thenReturn(false);
when(mResources.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops)) when(mResources
.getBoolean(com.android.internal.R.bool.config_canInternalDisplayHostDesktops))
.thenReturn(false); .thenReturn(false);
} }

View File

@@ -91,6 +91,7 @@ public class FreeformWindowsPreferenceControllerTest {
doReturn(mFragmentManager).when(mActivity).getSupportFragmentManager(); doReturn(mFragmentManager).when(mActivity).getSupportFragmentManager();
doReturn(mActivity).when(mFragment).getActivity(); doReturn(mActivity).when(mFragment).getActivity();
doReturn(true).when(mResources).getBoolean(R.bool.config_isDesktopModeSupported); doReturn(true).when(mResources).getBoolean(R.bool.config_isDesktopModeSupported);
doReturn(true).when(mResources).getBoolean(R.bool.config_canInternalDisplayHostDesktops);
mController = new FreeformWindowsPreferenceController(mContext, mFragment); mController = new FreeformWindowsPreferenceController(mContext, mFragment);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageManager()).thenReturn(mPackageManager);

View File

@@ -99,9 +99,9 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyOnePreferenceInvisible(mBackgroundTimePreference); verifyOnePreferenceInvisible(mBackgroundTimePreference);
verify(mScreenTimePreference).setTimeTitle("Screen time"); verify(mScreenTimePreference).setTitle("Screen time");
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -117,9 +117,9 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyOnePreferenceInvisible(mScreenTimePreference); verifyOnePreferenceInvisible(mScreenTimePreference);
verify(mBackgroundTimePreference).setTimeTitle("Background time"); verify(mBackgroundTimePreference).setTitle("Background time");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -135,12 +135,12 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeTitle("Screen time"); verify(mScreenTimePreference).setTitle("Screen time");
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
verify(mBackgroundTimePreference).setTimeTitle("Background time"); verify(mBackgroundTimePreference).setTitle("Background time");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
verify(mPowerUsageTimeCategory).setTitle("App usage for 12 am-2 am"); verify(mPowerUsageTimeCategory).setTitle("App usage for 12 am-2 am");
} }
@@ -173,8 +173,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("1 min"); verify(mScreenTimePreference).setSummary("1 min");
verify(mBackgroundTimePreference).setTimeSummary("Less than a minute"); verify(mBackgroundTimePreference).setSummary("Less than a minute");
} }
@Test @Test
@@ -190,8 +190,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mBackgroundTimePreference).setTimeSummary("2 min"); verify(mBackgroundTimePreference).setSummary("2 min");
} }
@Test @Test
@@ -207,8 +207,8 @@ public final class PowerUsageTimeControllerTest {
/* anomalyHintText= */ null); /* anomalyHintText= */ null);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mBackgroundTimePreference).setTimeSummary("Less than a minute"); verify(mBackgroundTimePreference).setSummary("Less than a minute");
} }
@Test @Test
@@ -224,8 +224,8 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mScreenTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
@Test @Test
@@ -241,8 +241,8 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference, never()).setAnomalyHint(anyString()); verify(mScreenTimePreference, never()).setHint(anyString());
verify(mBackgroundTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mBackgroundTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
} }
@Test @Test
@@ -258,9 +258,9 @@ public final class PowerUsageTimeControllerTest {
TEST_ANOMALY_HINT_TEXT); TEST_ANOMALY_HINT_TEXT);
verifyAllPreferencesVisible(true); verifyAllPreferencesVisible(true);
verify(mScreenTimePreference).setTimeSummary("Less than a minute"); verify(mScreenTimePreference).setSummary("Less than a minute");
verify(mScreenTimePreference).setAnomalyHint(TEST_ANOMALY_HINT_TEXT); verify(mScreenTimePreference).setHint(TEST_ANOMALY_HINT_TEXT);
verify(mBackgroundTimePreference, never()).setAnomalyHint(anyString()); verify(mBackgroundTimePreference, never()).setHint(anyString());
} }
private void verifySetPrefToVisible(Preference pref, boolean isVisible) { private void verifySetPrefToVisible(Preference pref, boolean isVisible) {

View File

@@ -67,7 +67,7 @@ public final class BatteryUsageBreakdownControllerTest {
@Mock private PreferenceGroup mRootPreferenceGroup; @Mock private PreferenceGroup mRootPreferenceGroup;
@Mock private Drawable mDrawable; @Mock private Drawable mDrawable;
@Mock private BatteryHistEntry mBatteryHistEntry; @Mock private BatteryHistEntry mBatteryHistEntry;
@Mock private AnomalyAppItemPreference mAnomalyAppItemPreference; @Mock private PowerGaugePreference mPowerGaugePreference;
private Context mContext; private Context mContext;
private FakeFeatureFactory mFeatureFactory; private FakeFeatureFactory mFeatureFactory;
@@ -131,13 +131,13 @@ public final class BatteryUsageBreakdownControllerTest {
BatteryDiffEntry.sResourceCache.put( BatteryDiffEntry.sResourceCache.put(
"fakeBatteryDiffEntryKey", "fakeBatteryDiffEntryKey",
new BatteryEntry.NameAndIcon("fakeName", /* icon= */ null, /* iconId= */ 1)); new BatteryEntry.NameAndIcon("fakeName", /* icon= */ null, /* iconId= */ 1));
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).findPreference(PREF_KEY); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).findPreference(PREF_KEY);
} }
@Test @Test
public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() { public void onDestroy_clearPreferenceCacheAndPreferenceGroupRemoveAll() {
// Ensures the testing environment is correct. // Ensures the testing environment is correct.
mBatteryUsageBreakdownController.mPreferenceCache.put(PREF_KEY, mAnomalyAppItemPreference); mBatteryUsageBreakdownController.mPreferenceCache.put(PREF_KEY, mPowerGaugePreference);
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).hasSize(1);
mBatteryUsageBreakdownController.onDestroy(); mBatteryUsageBreakdownController.onDestroy();
@@ -204,25 +204,25 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() { public void removeAndCacheAllUnusedPreferences_removePref_buildCacheAndRemoveAllPreference() {
doReturn(1).when(mRootPreferenceGroup).getPreferenceCount(); doReturn(1).when(mRootPreferenceGroup).getPreferenceCount();
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).getPreference(0); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).getPreference(0);
doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey(); doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey(); doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
// Ensures the testing data is correct. // Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences(); mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY)) assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
.isEqualTo(mAnomalyAppItemPreference); .isEqualTo(mPowerGaugePreference);
verify(mRootPreferenceGroup).removePreference(mAnomalyAppItemPreference); verify(mRootPreferenceGroup).removePreference(mPowerGaugePreference);
} }
@Test @Test
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() { public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
doReturn(1).when(mRootPreferenceGroup).getPreferenceCount(); doReturn(1).when(mRootPreferenceGroup).getPreferenceCount();
doReturn(mAnomalyAppItemPreference).when(mRootPreferenceGroup).getPreference(0); doReturn(mPowerGaugePreference).when(mRootPreferenceGroup).getPreference(0);
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey(); doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
doReturn(PREF_KEY).when(mAnomalyAppItemPreference).getKey(); doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
// Ensures the testing data is correct. // Ensures the testing data is correct.
assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
@@ -246,11 +246,11 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void handlePreferenceTreeClick_forAppEntry_returnTrue() { public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry(); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat( assertThat(
mBatteryUsageBreakdownController.handlePreferenceTreeClick( mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mAnomalyAppItemPreference)) mPowerGaugePreference))
.isTrue(); .isTrue();
verify(mMetricsFeatureProvider) verify(mMetricsFeatureProvider)
.action( .action(
@@ -264,11 +264,11 @@ public final class BatteryUsageBreakdownControllerTest {
@Test @Test
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() { public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY; mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
doReturn(mBatteryDiffEntry).when(mAnomalyAppItemPreference).getBatteryDiffEntry(); doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
assertThat( assertThat(
mBatteryUsageBreakdownController.handlePreferenceTreeClick( mBatteryUsageBreakdownController.handlePreferenceTreeClick(
mAnomalyAppItemPreference)) mPowerGaugePreference))
.isTrue(); .isTrue();
verify(mMetricsFeatureProvider) verify(mMetricsFeatureProvider)
.action( .action(

View File

@@ -19,19 +19,20 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.Space;
import androidx.preference.PreferenceViewHolder; import androidx.preference.PreferenceViewHolder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.widget.SettingsThemeHelper;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
@@ -48,17 +49,17 @@ public class PowerGaugePreferenceTest {
private View mWidgetView; private View mWidgetView;
private PreferenceViewHolder mPreferenceViewHolder; private PreferenceViewHolder mPreferenceViewHolder;
@Mock Drawable mMockIcon;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mPowerGaugePreference = new PowerGaugePreference(mContext);
mRootView = mRootView =
LayoutInflater.from(mContext) LayoutInflater.from(mContext)
.inflate( .inflate(mPowerGaugePreference.getLayoutResource(), null);
com.android.settingslib.widget.preference.app.R.layout
.preference_app,
null);
mWidgetView = mWidgetView =
LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null); LayoutInflater.from(mContext).inflate(R.layout.preference_widget_summary, null);
final LinearLayout widgetFrame = mRootView.findViewById(android.R.id.widget_frame); final LinearLayout widgetFrame = mRootView.findViewById(android.R.id.widget_frame);
@@ -66,31 +67,56 @@ public class PowerGaugePreferenceTest {
widgetFrame.addView(mWidgetView); widgetFrame.addView(mWidgetView);
mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(mRootView); mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
mPowerGaugePreference = new PowerGaugePreference(mContext);
assertThat(mPowerGaugePreference.getLayoutResource()) assertThat(mPowerGaugePreference.getLayoutResource())
.isEqualTo(com.android.settingslib.widget.preference.app.R.layout.preference_app); .isEqualTo(
SettingsThemeHelper.isExpressiveTheme(mContext)
? R.layout.expressive_warning_frame_preference
: R.layout.warning_frame_preference);
} }
@Test @Test
public void testOnBindViewHolder_showAnomaly_bindAnomalyIcon() { public void testOnBindViewHolder_showHint_hasHintChip() {
mPowerGaugePreference.shouldShowAnomalyIcon(true); mPowerGaugePreference.setHint("Hint Text");
mPowerGaugePreference.setIcon(mMockIcon);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder); mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
TextView widgetSummary = (TextView) mPreferenceViewHolder.findViewById(R.id.widget_summary); final LinearLayout warningChipFrame =
final Drawable[] drawables = widgetSummary.getCompoundDrawablesRelative(); (LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceHolder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(drawables[0]).isInstanceOf(VectorDrawable.class); assertThat(warningChipFrame.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(warningPaddingPlaceHolder.getVisibility()).isEqualTo(View.VISIBLE);
} }
@Test @Test
public void testOnBindViewHolder_notShowAnomaly_bindAnomalyIcon() { public void testOnBindViewHolder_emptyHintText_withoutHintChip() {
mPowerGaugePreference.shouldShowAnomalyIcon(false); mPowerGaugePreference.setHint("");
mPowerGaugePreference.setIcon(mMockIcon);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder); mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
TextView widgetSummary = (TextView) mPreferenceViewHolder.findViewById(R.id.widget_summary); final LinearLayout warningChipFrame =
final Drawable[] drawables = widgetSummary.getCompoundDrawablesRelative(); (LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceholder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(drawables[0]).isNull(); assertThat(warningChipFrame.getVisibility()).isEqualTo(View.GONE);
assertThat(warningPaddingPlaceholder.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void testOnBindViewHolder_noAppIconWithHintText_hasChipWithoutPaddingPlaceholder() {
mPowerGaugePreference.setHint("Anomaly Hint Text");
mPowerGaugePreference.setIcon(null);
mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
final LinearLayout warningChipFrame =
(LinearLayout) mPreferenceViewHolder.findViewById(R.id.warning_chip_frame);
final Space warningPaddingPlaceHolder =
warningChipFrame.findViewById(R.id.warning_padding_placeholder);
assertThat(warningChipFrame.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(warningPaddingPlaceHolder.getVisibility()).isEqualTo(View.GONE);
} }
@Test @Test

View File

@@ -102,7 +102,7 @@ public class DndConditionalCardControllerTest {
private ZenModeConfig getMutedAllConfig() { private ZenModeConfig getMutedAllConfig() {
final ZenModeConfig config = new ZenModeConfig(); final ZenModeConfig config = new ZenModeConfig();
config.applyNotificationPolicy(new NotificationManager.Policy(0, 0, 0)); config.applyNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
config.areChannelsBypassingDnd = false; config.hasPriorityChannels = false;
return config; return config;
} }
} }

View File

@@ -26,10 +26,10 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.app.Dialog;
import android.os.Bundle; import android.os.Bundle;
import android.window.OnBackInvokedDispatcher; import android.window.OnBackInvokedDispatcher;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
@@ -92,17 +92,17 @@ public class LocaleDialogFragmentTest {
@Test @Test
public void onBackInvoked_dialogIsStillDisplaying() { public void onBackInvoked_dialogIsStillDisplaying() {
mDialogFragment.setBackDispatcher(mOnBackInvokedDispatcher); mDialogFragment.setBackDispatcher(mOnBackInvokedDispatcher);
AlertDialog alertDialog = (AlertDialog) mDialogFragment.onCreateDialog(null); Dialog dialog = mDialogFragment.onCreateDialog(null);
alertDialog.show(); dialog.show();
assertThat(alertDialog).isNotNull(); assertThat(dialog).isNotNull();
assertThat(alertDialog.isShowing()).isTrue(); assertThat(dialog.isShowing()).isTrue();
mOnBackInvokedDispatcher.registerOnBackInvokedCallback( mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any()); eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any());
mDialogFragment.getBackInvokedCallback().onBackInvoked(); mDialogFragment.getBackInvokedCallback().onBackInvoked();
assertThat(alertDialog.isShowing()).isTrue(); assertThat(dialog.isShowing()).isTrue();
} }
} }

View File

@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog;
import android.app.IActivityManager; import android.app.IActivityManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -53,10 +54,10 @@ import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.internal.app.LocaleStore; import com.android.internal.app.LocaleStore;
@@ -78,6 +79,7 @@ import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric; import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
@@ -87,6 +89,7 @@ import java.util.Locale;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = { @Config(shadows = {
ShadowDialog.class,
ShadowAlertDialogCompat.class, ShadowAlertDialogCompat.class,
ShadowActivityManager.class, ShadowActivityManager.class,
com.android.settings.testutils.shadow.ShadowFragment.class, com.android.settings.testutils.shadow.ShadowFragment.class,
@@ -143,6 +146,8 @@ public class LocaleListEditorTest {
private ImageView mDragHandle; private ImageView mDragHandle;
@Mock @Mock
private NotificationController mNotificationController; private NotificationController mNotificationController;
@Mock
private Preference mAddLanguagePreference;
@Rule @Rule
public final CheckFlagsRule mCheckFlagsRule = public final CheckFlagsRule mCheckFlagsRule =
@@ -166,6 +171,8 @@ public class LocaleListEditorTest {
context.getSystemService(Context.USER_SERVICE)); context.getSystemService(Context.USER_SERVICE));
ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter); ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter);
ReflectionHelpers.setField(mLocaleListEditor, "mAddLanguage", mAddLanguage); ReflectionHelpers.setField(mLocaleListEditor, "mAddLanguage", mAddLanguage);
ReflectionHelpers.setField(mLocaleListEditor, "mAddLanguagePreference",
mAddLanguagePreference);
ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager); ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager);
ReflectionHelpers.setField(mLocaleListEditor, "mMetricsFeatureProvider", ReflectionHelpers.setField(mLocaleListEditor, "mMetricsFeatureProvider",
mMetricsFeatureProvider); mMetricsFeatureProvider);
@@ -178,7 +185,7 @@ public class LocaleListEditorTest {
ReflectionHelpers.setField(mLocaleListEditor, "mRemoveMode", false); ReflectionHelpers.setField(mLocaleListEditor, "mRemoveMode", false);
ReflectionHelpers.setField(mLocaleListEditor, "mShowingRemoveDialog", false); ReflectionHelpers.setField(mLocaleListEditor, "mShowingRemoveDialog", false);
ReflectionHelpers.setField(mLocaleListEditor, "mLocaleAdditionMode", false); ReflectionHelpers.setField(mLocaleListEditor, "mLocaleAdditionMode", false);
ShadowAlertDialogCompat.reset(); ShadowDialog.reset();
} }
@Test @Test
@@ -209,14 +216,13 @@ public class LocaleListEditorTest {
//launch dialog //launch dialog
mLocaleListEditor.showRemoveLocaleWarningDialog(); mLocaleListEditor.showRemoveLocaleWarningDialog();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); final Dialog dialog = ShadowDialog.getLatestDialog();
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); TextView dialogTitle = dialog.findViewById(R.id.dialog_with_icon_title);
assertThat(dialogTitle.getText().toString())
assertThat(shadowDialog.getTitle()).isEqualTo( .isEqualTo(mContext.getString(R.string.dlg_remove_locales_error_title));
mContext.getString(R.string.dlg_remove_locales_error_title));
} }
@Test @Test
@@ -231,14 +237,13 @@ public class LocaleListEditorTest {
//launch dialog //launch dialog
mLocaleListEditor.showRemoveLocaleWarningDialog(); mLocaleListEditor.showRemoveLocaleWarningDialog();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); final Dialog dialog = ShadowDialog.getLatestDialog();
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); TextView dialogMessage = dialog.findViewById(R.id.dialog_with_icon_message);
assertThat(dialogMessage.getText().toString())
assertThat(shadowDialog.getMessage()).isEqualTo( .isEqualTo(mContext.getString(R.string.dlg_remove_locales_message));
mContext.getString(R.string.dlg_remove_locales_message));
} }
@Test @Test
@@ -253,13 +258,12 @@ public class LocaleListEditorTest {
//launch dialog //launch dialog
mLocaleListEditor.showRemoveLocaleWarningDialog(); mLocaleListEditor.showRemoveLocaleWarningDialog();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); final Dialog dialog = ShadowDialog.getLatestDialog();
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog); TextView dialogMessage = dialog.findViewById(R.id.dialog_with_icon_message);
assertThat(dialogMessage.getText().isEmpty()).isTrue();
assertThat(shadowDialog.getMessage()).isNull();
} }
@Test @Test
@@ -280,12 +284,12 @@ public class LocaleListEditorTest {
//launch the first dialog //launch the first dialog
mLocaleListEditor.showRemoveLocaleWarningDialog(); mLocaleListEditor.showRemoveLocaleWarningDialog();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); final Dialog dialog = ShadowDialog.getLatestDialog();
assertThat(dialog).isNotNull(); assertThat(dialog).isNotNull();
// click the remove button // click the remove button
dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick(); dialog.findViewById(R.id.button_ok).performClick();
ShadowLooper.idleMainLooper(); ShadowLooper.idleMainLooper();
assertThat(dialog.isShowing()).isFalse(); assertThat(dialog.isShowing()).isFalse();

View File

@@ -21,14 +21,12 @@ import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNI
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.net.ConnectivitySettingsManager; import android.net.ConnectivitySettingsManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -88,31 +86,31 @@ public class PrivateDnsModeDialogPreferenceTest {
} }
@Test @Test
public void testOnCheckedChanged_dnsModeOff_disableEditText() { public void onCheckedChanged_dnsModeOff_disableHostnameText() {
mPreference.onCheckedChanged(null, R.id.private_dns_mode_off); mPreference.onCheckedChanged(null, R.id.private_dns_mode_off);
assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_OFF); assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_OFF);
assertThat(mPreference.mEditText.isEnabled()).isFalse(); assertThat(mPreference.mHostnameText.isEnabled()).isFalse();
} }
@Test @Test
public void testOnCheckedChanged_dnsModeOpportunistic_disableEditText() { public void onCheckedChanged_dnsModeOpportunistic_disableHostnameText() {
mPreference.onCheckedChanged(null, R.id.private_dns_mode_opportunistic); mPreference.onCheckedChanged(null, R.id.private_dns_mode_opportunistic);
assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_OPPORTUNISTIC); assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_OPPORTUNISTIC);
assertThat(mPreference.mEditText.isEnabled()).isFalse(); assertThat(mPreference.mHostnameText.isEnabled()).isFalse();
} }
@Test @Test
public void testOnCheckedChanged_dnsModeProvider_enableEditText() { public void onCheckedChanged_dnsModeProvider_enableHostnameText() {
mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider); mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider);
assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); assertThat(mPreference.mMode).isEqualTo(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
assertThat(mPreference.mEditText.isEnabled()).isTrue(); assertThat(mPreference.mHostnameText.isEnabled()).isTrue();
} }
@Test @Test
public void testOnBindDialogView_containsCorrectData() { public void onBindDialogView_containsCorrectData() {
// Don't set settings to the default value ("opportunistic") as that // Don't set settings to the default value ("opportunistic") as that
// risks masking failure to read the mode from settings. // risks masking failure to read the mode from settings.
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF); ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF);
@@ -123,57 +121,74 @@ public class PrivateDnsModeDialogPreferenceTest {
new LinearLayout(mContext), false); new LinearLayout(mContext), false);
mPreference.onBindDialogView(view); mPreference.onBindDialogView(view);
assertThat(mPreference.mEditText.getText().toString()).isEqualTo(HOST_NAME); assertThat(mPreference.mHostnameText.getText().toString()).isEqualTo(HOST_NAME);
assertThat(mPreference.mRadioGroup.getCheckedRadioButtonId()).isEqualTo( assertThat(mPreference.mRadioGroup.getCheckedRadioButtonId()).isEqualTo(
R.id.private_dns_mode_off); R.id.private_dns_mode_off);
} }
@Test @Test
public void testOnCheckedChanged_switchMode_saveButtonHasCorrectState() { public void doSaveButton_changeToOffMode_saveData() {
final String[] INVALID_HOST_NAMES = new String[] { // Set the default settings to OPPORTUNISTIC
INVALID_HOST_NAME, ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OPPORTUNISTIC);
"2001:db8::53", // IPv6 string literal
"192.168.1.1", // IPv4 string literal
};
for (String invalid : INVALID_HOST_NAMES) { mPreference.mMode = PRIVATE_DNS_MODE_OFF;
// Set invalid hostname mPreference.doSaveButton();
mPreference.mEditText.setText(invalid);
mPreference.onCheckedChanged(null, R.id.private_dns_mode_off);
assertWithMessage("off: " + invalid).that(mSaveButton.isEnabled()).isTrue();
mPreference.onCheckedChanged(null, R.id.private_dns_mode_opportunistic);
assertWithMessage("opportunistic: " + invalid).that(mSaveButton.isEnabled()).isTrue();
mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider);
assertWithMessage("provider: " + invalid).that(mSaveButton.isEnabled()).isFalse();
}
}
@Test
public void testOnClick_positiveButtonClicked_saveData() {
// Set the default settings to OFF
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF);
mPreference.mMode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
mPreference.onClick(null, DialogInterface.BUTTON_POSITIVE);
// Change to OPPORTUNISTIC // Change to OPPORTUNISTIC
assertThat(ConnectivitySettingsManager.getPrivateDnsMode(mContext)).isEqualTo( assertThat(ConnectivitySettingsManager.getPrivateDnsMode(mContext))
PRIVATE_DNS_MODE_OPPORTUNISTIC); .isEqualTo(PRIVATE_DNS_MODE_OFF);
} }
@Test @Test
public void testOnClick_negativeButtonClicked_doNothing() { public void doSaveButton_changeToOpportunisticMode_saveData() {
// Set the default settings to OFF // Set the default settings to OFF
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF); ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF);
mPreference.mMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; mPreference.mMode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
mPreference.onClick(null, DialogInterface.BUTTON_NEGATIVE); mPreference.doSaveButton();
// Still equal to OFF // Change to OPPORTUNISTIC
assertThat(ConnectivitySettingsManager.getPrivateDnsMode(mContext)).isEqualTo( assertThat(ConnectivitySettingsManager.getPrivateDnsMode(mContext))
PRIVATE_DNS_MODE_OFF); .isEqualTo(PRIVATE_DNS_MODE_OPPORTUNISTIC);
}
@Test
public void doSaveButton_changeToProviderHostnameMode_saveData() {
// Set the default settings to OFF
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OFF);
mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider);
mPreference.mHostnameText.setText(HOST_NAME);
mPreference.doSaveButton();
// Change to PROVIDER_HOSTNAME
assertThat(ConnectivitySettingsManager.getPrivateDnsMode(mContext))
.isEqualTo(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
assertThat(ConnectivitySettingsManager.getPrivateDnsHostname(mContext))
.isEqualTo(HOST_NAME);
}
@Test
public void doSaveButton_providerHostnameIsEmpty_setHostnameError() {
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
ConnectivitySettingsManager.setPrivateDnsHostname(mContext, HOST_NAME);
mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider);
mPreference.mHostnameText.setText("");
mPreference.doSaveButton();
assertThat(mPreference.mHostnameLayout.isErrorEnabled()).isTrue();
}
@Test
public void doSaveButton_providerHostnameIsInvalid_setHostnameError() {
ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
ConnectivitySettingsManager.setPrivateDnsHostname(mContext, HOST_NAME);
mPreference.onCheckedChanged(null, R.id.private_dns_mode_provider);
mPreference.mHostnameText.setText(INVALID_HOST_NAME);
mPreference.doSaveButton();
assertThat(mPreference.mHostnameLayout.isErrorEnabled()).isTrue();
} }
} }

View File

@@ -85,7 +85,7 @@ public class ZenModeSetCalendarPreferenceControllerTest {
} }
@Test @Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) @EnableFlags(Flags.FLAG_MODES_UI)
public void updateEventMode_updatesConditionAndTriggerDescription() { public void updateEventMode_updatesConditionAndTriggerDescription() {
ZenMode mode = new TestModeBuilder() ZenMode mode = new TestModeBuilder()
.setPackage(SystemZenRules.PACKAGE_ANDROID) .setPackage(SystemZenRules.PACKAGE_ANDROID)

View File

@@ -80,7 +80,7 @@ public class ZenModeSetSchedulePreferenceControllerTest {
} }
@Test @Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) @EnableFlags(Flags.FLAG_MODES_UI)
public void updateScheduleRule_updatesConditionAndTriggerDescription() { public void updateScheduleRule_updatesConditionAndTriggerDescription() {
ZenMode mode = new TestModeBuilder() ZenMode mode = new TestModeBuilder()
.setPackage(SystemZenRules.PACKAGE_ANDROID) .setPackage(SystemZenRules.PACKAGE_ANDROID)

View File

@@ -213,11 +213,7 @@ public class ZenModeBackendTest {
mBackend.saveConversationSenders(CONVERSATION_SENDERS_NONE); mBackend.saveConversationSenders(CONVERSATION_SENDERS_NONE);
ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class); ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class);
if (android.app.Flags.modesApi()) { verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
} else {
verify(mNotificationManager).setNotificationPolicy(captor.capture());
}
Policy expected = new Policy( Policy expected = new Policy(
PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS,
@@ -241,11 +237,7 @@ public class ZenModeBackendTest {
mBackend.saveConversationSenders(CONVERSATION_SENDERS_ANYONE); mBackend.saveConversationSenders(CONVERSATION_SENDERS_ANYONE);
ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class); ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class);
if (android.app.Flags.modesApi()) { verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
} else {
verify(mNotificationManager).setNotificationPolicy(captor.capture());
}
Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS
| PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS,
@@ -270,11 +262,7 @@ public class ZenModeBackendTest {
mBackend.saveSenders(PRIORITY_CATEGORY_CALLS, PRIORITY_SENDERS_ANY); mBackend.saveSenders(PRIORITY_CATEGORY_CALLS, PRIORITY_SENDERS_ANY);
ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class); ArgumentCaptor<Policy> captor = ArgumentCaptor.forClass(Policy.class);
if (android.app.Flags.modesApi()) { verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true));
} else {
verify(mNotificationManager).setNotificationPolicy(captor.capture());
}
Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS
| PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS,

View File

@@ -107,7 +107,7 @@ public class ZenModeEventRuleSettingsTest {
} }
@Test @Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) @EnableFlags(Flags.FLAG_MODES_UI)
public void updateEventRule_updatesConditionAndTriggerDescription() { public void updateEventRule_updatesConditionAndTriggerDescription() {
mFragment.setBackend(mBackend); mFragment.setBackend(mBackend);
mFragment.mId = "id"; mFragment.mId = "id";

View File

@@ -107,7 +107,7 @@ public class ZenModeScheduleRuleSettingsTest {
} }
@Test @Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) @EnableFlags(Flags.FLAG_MODES_UI)
public void updateScheduleRule_updatesConditionAndTriggerDescription() { public void updateScheduleRule_updatesConditionAndTriggerDescription() {
mFragment.setBackend(mBackend); mFragment.setBackend(mBackend);
mFragment.mId = "id"; mFragment.mId = "id";

View File

@@ -117,11 +117,7 @@ public class ZenModeSliceBuilderTest {
ZenModeSliceBuilder.handleUriChange(mContext, intent); ZenModeSliceBuilder.handleUriChange(mContext, intent);
if (android.app.Flags.modesApi()) { verify(mNm).setZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), any(), any(), eq(true));
verify(mNm).setZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), any(), any(), eq(true));
} else {
verify(mNm).setZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), any(), any());
}
} }
@Test @Test
@@ -131,10 +127,6 @@ public class ZenModeSliceBuilderTest {
ZenModeSliceBuilder.handleUriChange(mContext, intent); ZenModeSliceBuilder.handleUriChange(mContext, intent);
if (android.app.Flags.modesApi()) { verify(mNm).setZenMode(eq(ZEN_MODE_OFF), any(), any(), eq(true));
verify(mNm).setZenMode(eq(ZEN_MODE_OFF), any(), any(), eq(true));
} else {
verify(mNm).setZenMode(eq(ZEN_MODE_OFF), any(), any());
}
} }
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.deviceinfo package com.android.settings.deviceinfo
import android.content.Context import android.content.Context
import android.os.UserManager
import android.telephony.SubscriptionInfo import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
@@ -25,30 +26,39 @@ import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R import com.android.settings.R
import com.android.settings.core.BasePreferenceController
import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.Utils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.MockitoSession
import org.mockito.kotlin.any import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
import org.mockito.kotlin.verify import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class PhoneNumberPreferenceControllerTest { class PhoneNumberPreferenceControllerTest {
private lateinit var mockSession: MockitoSession
private val mockUserManager = mock<UserManager>()
private val mockTelephonyManager = mock<TelephonyManager>() private val mockTelephonyManager = mock<TelephonyManager>()
private val mockSubscriptionManager = mock<SubscriptionManager>() private val mockSubscriptionManager = mock<SubscriptionManager>()
private val context: Context = private val context: Context =
spy(ApplicationProvider.getApplicationContext()) { spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(SubscriptionManager::class.java) } doReturn on { getSystemService(SubscriptionManager::class.java) } doReturn mockSubscriptionManager
mockSubscriptionManager
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
on { getSystemService(UserManager::class.java) } doReturn mockUserManager
} }
private val subscriptionInfo = mock<SubscriptionInfo>() private val subscriptionInfo = mock<SubscriptionInfo>()
@@ -61,6 +71,20 @@ class PhoneNumberPreferenceControllerTest {
@Before @Before
fun setup() { fun setup() {
mockSession =
ExtendedMockito.mockitoSession()
.mockStatic(SubscriptionUtil::class.java)
.mockStatic(Utils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
// By default, available
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
whenever(Utils.isWifiOnly(context)).thenReturn(false)
mockUserManager.stub {
on { isAdminUser } doReturn true
}
preference.setKey(controller.preferenceKey) preference.setKey(controller.preferenceKey)
preference.isVisible = true preference.isVisible = true
preferenceScreen.addPreference(preference) preferenceScreen.addPreference(preference)
@@ -70,6 +94,11 @@ class PhoneNumberPreferenceControllerTest {
doReturn(secondPreference).whenever(controller).createNewPreference(context) doReturn(secondPreference).whenever(controller).createNewPreference(context)
} }
@After
fun teardown() {
mockSession.finishMocking()
}
@Test @Test
fun displayPreference_multiSim_shouldAddSecondPreference() { fun displayPreference_multiSim_shouldAddSecondPreference() {
whenever(mockTelephonyManager.phoneCount).thenReturn(2) whenever(mockTelephonyManager.phoneCount).thenReturn(2)
@@ -132,4 +161,37 @@ class PhoneNumberPreferenceControllerTest {
verify(preference).summary = context.getString(R.string.device_info_not_available) verify(preference).summary = context.getString(R.string.device_info_not_available)
} }
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
// Use defaults from setup()
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
}
@Test
fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
mockUserManager.stub {
on { isAdminUser } doReturn false
}
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
whenever(Utils.isWifiOnly(context)).thenReturn(true)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
}
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.network.telephony package com.android.settings.network.telephony
import android.content.Context import android.content.Context
import android.os.UserManager
import androidx.lifecycle.testing.TestLifecycleOwner import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@@ -26,6 +27,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.R import com.android.settings.R
import com.android.settings.core.BasePreferenceController import com.android.settings.core.BasePreferenceController
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settingslib.Utils
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@@ -37,6 +39,7 @@ import org.junit.runner.RunWith
import org.mockito.MockitoSession import org.mockito.MockitoSession
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub import org.mockito.kotlin.stub
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness import org.mockito.quality.Strictness
@@ -45,9 +48,14 @@ import org.mockito.quality.Strictness
class MobileNetworkPhoneNumberPreferenceControllerTest { class MobileNetworkPhoneNumberPreferenceControllerTest {
private lateinit var mockSession: MockitoSession private lateinit var mockSession: MockitoSession
private val context: Context = ApplicationProvider.getApplicationContext() private val mockUserManager = mock<UserManager>()
private val mockSubscriptionRepository = mock<SubscriptionRepository>() private val mockSubscriptionRepository = mock<SubscriptionRepository>()
private val context: Context =
spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(UserManager::class.java) } doReturn mockUserManager
}
private val controller = private val controller =
MobileNetworkPhoneNumberPreferenceController(context, TEST_KEY, mockSubscriptionRepository) MobileNetworkPhoneNumberPreferenceController(context, TEST_KEY, mockSubscriptionRepository)
private val preference = Preference(context).apply { key = TEST_KEY } private val preference = Preference(context).apply { key = TEST_KEY }
@@ -58,9 +66,17 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
mockSession = mockSession =
ExtendedMockito.mockitoSession() ExtendedMockito.mockitoSession()
.mockStatic(SubscriptionUtil::class.java) .mockStatic(SubscriptionUtil::class.java)
.mockStatic(Utils::class.java)
.strictness(Strictness.LENIENT) .strictness(Strictness.LENIENT)
.startMocking() .startMocking()
// By default, available
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
whenever(Utils.isWifiOnly(context)).thenReturn(false)
mockUserManager.stub {
on { isAdminUser } doReturn true
}
preferenceScreen.addPreference(preference) preferenceScreen.addPreference(preference)
controller.init(SUB_ID) controller.init(SUB_ID)
controller.displayPreference(preferenceScreen) controller.displayPreference(preferenceScreen)
@@ -73,7 +89,6 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
@Test @Test
fun onViewCreated_cannotGetPhoneNumber_displayUnknown() = runBlocking { fun onViewCreated_cannotGetPhoneNumber_displayUnknown() = runBlocking {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
mockSubscriptionRepository.stub { mockSubscriptionRepository.stub {
on { phoneNumberFlow(SUB_ID) } doReturn flowOf(null) on { phoneNumberFlow(SUB_ID) } doReturn flowOf(null)
} }
@@ -86,7 +101,6 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
@Test @Test
fun onViewCreated_canGetPhoneNumber_displayPhoneNumber() = runBlocking { fun onViewCreated_canGetPhoneNumber_displayPhoneNumber() = runBlocking {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
mockSubscriptionRepository.stub { mockSubscriptionRepository.stub {
on { phoneNumberFlow(SUB_ID) } doReturn flowOf(PHONE_NUMBER) on { phoneNumberFlow(SUB_ID) } doReturn flowOf(PHONE_NUMBER)
} }
@@ -98,11 +112,35 @@ class MobileNetworkPhoneNumberPreferenceControllerTest {
} }
@Test @Test
fun getAvailabilityStatus_notSimHardwareVisible() { fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
// Use defaults from setup()
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
}
@Test
fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false) whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
val availabilityStatus = controller.availabilityStatus val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
mockUserManager.stub {
on { isAdminUser } doReturn false
}
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
}
@Test
fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
whenever(Utils.isWifiOnly(context)).thenReturn(true)
val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE) assertThat(availabilityStatus).isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE)
} }

View File

@@ -28,14 +28,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.AppOpsManager; import android.app.AppOpsManager;
import android.app.Flags;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -50,7 +48,6 @@ import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -188,7 +185,6 @@ public class ApprovalPreferenceControllerTest {
} }
@Test @Test
@EnableFlags(Flags.FLAG_MODES_API)
public void disable() { public void disable() {
when(mNm.isNotificationPolicyAccessGrantedForPackage(anyString())).thenReturn(false); when(mNm.isNotificationPolicyAccessGrantedForPackage(anyString())).thenReturn(false);
mController.disable(mCn); mController.disable(mCn);

View File

@@ -22,6 +22,8 @@ import static com.android.settings.connecteddevice.display.ExternalDisplayPrefer
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SETTINGS_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SETTINGS_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.PREVIOUSLY_SHOWN_LIST_KEY; import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.PREVIOUSLY_SHOWN_LIST_KEY;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.displayListDisplayCategoryKey;
import static com.android.settings.connecteddevice.display.ExternalDisplayPreferenceFragment.resolutionRotationPreferenceKey;
import static com.android.settings.flags.Flags.FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING; import static com.android.settings.flags.Flags.FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING;
import static com.android.settings.flags.Flags.FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST; import static com.android.settings.flags.Flags.FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST;
import static com.android.settingslib.widget.FooterPreference.KEY_FOOTER; import static com.android.settingslib.widget.FooterPreference.KEY_FOOTER;
@@ -79,6 +81,19 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
assertThat(mPreferenceIdFromResource).isEqualTo(EXTERNAL_DISPLAY_SETTINGS_RESOURCE); assertThat(mPreferenceIdFromResource).isEqualTo(EXTERNAL_DISPLAY_SETTINGS_RESOURCE);
} }
private void assertDisplayList(boolean present, int displayId) {
// In display list fragment, there is a combined resolution/rotation preference key.
var category = mPreferenceScreen.findPreference(displayListDisplayCategoryKey(displayId));
var pref = mPreferenceScreen.findPreference(resolutionRotationPreferenceKey(displayId));
if (present) {
assertThat(category).isNotNull();
assertThat(pref).isNotNull();
} else {
assertThat(category).isNull();
assertThat(pref).isNull();
}
}
@Test @Test
@UiThreadTest @UiThreadTest
public void testShowDisplayList() { public void testShowDisplayList() {
@@ -89,19 +104,26 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
fragment.onSaveInstanceStateCallback(outState); fragment.onSaveInstanceStateCallback(outState);
assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isFalse(); assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isFalse();
assertThat(mHandler.getPendingMessages().size()).isEqualTo(1); assertThat(mHandler.getPendingMessages().size()).isEqualTo(1);
PreferenceCategory pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key);
assertThat(pref).isNull(); // Combined resolution/refresh rate are not available in displays list because the pane is
// disabled (v1 UI).
assertDisplayList(false, EXTERNAL_DISPLAY_ID);
assertDisplayList(false, OVERLAY_DISPLAY_ID);
// Individual resolution preference is not available in displays list.
assertThat(mPreferenceScreen.<Preference>findPreference(
PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key))
.isNull();
verify(mMockedInjector, never()).getAllDisplays(); verify(mMockedInjector, never()).getAllDisplays();
mHandler.flush(); mHandler.flush();
assertThat(mHandler.getPendingMessages().size()).isEqualTo(0); assertThat(mHandler.getPendingMessages().size()).isEqualTo(0);
verify(mMockedInjector).getAllDisplays(); verify(mMockedInjector).getAllDisplays();
pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(true, EXTERNAL_DISPLAY_ID);
assertThat(pref).isNotNull(); assertDisplayList(true, OVERLAY_DISPLAY_ID);
assertThat(pref.getPreferenceCount()).isEqualTo(2);
fragment.onSaveInstanceStateCallback(outState); fragment.onSaveInstanceStateCallback(outState);
assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isTrue(); assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isTrue();
pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key); Preference pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key);
assertThat(pref).isNull(); assertThat(pref).isNull();
pref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key); pref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key);
@@ -122,8 +144,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key); pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key);
assertThat(pref).isNotNull(); assertThat(pref).isNotNull();
pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(false, mDisplays[1].getDisplayId());
assertThat(pref).isNull();
PreferenceCategory listPref = PreferenceCategory listPref =
mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key); mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key);
@@ -148,11 +169,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key); pref = mPreferenceScreen.findPreference(PrefBasics.MIRROR.key);
assertThat(pref).isNull(); assertThat(pref).isNull();
PreferenceCategory listPref = assertDisplayList(false, EXTERNAL_DISPLAY_ID);
mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(false, OVERLAY_DISPLAY_ID);
assertThat(listPref).isNull();
listPref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key); var listPref = mPreferenceScreen.findPreference(PrefBasics.BUILTIN_DISPLAY_LIST.key);
assertThat(listPref).isNull(); assertThat(listPref).isNull();
} }
@@ -161,19 +181,23 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
public void testLaunchDisplaySettingFromList() { public void testLaunchDisplaySettingFromList() {
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
PreferenceCategory pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(true, EXTERNAL_DISPLAY_ID);
assertThat(pref).isNotNull(); assertDisplayList(true, OVERLAY_DISPLAY_ID);
var display1Category = (PreferenceCategory) pref.getPreference(0); PreferenceCategory display1Category = mPreferenceScreen.findPreference(
displayListDisplayCategoryKey(EXTERNAL_DISPLAY_ID));
var display1Pref = (DisplayPreference) display1Category.getPreference(0); var display1Pref = (DisplayPreference) display1Category.getPreference(0);
var display2Category = (PreferenceCategory) pref.getPreference(1); PreferenceCategory display2Category = mPreferenceScreen.findPreference(
displayListDisplayCategoryKey(OVERLAY_DISPLAY_ID));
var display2Pref = (DisplayPreference) display2Category.getPreference(0); var display2Pref = (DisplayPreference) display2Category.getPreference(0);
assertThat(display1Pref.getKey()).isEqualTo("display_id_" + 1); assertThat(display1Pref.getKey()).isEqualTo(
resolutionRotationPreferenceKey(EXTERNAL_DISPLAY_ID));
assertThat("" + display1Category.getTitle()).isEqualTo("HDMI"); assertThat("" + display1Category.getTitle()).isEqualTo("HDMI");
assertThat("" + display1Pref.getSummary()).isEqualTo("1920 x 1080"); assertThat("" + display1Pref.getSummary()).isEqualTo("1920 x 1080");
display1Pref.onPreferenceClick(display1Pref); display1Pref.onPreferenceClick(display1Pref);
assertThat(mDisplayIdArg).isEqualTo(1); assertThat(mDisplayIdArg).isEqualTo(1);
verify(mMockedMetricsLogger).writePreferenceClickMetric(display1Pref); verify(mMockedMetricsLogger).writePreferenceClickMetric(display1Pref);
assertThat(display2Pref.getKey()).isEqualTo("display_id_" + 2); assertThat(display2Pref.getKey()).isEqualTo(
resolutionRotationPreferenceKey(OVERLAY_DISPLAY_ID));
assertThat("" + display2Category.getTitle()).isEqualTo("Overlay #1"); assertThat("" + display2Category.getTitle()).isEqualTo("Overlay #1");
assertThat("" + display2Pref.getSummary()).isEqualTo("1240 x 780"); assertThat("" + display2Pref.getSummary()).isEqualTo("1240 x 780");
display2Pref.onPreferenceClick(display2Pref); display2Pref.onPreferenceClick(display2Pref);
@@ -190,9 +214,12 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
// Only one display available // Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays();
mHandler.flush(); mHandler.flush();
PreferenceCategory pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); int attachedId = mDisplays[1].getDisplayId();
assertThat(pref).isNotNull(); assertDisplayList(true, attachedId);
assertThat(pref.getPreferenceCount()).isEqualTo(1); assertThat(mPreferenceScreen.<Preference>findPreference(
resolutionRotationPreferenceKey(attachedId)))
.isNotNull();
assertDisplayList(false, mDisplays[2].getDisplayId());
} }
@Test @Test
@@ -205,8 +232,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
// Init // Init
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
PreferenceCategory list = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(false, mDisplays[1].getDisplayId());
assertThat(list).isNull();
var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key);
assertThat(pref).isNotNull(); assertThat(pref).isNotNull();
pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key);
@@ -227,8 +253,8 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
// Init // Init
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
PreferenceCategory list = mPreferenceScreen.findPreference(PrefBasics.DISPLAYS_LIST.key); assertDisplayList(false, mDisplays[1].getDisplayId());
assertThat(list).isNull(); assertDisplayList(false, mDisplays[2].getDisplayId());
var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key); var pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.key);
assertThat(pref).isNotNull(); assertThat(pref).isNotNull();
pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key); pref = mPreferenceScreen.findPreference(PrefBasics.EXTERNAL_DISPLAY_ROTATION.key);

View File

@@ -49,6 +49,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
public class ExternalDisplayTestBase { public class ExternalDisplayTestBase {
static final int EXTERNAL_DISPLAY_ID = 1;
static final int OVERLAY_DISPLAY_ID = 2;
@Mock @Mock
ExternalDisplaySettingsConfiguration.Injector mMockedInjector; ExternalDisplaySettingsConfiguration.Injector mMockedInjector;
@Mock @Mock
@@ -115,7 +118,7 @@ public class ExternalDisplayTestBase {
} }
Display createExternalDisplay() throws RemoteException { Display createExternalDisplay() throws RemoteException {
int displayId = 1; int displayId = EXTERNAL_DISPLAY_ID;
var displayInfo = new DisplayInfo(); var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId); doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId; displayInfo.displayId = displayId;
@@ -134,7 +137,7 @@ public class ExternalDisplayTestBase {
} }
Display createOverlayDisplay() throws RemoteException { Display createOverlayDisplay() throws RemoteException {
int displayId = 2; int displayId = OVERLAY_DISPLAY_ID;
var displayInfo = new DisplayInfo(); var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId); doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId; displayInfo.displayId = displayId;

View File

@@ -35,6 +35,7 @@ import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.internal.app.LocaleStore; import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResourcesUtils; import com.android.settings.testutils.ResourcesUtils;
@@ -82,11 +83,9 @@ public class LocaleDialogFragmentTest {
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent = LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent(); controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString( assertEquals(R.string.button_label_confirmation_of_system_locale_change,
mContext, "button_label_confirmation_of_system_locale_change"),
dialogContent.mPositiveButton); dialogContent.mPositiveButton);
assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"), assertEquals(R.string.cancel, dialogContent.mNegativeButton);
dialogContent.mNegativeButton);
} }
@Test @Test
@@ -99,9 +98,8 @@ public class LocaleDialogFragmentTest {
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent = LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent(); controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString(mContext, "okay"), assertEquals(R.string.okay, dialogContent.mPositiveButton);
dialogContent.mPositiveButton); assertTrue(dialogContent.mNegativeButton == 0);
assertTrue(dialogContent.mNegativeButton.isEmpty());
} }
@Test @Test