Snap for 5171533 from 70dc967352 to qt-release

Change-Id: I044929d6e34b6ca8543737e7f823af42118e31a6
This commit is contained in:
android-build-team Robot
2018-12-09 04:10:39 +00:00
81 changed files with 1614 additions and 660 deletions

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 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="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,2C4.9,2 4.01,2.9 4.01,4L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8l-6,-6H6zM18,17.59l-2.2,-2.2c0.44,-0.69 0.7,-1.51 0.7,-2.39c0,-2.48 -2.02,-4.5 -4.5,-4.5S7.5,10.52 7.5,13s2.02,4.5 4.5,4.5c0.88,0 1.69,-0.26 2.39,-0.7l3.2,3.2L6,20V4h7.17L18,8.83V17.59zM12,15.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5S13.38,15.5 12,15.5z"/>
</vector>

View File

@@ -61,6 +61,7 @@
android:id="@+id/first_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
style="@style/ConditionHalfCardBorderlessButton"/>
</LinearLayout>

View File

@@ -21,24 +21,17 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:elevation="0dp">
<include layout="@layout/search_bar"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/main_content_scrollable_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="@dimen/app_bar_height"
android:descendantFocusability="blocksDescendants">
<FrameLayout
@@ -55,4 +48,10 @@
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/search_bar"/>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -15,6 +15,13 @@
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/search_app_list_menu"
android:title="@string/search_settings"
android:icon="@drawable/ic_find_in_page_24px"
android:showAsAction="always|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
<item
android:id="@+id/advanced"
android:title="@string/advanced_apps"

View File

@@ -1077,11 +1077,18 @@
<item>never</item>
</string-array>
<string-array name="zen_mode_contacts_entries" translatable="false">
<string-array name="zen_mode_contacts_messages_entries" translatable="false">
<item>@string/zen_mode_from_anyone</item>
<item>@string/zen_mode_from_contacts</item>
<item>@string/zen_mode_from_starred</item>
<item>@string/zen_mode_from_none</item>
<item>@string/zen_mode_from_none_calls</item>
</string-array>
<string-array name="zen_mode_contacts_calls_entries" translatable="false">
<item>@string/zen_mode_from_anyone</item>
<item>@string/zen_mode_from_contacts</item>
<item>@string/zen_mode_from_starred</item>
<item>@string/zen_mode_from_none_messages</item>
</string-array>
<string-array name="zen_mode_contacts_values" translatable="false">

View File

@@ -72,6 +72,14 @@
<attr name="allowDynamicSummaryInSlice" format="boolean" />
</declare-styleable>
<declare-styleable name="PreferenceScreen">
<!-- Determines if static preferences defined in addStaticPreferences are added before or after the radio buttons -->
<attr name="staticPreferenceLocation">
<enum name="prepend" value="0" />
<enum name="append" value="1" />
</attr>
</declare-styleable>
<!-- For DotsPageIndicator -->
<declare-styleable name="DotsPageIndicator">
<attr name="dotDiameter" format="dimension" />

View File

@@ -105,6 +105,8 @@
<dimen name="search_bar_avatar_size">32dp</dimen>
<dimen name="search_bar_avatar_start_margin">4dp</dimen>
<dimen name="search_bar_avatar_end_margin">16dp</dimen>
<!-- appbar height is equal search bar height (48dp) plus search bar top and bottom margin -->
<dimen name="app_bar_height">80dp</dimen>
<!-- Dimensions for Wifi Assistant Card -->
<dimen name="wifi_assistant_padding_top_bottom">16dp</dimen>

View File

@@ -670,7 +670,7 @@
<!-- check box cellular data title [CHAR LIMIT=30] -->
<string name="cellular_data_title">Mobile data</string>
<!-- check box Calls title [CHAR LIMIT=30] -->
<string name="calls_title">Calls</string>
<string name="calls_title">Allow calls</string>
<!-- check box SMS Messges title [CHAR LIMIT=30] -->
<string name="sms_messages_title">SMS messages</string>
<!-- check box cellular data summary [CHAR LIMIT=85] -->
@@ -2878,6 +2878,14 @@
<string name="status_prl_version">PRL version</string>
<!-- About phone screen, title for MEID for multi-sim devices -->
<string name="meid_multi_sim">MEID (sim slot %1$d)</string>
<!-- The status text when both Wi-Fi scanning and Bluetooth scanning are on. [CHAR LIMIT=120] -->
<string name="scanning_status_text_wifi_on_ble_on">Both Wi\u2011Fi and Bluetooth are allowed to determine location</string>
<!-- The status text when Wi-Fi scanning is on and Bluetooth scanning are off. [CHAR LIMIT=120] -->
<string name="scanning_status_text_wifi_on_ble_off">Only Wi\u2011Fi is allowed to determine location</string>
<!-- The status text when Wi-Fi scanning is off and Bluetooth scanning are on. [CHAR LIMIT=120] -->
<string name="scanning_status_text_wifi_off_ble_on">Only Bluetooth is allowed to determine location</string>
<!-- The status text when both Wi-Fi scanning and Bluetooth scanning are off. [CHAR LIMIT=120] -->
<string name="scanning_status_text_wifi_off_ble_off">Neither Wi\u2011Fi nor Bluetooth is allowed to determine location</string>
<!-- About phone, status item title. The phone MEID number of the current LTE/CDMA device. [CHAR LIMIT=30] -->
<string name="status_meid_number">MEID</string>
<!-- About phone, status item title. The ICCID of the current LTE device. [CHAR LIMIT=30] -->
@@ -3612,8 +3620,8 @@
<string name="location_high_battery_use">High battery use</string>
<!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
<string name="location_low_battery_use">Low battery use</string>
<!-- [CHAR LIMIT=30] Wireless background scanning settings screen, screen title -->
<string name="location_scanning_screen_title">Scanning</string>
<!-- [CHAR LIMIT=60] Wireless background scanning settings screen, screen title -->
<string name="location_scanning_screen_title">Wi\u2011Fi and Bluetooth scanning</string>
<!-- [CHAR LIMIT=130] Preference title for Wi-Fi always scanning -->
<string name="location_scanning_wifi_always_scanning_title">Wi\u2011Fi scanning</string>
<!-- Preference description text for Wi-Fi always scanning -->
@@ -5406,6 +5414,12 @@
<!-- Battery saver: Label for preference to turn on battery saver automatically when battery is low [CHAR_LIMIT=40] -->
<string name="battery_saver_auto_title">Turn on automatically</string>
<!-- Battery saver: Label for preference to indicate there is no battery saver schedule [CHAR_LIMIT=40] -->
<string name="battery_saver_auto_no_schedule">No schedule</string>
<!-- Battery saver: Title for battery saver schedule screen [CHAR_LIMIT=40] -->
<string name="battery_saver_schedule_settings_title">Set a schedule</string>
<!-- Battery saver: Label for seekbar to change battery saver threshold [CHAR_LIMIT=40] -->
<string name="battery_saver_seekbar_title">At <xliff:g id="percent">%1$s</xliff:g></string>
@@ -7083,8 +7097,8 @@
<!-- Sound: Summary for the Do not Disturb option when at least one automatic rules turned on. [CHAR LIMIT=NONE]-->
<plurals name="zen_mode_settings_summary_on">
<item quantity="one">1 rule</item>
<item quantity="other"><xliff:g id="on_count" example="10">%d</xliff:g> rules</item>
<item quantity="one">1 enabled</item>
<item quantity="other"><xliff:g id="on_count" example="10">%d</xliff:g> enabled</item>
</plurals>
<!-- Sound: Title for the Do not Disturb option and associated settings page. [CHAR LIMIT=50]-->
@@ -7124,10 +7138,10 @@
<string name="zen_mode_schedule_delete">Delete</string>
<!-- Do not disturb: Title for the zen mode automatic rules page in settings. [CHAR LIMIT=30] -->
<string name="zen_mode_automation_settings_page_title">Do Not Disturb</string>
<string name="zen_mode_automation_settings_page_title">Schedules</string>
<!-- Do not disturb: Title for a specific zen mode automatic rule in settings. [CHAR LIMIT=30] -->
<string name="zen_mode_automatic_rule_settings_page_title">Automatic rule</string>
<string name="zen_mode_automatic_rule_settings_page_title">Schedule</string>
<!-- Do not disturb: Title do not disturb settings representing automatic (scheduled) do not disturb rules. [CHAR LIMIT=30] -->
<string name="zen_mode_schedule_category_title">Schedule</string>
@@ -7142,7 +7156,7 @@
<string name="zen_mode_schedule_title">Schedule</string>
<!-- Do not disturb: Switch toggle to toggle whether to use an automatic dnd rule or not [CHAR LIMIT=40] -->
<string name="zen_mode_use_automatic_rule">Use rule</string>
<string name="zen_mode_use_automatic_rule">Use schedule</string>
<!-- Do not disturb: Zen mode option: Important interruptions [CHAR LIMIT=60] -->
<string name="zen_mode_option_important_interruptions">Priority only</string>
@@ -7166,7 +7180,7 @@
<string name="zen_mode_settings_category">When Do Not Disturb is on</string>
<!-- Do not disturb: restrict notifications title [CHAR LIMIT=80] -->
<string name="zen_mode_restrict_notifications_title">Notification restrictions</string>
<string name="zen_mode_restrict_notifications_title">Restrict notifications</string>
<!-- Do not disturb: Mute notifications option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_mute">No sound from notifications</string>
<!-- Do not disturb:Mute notifications summary [CHAR LIMIT=NONE] -->
@@ -7272,7 +7286,7 @@
<string name="zen_mode_sound_summary_on_with_info">On / <xliff:g name="dnd_summary" example="No sound except alarms and media">%1$s</xliff:g></string>
<!-- Sound settings screen, summary format of do not disturb when off with extra information. [CHAR LIMIT=NONE] -->
<string name="zen_mode_sound_summary_off_with_info">Off / <xliff:g name="dnd_summary" example="1 rule can turn on automatically">%1$s</xliff:g></string>
<string name="zen_mode_sound_summary_off_with_info">Off / <xliff:g name="dnd_summary" example="1 schedule can turn on automatically">%1$s</xliff:g></string>
<!-- Sound settings screen, summary format of do not disturb when off with no extra information. [CHAR LIMIT=NONE] -->
<string name="zen_mode_sound_summary_off">Off</string>
@@ -7297,12 +7311,12 @@
<!-- Summary for the Sound Do not Disturb option when at least one automatic rules is enabled. [CHAR LIMIT=NONE]-->
<plurals name="zen_mode_sound_summary_summary_off_info">
<item quantity="one">1 rule can turn on automatically</item>
<item quantity="other"><xliff:g id="on_count" example="3">%d</xliff:g> rules can turn on automatically</item>
<item quantity="one">1 schedule can turn on automatically</item>
<item quantity="other"><xliff:g id="on_count" example="3">%d</xliff:g> schedules can turn on automatically</item>
</plurals>
<!-- Do not disturb settings, category header [CHAR LIMIT=120]-->
<string name="zen_category_behavior">Mute phone, but allow exceptions</string>
<string name="zen_category_behavior">Mute device but allow exceptions</string>
<!-- Do not disturb settings, exceptions to dnd title [CHAR LIMIT=100]-->
<string name="zen_category_exceptions">Exceptions</string>
<!-- Do not disturb settings, category header [CHAR LIMIT=100]-->
@@ -7753,28 +7767,28 @@
<string name="zen_mode_rule_rename_button">Rename</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Rule name option and edit dialog title -->
<string name="zen_mode_rule_name">Rule name</string>
<string name="zen_mode_rule_name">Schedule name</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Rule name hint text -->
<string name="zen_mode_rule_name_hint">Enter rule name</string>
<string name="zen_mode_rule_name_hint">Enter schedule name</string>
<!-- [CHAR LIMIT=100] Zen mode settings: Warning text for invalid zen rule names -->
<string name="zen_mode_rule_name_warning">Rule name already in use</string>
<string name="zen_mode_rule_name_warning">Schedule name already in use</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Add another automatic zen rule option name-->
<string name="zen_mode_add_rule">Add more</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Add event-based rule, set rule name title -->
<string name="zen_mode_add_event_rule">Add event rule</string>
<string name="zen_mode_add_event_rule">Add event schedule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Add time-based rule, set rule name title -->
<string name="zen_mode_add_time_rule">Add time rule</string>
<string name="zen_mode_add_time_rule">Add time schedule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule menu option name -->
<string name="zen_mode_delete_rule">Delete rule</string>
<string name="zen_mode_delete_rule">Delete schedule</string>
<!-- [CHAR LIMIT=60] Zen mode settings: Choose rule type dialog title -->
<string name="zen_mode_choose_rule_type">Choose rule type</string>
<string name="zen_mode_choose_rule_type">Choose schedule type</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule dialog confirmation message -->
<string name="zen_mode_delete_rule_confirmation">Delete \u201c<xliff:g id="rule" example="Weekends">%1$s</xliff:g>\u201d rule?</string>
@@ -7855,7 +7869,7 @@
<string name="zen_mode_schedule_alarm_title">Alarm can override end time</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Downtime rule setting -->
<string name="zen_mode_schedule_alarm_summary">Stop at the end time or next alarm, whichever comes first</string>
<string name="zen_mode_schedule_alarm_summary">Schedule turns off when an alarm rings</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Title for preference to allow custom behavior for the dnd schedule -->
<string name="zen_mode_custom_behavior_title">Do Not Disturb behavior</string>
@@ -7876,10 +7890,10 @@
<string name="summary_range_verbal_combination"><xliff:g id="start" example="Sun">%1$s</xliff:g> to <xliff:g id="end" example="Thu">%2$s</xliff:g></string>
<!-- [CHAR LIMIT=20] Zen mode settings: Calls option -->
<string name="zen_mode_calls">Calls</string>
<string name="zen_mode_calls">Allow calls</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title -->
<string name="zen_mode_calls_title">Allow calls</string>
<string name="zen_mode_calls_title">Calls</string>
<!-- [CHAR LIMIT=20] Zen mode settings: Calls screen footer -->
<string name="zen_mode_calls_footer">When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
@@ -7894,25 +7908,13 @@
</plurals>
<!-- [CHAR LIMIT=20] Zen mode settings: Messages option -->
<string name="zen_mode_messages">Messages</string>
<string name="zen_mode_messages">Allow text messages</string>
<!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
<string name="zen_mode_messages_footer">When Do Not Disturb is on, incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Allow messages toggle title -->
<string name="zen_mode_messages_title">Allow messages</string>
<!-- [CHAR LIMIT=50] Zen mode settings: All messages summary -->
<string name="zen_mode_all_messages">Messages</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Messages option (ie: text messages) -->
<string name="zen_mode_all_messages_list">messages</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Selected messages summary -->
<string name="zen_mode_selected_messages">Some messages</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Selected messages (ie: some text messages are allowed to bypass dnd) -->
<string name="zen_mode_selected_messages_list">some messages</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Allow messages to bypass DND title -->
<string name="zen_mode_messages_title">Text messages</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls or messages option value: From anyone -->
<string name="zen_mode_from_anyone">From anyone</string>
@@ -7932,9 +7934,15 @@
<!-- Do not disturb settings, calls summary [CHAR LIMIT=100]-->
<string name="zen_calls_summary_repeat_only">From repeat callers only</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls or messages option value: None -->
<!-- [CHAR LIMIT=40] Zen mode settings: Calls and/or messages from none-->
<string name="zen_mode_from_none">None</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls option value: No calls allowed -->
<string name="zen_mode_from_none_calls">Don\u2019t allow any calls</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Messages option value: No messages allowed -->
<string name="zen_mode_from_none_messages">Don\u2019t allow any messages</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Allow alarms option -->
<string name="zen_mode_alarms">Allow alarms</string>
@@ -7942,7 +7950,7 @@
<string name="zen_mode_alarms_list">alarms</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Allow media (sound from video) to bypass dnd -->
<string name="zen_mode_media">Allow media</string>
<string name="zen_mode_media">Allow media sounds</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Media (ie: sound from video) -->
<string name="zen_mode_media_list">media</string>
@@ -7966,7 +7974,7 @@
<string name="zen_mode_bypassing_apps">Allow apps to override</string>
<!-- [CHAR LIMIT=100] Zen mode settings: Allow apps to bypass DND title-->
<string name="zen_mode_bypassing_apps_title">Overrides Do Not Disturb</string>
<string name="zen_mode_bypassing_apps_title">App exceptions</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Allow apps to bypass DND -->
<plurals name="zen_mode_bypassing_apps_subtext">
@@ -7997,10 +8005,10 @@
<string name="zen_mode_repeat_callers_title">Allow repeat callers</string>
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
<string name="zen_mode_calls_summary_one">From <xliff:g id="caller type" example="contacts">%1$s</xliff:g></string>
<string name="zen_mode_calls_summary_one">Allow from <xliff:g id="caller type" example="contacts">%1$s</xliff:g></string>
<!-- [CHAR LIMIT=50] Zen mode settings: calls summary -->
<string name="zen_mode_calls_summary_two">From <xliff:g id="caller type" example="starred contacts">%1$s</xliff:g> and <xliff:g id="callert tpye" example="repeat callers">%2$s</xliff:g></string>
<string name="zen_mode_calls_summary_two">Allow from <xliff:g id="caller type" example="starred contacts">%1$s</xliff:g> and <xliff:g id="callert tpye" example="repeat callers">%2$s</xliff:g></string>
<!-- [CHAR LIMIT=200] Zen mode settings: Repeat callers option summary -->
<string name="zen_mode_repeat_callers_summary">If the same person calls a second time within a <xliff:g id="minutes">%d</xliff:g> minute period</string>
@@ -8976,7 +8984,7 @@
<string name="condition_cellular_title">Mobile data is off</string>
<!-- Summary of condition that cellular data is off [CHAR LIMIT=NONE] -->
<string name="condition_cellular_summary">Internet is available only via Wi-Fi</string>
<string name="condition_cellular_summary">Internet only available via Wi\u2011Fi</string>
<!-- Title of condition that background data is off [CHAR LIMIT=30] -->
<string name="condition_bg_data_title">Data Saver</string>
@@ -8988,7 +8996,7 @@
<string name="condition_work_title">Work profile is off</string>
<!-- Summary of condition that work mode is off [CHAR LIMIT=NONE] -->
<string name="condition_work_summary">Apps, background sync, and other features related to your work profile are turned off.</string>
<string name="condition_work_summary">For apps &amp; notifications</string>
<!-- Action label on device muted card - clicking action will turn on ringtone sound [CHAR LIMIT=50] -->
<string name="condition_device_muted_action_turn_on_sound">Turn on sound</string>

View File

@@ -461,8 +461,9 @@
<style name="SearchBarStyle">
<item name="android:layout_margin">@dimen/search_bar_margin</item>
<item name="cardCornerRadius">8dp</item>
<item name="strokeColor">@color/homepage_card_stroke_color</item>
<item name="strokeWidth">1dp</item>
<item name="enforceMaterialTheme">true</item>
<item name="cardElevation">3dp</item>
<item name="shapeAppearance">@null</item>
</style>
<style name="ConditionCardBorderlessButton"

View File

@@ -17,27 +17,23 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="accessibility_content_timeout_preference"
android:title="@string/accessibility_content_timeout_preference_title"
android:persistent="false" >
<com.android.settings.widget.VideoPreference
android:key="accessibility_content_timeout_video"
app:animation="@raw/gesture_swipe_up"
app:preview="@drawable/gesture_swipe_up"
android:persistent="false" />
<Preference
android:key="accessibility_content_timeout_summary"
android:selectable="false"
android:enabled="true"
android:summary="@string/accessibility_content_timeout_preference_summary"
android:title="@string/summary_placeholder"
settings:animation="@raw/gesture_swipe_up"
settings:preview="@drawable/gesture_swipe_up"
settings:controller="com.android.settings.widget.VideoPreferenceController"
android:persistent="false" />
<com.android.settings.widget.RadioButtonPreference
android:key="accessibility_content_timeout_default"
android:title="@string/accessibility_timeout_default"
settings:allowDividerAbove="true"
android:persistent="false" />
<com.android.settings.widget.RadioButtonPreference
@@ -60,4 +56,8 @@
android:title="@string/accessibility_timeout_2mins"
android:persistent="false" />
<com.android.settingslib.widget.FooterPreference
android:title="@string/accessibility_content_timeout_preference_summary"
android:selectable="false" />
</PreferenceScreen>

View File

@@ -17,27 +17,23 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="accessibility_control_timeout_preference"
android:title="@string/accessibility_control_timeout_preference_title"
android:persistent="false" >
<com.android.settings.widget.VideoPreference
android:key="accessibility_control_timeout_video"
app:animation="@raw/gesture_swipe_up"
app:preview="@drawable/gesture_swipe_up"
android:persistent="false" />
<Preference
android:key="accessibility_control_timeout_summary"
android:selectable="false"
android:enabled="true"
android:summary="@string/accessibility_control_timeout_preference_summary"
android:title="@string/summary_placeholder"
settings:animation="@raw/gesture_swipe_up"
settings:preview="@drawable/gesture_swipe_up"
settings:controller="com.android.settings.widget.VideoPreferenceController"
android:persistent="false" />
<com.android.settings.widget.RadioButtonPreference
android:key="accessibility_control_timeout_default"
android:title="@string/accessibility_timeout_default"
settings:allowDividerAbove="true"
android:persistent="false" />
<com.android.settings.widget.RadioButtonPreference
@@ -60,4 +56,8 @@
android:title="@string/accessibility_timeout_2mins"
android:persistent="false" />
<com.android.settingslib.widget.FooterPreference
android:title="@string/accessibility_control_timeout_preference_summary"
android:selectable="false" />
</PreferenceScreen>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/battery_saver_schedule_settings_title"
settings:staticPreferenceLocation="append">
</PreferenceScreen >

View File

@@ -424,9 +424,6 @@
android:summary="%s"
android:title="@string/simulate_color_space" />
<Preference android:key="angle_enabled_app"
android:title="@string/angle_enabled_app" />
<Preference android:key="updated_gfx_driver_dev_opt_in_app"
android:summary="@string/updated_gfx_driver_dev_opt_in_app_summary"
android:title="@string/updated_gfx_driver_dev_opt_in_app" />

View File

@@ -21,13 +21,20 @@
android:title="@string/network_dashboard_title"
settings:initialExpandedChildrenCount="5">
<PreferenceCategory
android:key="multi_network_header"
settings:allowDividerBelow="true"
android:order="-40"
settings:controller="com.android.settings.network.MultiNetworkHeaderController"/>
<com.android.settings.widget.MasterSwitchPreference
android:fragment="com.android.settings.wifi.WifiSettings"
android:key="toggle_wifi"
android:title="@string/wifi_settings"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_settings_wireless"
android:order="-30">
android:order="-30"
settings:allowDividerAbove="true">
<intent
android:action="android.settings.WIFI_SETTINGS"
android:targetClass="Settings$WifiSettingsActivity" />
@@ -44,16 +51,15 @@
settings:useAdminDisabledSummary="true">
</com.android.settingslib.RestrictedPreference>
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.TetherSettings"
android:key="tether_settings"
android:title="@string/tether_settings_title_all"
android:icon="@drawable/ic_wifi_tethering"
<com.android.settingslib.RestrictedSwitchPreference
android:key="toggle_airplane"
android:title="@string/airplane_mode"
android:icon="@drawable/ic_airplanemode_active"
android:disableDependentsState="true"
android:order="-5"
android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_hotspot_tethering"
settings:userRestriction="no_config_tethering"
settings:useAdminDisabledSummary="true" />
settings:controller="com.android.settings.network.AirplaneModePreferenceController"
settings:platform_slice="true"
settings:userRestriction="no_airplane_mode"/>
<com.android.settingslib.RestrictedPreference
android:key="manage_mobile_plan"
@@ -63,20 +69,16 @@
settings:userRestriction="no_config_mobile_networks"
settings:useAdminDisabledSummary="true" />
<com.android.settingslib.RestrictedSwitchPreference
android:key="toggle_airplane"
android:title="@string/airplane_mode"
android:icon="@drawable/ic_airplanemode_active"
android:disableDependentsState="true"
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.TetherSettings"
android:key="tether_settings"
android:title="@string/tether_settings_title_all"
android:icon="@drawable/ic_wifi_tethering"
android:order="5"
settings:controller="com.android.settings.network.AirplaneModePreferenceController"
settings:platform_slice="true"
settings:userRestriction="no_airplane_mode"/>
<Preference
android:fragment="com.android.settings.ProxySelector"
android:key="proxy_settings"
android:title="@string/proxy_settings_title" />
android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_hotspot_tethering"
settings:userRestriction="no_config_tethering"
settings:useAdminDisabledSummary="true" />
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.vpn2.VpnSettings"

View File

@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="zen_mode_calls_settings_page"
android:title="@string/zen_mode_calls" >
android:title="@string/zen_mode_calls_title" >
<PreferenceCategory
android:title="@string/zen_mode_settings_category"
@@ -27,8 +27,8 @@
<!-- Calls -->
<ListPreference
android:key="zen_mode_calls"
android:title="@string/zen_mode_calls_title"
android:entries="@array/zen_mode_contacts_entries"
android:title="@string/zen_mode_calls"
android:entries="@array/zen_mode_contacts_calls_entries"
android:entryValues="@array/zen_mode_contacts_values"/>
<Preference

View File

@@ -18,7 +18,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="zen_mode_messages_settings_page"
android:title="@string/zen_mode_messages" >
android:title="@string/zen_mode_messages_title" >
<PreferenceCategory
android:title="@string/zen_mode_settings_category"
@@ -26,8 +26,8 @@
<!-- Messages -->
<ListPreference
android:key="zen_mode_messages"
android:title="@string/zen_mode_messages_title"
android:entries="@array/zen_mode_contacts_entries"
android:title="@string/zen_mode_messages"
android:entries="@array/zen_mode_contacts_messages_entries"
android:entryValues="@array/zen_mode_contacts_values"/>
<Preference

View File

@@ -27,13 +27,13 @@
<!-- Calls -->
<Preference
android:key="zen_mode_calls_settings"
android:title="@string/zen_mode_calls_title"
android:title="@string/zen_mode_calls"
android:fragment="com.android.settings.notification.ZenModeCallsSettings" />
<!-- Messages -->
<Preference
android:key="zen_mode_messages_settings"
android:title="@string/zen_mode_messages_title"
android:title="@string/zen_mode_messages"
android:fragment="com.android.settings.notification.ZenModeMessagesSettings" />
<!-- Alarms -->

View File

@@ -36,8 +36,9 @@ import java.util.List;
public class EmergencyInfoPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
public static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
private static final String KEY_EMERGENCY_INFO = "emergency_info";
private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
private static final String PACKAGE_NAME_EMERGENCY = "com.android.emergency";
public EmergencyInfoPreferenceController(Context context) {
@@ -57,7 +58,7 @@ public class EmergencyInfoPreferenceController extends AbstractPreferenceControl
public void updateState(Preference preference) {
UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
UserHandle.myUserId());
UserHandle.myUserId());
preference.setSummary(mContext.getString(R.string.emergency_info_summary, info.name));
}

View File

@@ -67,11 +67,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Filter;
import android.widget.FrameLayout;
import android.widget.SearchView;
import android.widget.Spinner;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -140,7 +143,7 @@ import java.util.Set;
* intent.
*/
public class ManageApplications extends InstrumentedFragment
implements View.OnClickListener, OnItemSelectedListener {
implements View.OnClickListener, OnItemSelectedListener, SearchView.OnQueryTextListener {
static final String TAG = "ManageApplications";
static final boolean DEBUG = true;
@@ -196,6 +199,7 @@ public class ManageApplications extends InstrumentedFragment
private View mListContainer;
private RecyclerView mRecyclerView;
private SearchView mSearchView;
// Size resource used for packages whose size computation failed for some reason
CharSequence mInvalidSizeStr;
@@ -599,6 +603,13 @@ public class ManageApplications extends InstrumentedFragment
mOptionsMenu = menu;
inflater.inflate(R.menu.manage_apps, menu);
final MenuItem searchMenuItem = menu.findItem(R.id.search_app_list_menu);
if (searchMenuItem != null) {
mSearchView = (SearchView) searchMenuItem.getActionView();
mSearchView.setQueryHint(getText(R.string.search_settings));
mSearchView.setOnQueryTextListener(this);
}
updateOptionsMenu();
}
@@ -724,6 +735,17 @@ public class ManageApplications extends InstrumentedFragment
public void onNothingSelected(AdapterView<?> parent) {
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
mApplications.filterSearch(newText);
return false;
}
public void updateView() {
updateOptionsMenu();
final Activity host = getActivity();
@@ -859,6 +881,7 @@ public class ManageApplications extends InstrumentedFragment
private AppFilterItem mAppFilter;
private ArrayList<ApplicationsState.AppEntry> mEntries;
private ArrayList<ApplicationsState.AppEntry> mOriginalEntries;
private boolean mResumed;
private int mLastSortMode = -1;
private int mWhichSize = SIZE_TOTAL;
@@ -866,6 +889,7 @@ public class ManageApplications extends InstrumentedFragment
private boolean mHasReceivedLoadEntries;
private boolean mHasReceivedBridgeCallback;
private FileViewHolderController mExtraViewController;
private SearchFilter mSearchFilter;
// This is to remember and restore the last scroll position when this
// fragment is paused. We need this special handling because app entries are added gradually
@@ -1100,6 +1124,13 @@ public class ManageApplications extends InstrumentedFragment
});
}
public void filterSearch(String query) {
if (mSearchFilter == null) {
mSearchFilter = new SearchFilter();
}
mSearchFilter.filter(query);
}
@VisibleForTesting
static boolean shouldUseStableItemHeight(int listType) {
return true;
@@ -1146,6 +1177,7 @@ public class ManageApplications extends InstrumentedFragment
entries = removeDuplicateIgnoringUser(entries);
}
mEntries = entries;
mOriginalEntries = entries;
notifyDataSetChanged();
if (getItemCount() == 0) {
mManageApplications.mRecyclerView.setVisibility(View.GONE);
@@ -1153,6 +1185,14 @@ public class ManageApplications extends InstrumentedFragment
} else {
mManageApplications.mEmptyView.setVisibility(View.GONE);
mManageApplications.mRecyclerView.setVisibility(View.VISIBLE);
if (mManageApplications.mSearchView != null
&& mManageApplications.mSearchView.isVisibleToUser()) {
final CharSequence query = mManageApplications.mSearchView.getQuery();
if (!TextUtils.isEmpty(query)) {
filterSearch(query.toString());
}
}
}
// Restore the last scroll position if the number of entries added so far is bigger than
// it.
@@ -1405,6 +1445,38 @@ public class ManageApplications extends InstrumentedFragment
}
}
}
/**
* An array filter that constrains the content of the array adapter with a substring.
* Item that does not contains the specified substring will be removed from the list.</p>
*/
private class SearchFilter extends Filter {
@WorkerThread
@Override
protected FilterResults performFiltering(CharSequence query) {
final ArrayList<ApplicationsState.AppEntry> matchedEntries;
if (TextUtils.isEmpty(query)) {
matchedEntries = mOriginalEntries;
} else {
matchedEntries = new ArrayList<>();
for (ApplicationsState.AppEntry entry : mOriginalEntries) {
if (entry.label.toLowerCase().contains(query.toString().toLowerCase())) {
matchedEntries.add(entry);
}
}
}
final FilterResults results = new FilterResults();
results.values = matchedEntries;
results.count = matchedEntries.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;
notifyDataSetChanged();
}
}
}
private static class SummaryProvider implements SummaryLoader.SummaryProvider {

View File

@@ -55,6 +55,8 @@ public class PreferenceXmlParserUtils {
private static final List<String> SUPPORTED_PREF_TYPES = Arrays.asList(
"Preference", "PreferenceCategory", "PreferenceScreen",
"com.android.settings.widget.WorkOnlyCategory");
public static final int PREPEND_VALUE = 0;
public static final int APPEND_VALUE = 1;
/**
* Flag definition to indicate which metadata should be extracted when
@@ -84,6 +86,7 @@ public class PreferenceXmlParserUtils {
int FLAG_NEED_KEYWORDS = 1 << 8;
int FLAG_NEED_SEARCHABLE = 1 << 9;
int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10;
int FLAG_NEED_PREF_APPEND = 1 << 11;
}
public static final String METADATA_PREF_TYPE = "type";
@@ -97,6 +100,7 @@ public class PreferenceXmlParserUtils {
public static final String METADATA_SEARCHABLE = "searchable";
public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE =
"allow_dynamic_summary_in_slice";
public static final String METADATA_APPEND = "staticPreferenceLocation";
private static final String ENTRIES_SEPARATOR = "|";
@@ -184,14 +188,13 @@ public class PreferenceXmlParserUtils {
// Parse next until start tag is found
}
final int outerDepth = parser.getDepth();
final boolean hasPrefScreenFlag = hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN);
do {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String nodeName = parser.getName();
if (!hasFlag(flags, MetadataFlag.FLAG_INCLUDE_PREF_SCREEN)
&& TextUtils.equals(PREF_SCREEN_TAG, nodeName)) {
if (!hasPrefScreenFlag && TextUtils.equals(PREF_SCREEN_TAG, nodeName)) {
continue;
}
if (!SUPPORTED_PREF_TYPES.contains(nodeName) && !nodeName.endsWith("Preference")) {
@@ -199,8 +202,14 @@ public class PreferenceXmlParserUtils {
}
final Bundle preferenceMetadata = new Bundle();
final AttributeSet attrs = Xml.asAttributeSet(parser);
final TypedArray preferenceAttributes = context.obtainStyledAttributes(attrs,
R.styleable.Preference);
TypedArray preferenceScreenAttributes = null;
if (hasPrefScreenFlag) {
preferenceScreenAttributes = context.obtainStyledAttributes(
attrs, R.styleable.PreferenceScreen);
}
if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_TYPE)) {
preferenceMetadata.putString(METADATA_PREF_TYPE, nodeName);
@@ -236,6 +245,10 @@ public class PreferenceXmlParserUtils {
preferenceMetadata.putBoolean(METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
isDynamicSummaryAllowed(preferenceAttributes));
}
if (hasFlag(flags, MetadataFlag.FLAG_NEED_PREF_APPEND) && hasPrefScreenFlag) {
preferenceMetadata.putBoolean(METADATA_APPEND,
isAppended(preferenceScreenAttributes));
}
metadata.add(preferenceMetadata);
preferenceAttributes.recycle();
@@ -325,7 +338,12 @@ public class PreferenceXmlParserUtils {
false /* default */);
}
private static String getKeywords(TypedArray styleAttributes) {
return styleAttributes.getString(R.styleable.Preference_keywords);
private static String getKeywords(TypedArray styledAttributes) {
return styledAttributes.getString(R.styleable.Preference_keywords);
}
private static boolean isAppended(TypedArray styledAttributes) {
return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation,
PREPEND_VALUE) == APPEND_VALUE;
}
}

View File

@@ -95,9 +95,13 @@ public class ChartDataUsagePreference extends Preference {
final SparseIntArray points = new SparseIntArray();
points.put(0, 0);
final long now = System.currentTimeMillis();
long totalData = 0;
for (NetworkCycleData data : usageSummary) {
final long startTime = data.getStartTime();
if (startTime > now) {
break;
}
final long endTime = data.getEndTime();
// increment by current bucket total

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) 2018 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.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
.REQUEST_CODE_ANGLE_ENABLED_APP;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class AngleEnabledAppPreferenceController extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin, OnActivityResultListener {
private static final String ANGLE_ENABLED_APP_KEY = "angle_enabled_app";
private final DevelopmentSettingsDashboardFragment mFragment;
private final PackageManager mPackageManager;
public AngleEnabledAppPreferenceController(Context context,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mPackageManager = mContext.getPackageManager();
}
@Override
public String getPreferenceKey() {
return ANGLE_ENABLED_APP_KEY;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (ANGLE_ENABLED_APP_KEY.equals(preference.getKey())) {
// pass it on to settings
final Intent intent = getActivityStartIntent();
mFragment.startActivityForResult(intent, REQUEST_CODE_ANGLE_ENABLED_APP);
return true;
}
return false;
}
@Override
public void updateState(Preference preference) {
updatePreferenceSummary();
}
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CODE_ANGLE_ENABLED_APP || resultCode != Activity.RESULT_OK) {
return false;
}
Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ANGLE_ENABLED_APP,
data.getAction());
updatePreferenceSummary();
return true;
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
mPreference.setSummary(mContext.getResources().getString(
R.string.angle_enabled_app_not_set));
}
@VisibleForTesting
Intent getActivityStartIntent() {
Intent intent = new Intent(mContext, AppPicker.class);
intent.putExtra(AppPicker.EXTRA_NON_SYSTEM, true /* value */);
return intent;
}
private void updatePreferenceSummary() {
final String angleEnabledApp = Settings.Global.getString(
mContext.getContentResolver(), Settings.Global.ANGLE_ENABLED_APP);
if (angleEnabledApp != null && angleEnabledApp.length() > 0) {
mPreference.setSummary(mContext.getResources().getString(
R.string.angle_enabled_app_set,
getAppLabel(angleEnabledApp)));
} else {
mPreference.setSummary(mContext.getResources().getString(
R.string.angle_enabled_app_not_set));
}
}
private String getAppLabel(String angleEnabledApp) {
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfo(angleEnabledApp,
PackageManager.GET_DISABLED_COMPONENTS);
final CharSequence lab = mPackageManager.getApplicationLabel(ai);
return lab != null ? lab.toString() : angleEnabledApp;
} catch (PackageManager.NameNotFoundException e) {
return angleEnabledApp;
}
}
}

View File

@@ -66,6 +66,25 @@ public class BluetoothA2dpHwOffloadPreferenceController extends DeveloperOptions
}
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
final boolean offloadSupported =
SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
if (offloadSupported) {
((SwitchPreference) mPreference).setChecked(false);
SystemProperties.set(A2DP_OFFLOAD_DISABLED_PROPERTY, "false");
}
}
public boolean isDefaultValue() {
final boolean offloadSupported =
SystemProperties.getBoolean(A2DP_OFFLOAD_SUPPORTED_PROPERTY, false);
final boolean offloadDisabled =
SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);
return offloadSupported ? !offloadDisabled : true;
}
public void onA2dpHwDialogConfirmed() {
final boolean offloadDisabled =
SystemProperties.getBoolean(A2DP_OFFLOAD_DISABLED_PROPERTY, false);

View File

@@ -26,7 +26,11 @@ public interface DevelopmentOptionsActivityRequestCodes {
int REQUEST_MOCK_LOCATION_APP = 2;
int REQUEST_CODE_ANGLE_ENABLED_APP = 3;
int REQUEST_CODE_ANGLE_ALL_USE_ANGLE = 3;
int REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP = 4;
int REQUEST_CODE_ANGLE_DRIVER_PKGS = 4;
int REQUEST_CODE_ANGLE_DRIVER_VALUES = 5;
int REQUEST_CODE_UPDATED_GFX_DRIVER_DEV_OPT_IN_APP = 6;
}

View File

@@ -221,7 +221,16 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
if (isChecked) {
EnableDevelopmentSettingWarningDialog.show(this /* host */);
} else {
disableDeveloperOptions();
final BluetoothA2dpHwOffloadPreferenceController controller =
getDevelopmentOptionsController(
BluetoothA2dpHwOffloadPreferenceController.class);
// If A2DP hardware offload isn't default value, we must reboot after disable
// developer options. Show a dialog for the user to confirm.
if (controller == null || controller.isDefaultValue()) {
disableDeveloperOptions();
} else {
DisableDevSettingsDialogFragment.show(this /* host */);
}
}
}
}
@@ -380,6 +389,15 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
mSwitchBar.setChecked(false);
}
void onDisableDevelopmentOptionsConfirmed() {
disableDeveloperOptions();
}
void onDisableDevelopmentOptionsRejected() {
// Reset the toggle
mSwitchBar.setChecked(true);
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
@@ -405,7 +423,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new SelectDebugAppPreferenceController(context, fragment));
controllers.add(new WaitForDebuggerPreferenceController(context));
controllers.add(new EnableGpuDebugLayersPreferenceController(context));
controllers.add(new AngleEnabledAppPreferenceController(context, fragment));
controllers.add(new UpdatedGfxDriverDevOptInPreferenceController(context, fragment));
controllers.add(new VerifyAppsOverUsbPreferenceController(context));
controllers.add(new LogdSizePreferenceController(context));

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2018 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.development;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.PowerManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class DisableDevSettingsDialogFragment extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
public static final String TAG = "DisableDevSettingDlg";
@VisibleForTesting
static DisableDevSettingsDialogFragment newInstance() {
final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
return dialog;
}
public static void show(DevelopmentSettingsDashboardFragment host) {
final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
dialog.setTargetFragment(host, 0 /* requestCode */);
final FragmentManager manager = host.getActivity().getSupportFragmentManager();
dialog.show(manager, TAG);
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DIALOG_DISABLE_DEVELOPMENT_OPTIONS;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Reuse the same text of disable_a2dp_hw_offload_dialog.
// The text is generic enough to be used for turning off Dev options.
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message)
.setTitle(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title)
.setPositiveButton(
R.string.bluetooth_disable_a2dp_hw_offload_dialog_confirm, this)
.setNegativeButton(
R.string.bluetooth_disable_a2dp_hw_offload_dialog_cancel, this)
.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
Fragment fragment = getTargetFragment();
if (!(fragment instanceof DevelopmentSettingsDashboardFragment)){
Log.e(TAG, "getTargetFragment return unexpected type");
}
final DevelopmentSettingsDashboardFragment host =
(DevelopmentSettingsDashboardFragment) fragment;
if (which == DialogInterface.BUTTON_POSITIVE) {
host.onDisableDevelopmentOptionsConfirmed();
PowerManager pm = getContext().getSystemService(PowerManager.class);
pm.reboot(null);
} else {
host.onDisableDevelopmentOptionsRejected();
}
}
}

View File

@@ -28,6 +28,7 @@ import android.content.IntentFilter;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.util.Log;
@@ -41,69 +42,78 @@ import androidx.slice.builders.SliceAction;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.SliceBroadcastReceiver;
import com.android.settings.slices.CustomSliceable;
/**
* Utility class to build a Flashlight Slice, and handle all associated actions.
*/
public class FlashlightSliceBuilder {
public class FlashlightSlice implements CustomSliceable {
private static final String TAG = "FlashlightSliceBuilder";
/**
* Action notifying a change on the Flashlight Slice.
*/
public static final String ACTION_FLASHLIGHT_SLICE_CHANGED =
"com.android.settings.flashlight.action.FLASHLIGHT_SLICE_CHANGED";
private static final String TAG = "FlashlightSlice";
/**
* Action broadcasting a change on whether flashlight is on or off.
*/
public static final String ACTION_FLASHLIGHT_CHANGED =
private static final String ACTION_FLASHLIGHT_CHANGED =
"com.android.settings.flashlight.action.FLASHLIGHT_CHANGED";
public static final IntentFilter INTENT_FILTER = new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
private final Context mContext;
private FlashlightSliceBuilder() {
public FlashlightSlice(Context context) {
mContext = context;
}
public static Slice getSlice(Context context) {
if (!isFlashlightAvailable(context)) {
@Override
public Slice getSlice() {
if (!isFlashlightAvailable(mContext)) {
return null;
}
final PendingIntent toggleAction = getBroadcastIntent(context);
@ColorInt final int color = Utils.getColorAccentDefaultColor(context);
final PendingIntent toggleAction = getBroadcastIntent(mContext);
@ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
final IconCompat icon =
IconCompat.createWithResource(context, R.drawable.ic_signal_flashlight);
return new ListBuilder(context, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
IconCompat.createWithResource(mContext, R.drawable.ic_signal_flashlight);
return new ListBuilder(mContext, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(new RowBuilder()
.setTitle(context.getText(R.string.power_flashlight))
.setTitle(mContext.getText(R.string.power_flashlight))
.setTitleItem(icon, ICON_IMAGE)
.setPrimaryAction(
SliceAction.createToggle(toggleAction, null, isFlashlightEnabled(context))))
SliceAction.createToggle(toggleAction, null,
isFlashlightEnabled(mContext))))
.build();
}
/**
* Update the current flashlight status to the boolean value keyed by
* {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
*/
public static void handleUriChange(Context context, Intent intent) {
@Override
public Uri getUri() {
return CustomSliceRegistry.FLASHLIGHT_SLICE_URI;
}
@Override
public IntentFilter getIntentFilter() {
return new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
}
@Override
public void onNotifyChange(Intent intent) {
try {
final String cameraId = getCameraId(context);
final String cameraId = getCameraId(mContext);
if (cameraId != null) {
final boolean state = intent.getBooleanExtra(
EXTRA_TOGGLE_STATE, isFlashlightEnabled(context));
final CameraManager cameraManager = context.getSystemService(CameraManager.class);
EXTRA_TOGGLE_STATE, isFlashlightEnabled(mContext));
final CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
cameraManager.setTorchMode(cameraId, state);
}
} catch (CameraAccessException e) {
Log.e(TAG, "Camera couldn't set torch mode.", e);
}
context.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
mContext.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
}
@Override
public Intent getIntent() {
return null;
}
private static String getCameraId(Context context) throws CameraAccessException {
@@ -121,12 +131,6 @@ public class FlashlightSliceBuilder {
return null;
}
private static PendingIntent getBroadcastIntent(Context context) {
final Intent intent = new Intent(ACTION_FLASHLIGHT_SLICE_CHANGED);
intent.setClass(context, SliceBroadcastReceiver.class);
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
private static boolean isFlashlightAvailable(Context context) {
return Settings.Secure.getInt(

View File

@@ -16,8 +16,10 @@
package com.android.settings.homepage.contextualcards;
import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -25,6 +27,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.slice.widget.EventInfo;
import com.android.settings.R;
import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import java.util.List;
@@ -38,10 +41,6 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
// Contextual card shows, log card name and rank
private static final int CONTEXTUAL_CARD_SHOW = 39;
// Contextual card is eligible to be shown, but doesn't rank high
// enough, log card name and score
private static final int CONTEXTUAL_CARD_NOT_SHOW = 40;
// Contextual card is dismissed, log card name
private static final int CONTEXTUAL_CARD_DISMISS = 41;
@@ -67,6 +66,11 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
// log type
private static final String EXTRA_CONTEXTUALCARD_ACTION_TYPE = "type";
// displayed contextual cards
private static final String EXTRA_CONTEXTUALCARD_VISIBLE = "visible";
// hidden contextual cards
private static final String EXTRA_CONTEXTUALCARD_HIDDEN = "hidden";
// Contextual card tap target
private static final int TARGET_DEFAULT = 0;
@@ -82,6 +86,10 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
@Override
public void logHomepageDisplay(Context context, Long latency) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW);
intent.putExtra(EXTRA_LATENCY, latency);
sendBroadcast(context, intent);
}
@Override
@@ -94,8 +102,13 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
}
@Override
public void logContextualCardDisplay(Context context, List<ContextualCard> showCards,
public void logContextualCardDisplay(Context context, List<ContextualCard> visibleCards,
List<ContextualCard> hiddenCards) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_SHOW);
intent.putExtra(EXTRA_CONTEXTUALCARD_VISIBLE, serialize(visibleCards));
intent.putExtra(EXTRA_CONTEXTUALCARD_HIDDEN, serialize(hiddenCards));
sendBroadcast(context, intent);
}
@Override
@@ -116,7 +129,7 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
final String action = context.getString(R.string.config_settingsintelligence_log_action);
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
context.sendBroadcast(intent);
context.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
@@ -133,4 +146,16 @@ public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureP
return TARGET_DEFAULT;
}
}
@VisibleForTesting
@NonNull
byte[] serialize(List<ContextualCard> cards) {
final ContextualCardList.Builder builder = ContextualCardList.newBuilder();
cards.stream().forEach(card -> builder.addCard(
com.android.settings.intelligence.ContextualCardProto.ContextualCard.newBuilder()
.setSliceUri(card.getSliceUri().toString())
.setCardName(card.getName())
.build()));
return builder.build().toByteArray();
}
}

View File

@@ -20,6 +20,9 @@ import static android.app.slice.Slice.HINT_ERROR;
import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
import static com.android.settings.slices.CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI;
import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
@@ -34,7 +37,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.slice.Slice;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList;
@@ -103,27 +106,50 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
return getFinalDisplayableCards(result);
}
// Get final displayed cards and log what cards will be displayed/hidden
@VisibleForTesting
List<ContextualCard> getFinalDisplayableCards(List<ContextualCard> candidates) {
List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
eligibleCards = eligibleCards.stream().limit(DEFAULT_CARD_COUNT).collect(
Collectors.toList());
final List<ContextualCard> eligibleCards = filterEligibleCards(candidates);
final List<ContextualCard> visibleCards = new ArrayList<>();
final List<ContextualCard> hiddenCards = new ArrayList<>();
if (eligibleCards.size() <= 2 || getNumberOfLargeCard(eligibleCards) == 0) {
return eligibleCards;
final int size = eligibleCards.size();
for (int i = 0; i < size; i++) {
if (i < DEFAULT_CARD_COUNT) {
visibleCards.add(eligibleCards.get(i));
} else {
hiddenCards.add(eligibleCards.get(i));
}
}
if (eligibleCards.size() == DEFAULT_CARD_COUNT) {
eligibleCards.remove(eligibleCards.size() - 1);
try {
// The maximum cards are four small cards OR
// one large card with two small cards OR
// two large cards
if (visibleCards.size() <= 2 || getNumberOfLargeCard(visibleCards) == 0) {
// four small cards
return visibleCards;
}
if (visibleCards.size() == DEFAULT_CARD_COUNT) {
hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
}
if (getNumberOfLargeCard(visibleCards) == 1) {
// One large card with two small cards
return visibleCards;
}
hiddenCards.add(visibleCards.remove(visibleCards.size() - 1));
// Two large cards
return visibleCards;
} finally {
final ContextualCardFeatureProvider contextualCardFeatureProvider =
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
contextualCardFeatureProvider.logContextualCardDisplay(mContext, visibleCards,
hiddenCards);
}
if (getNumberOfLargeCard(eligibleCards) == 1) {
return eligibleCards;
}
eligibleCards.remove(eligibleCards.size() - 1);
return eligibleCards;
}
@VisibleForTesting
@@ -169,8 +195,8 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
private int getNumberOfLargeCard(List<ContextualCard> cards) {
return (int) cards.stream()
.filter(card -> card.getSliceUri().equals(CustomSliceRegistry.WIFI_SLICE_URI)
|| card.getSliceUri().equals(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI))
.filter(card -> card.getSliceUri().equals(WIFI_SLICE_URI)
|| card.getSliceUri().equals(CONNECTED_DEVICE_SLICE_URI))
.count();
}

View File

@@ -16,8 +16,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader
.CARD_CONTENT_LOADER_ID;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
import static java.util.stream.Collectors.groupingBy;
@@ -33,6 +32,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -72,6 +72,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
private final List<LifecycleObserver> mLifecycleObservers;
private ContextualCardUpdateListener mListener;
private long mStartTime;
public ContextualCardManager(Context context, Lifecycle lifecycle) {
mContext = context;
@@ -86,6 +87,7 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
}
void loadContextualCards(ContextualCardsFragment fragment) {
mStartTime = System.currentTimeMillis();
final CardContentLoaderCallbacks cardContentLoaderCallbacks =
new CardContentLoaderCallbacks(mContext);
cardContentLoaderCallbacks.setListener(this);
@@ -168,6 +170,10 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
@Override
public void onFinishCardLoading(List<ContextualCard> cards) {
onContextualCardUpdated(cards.stream().collect(groupingBy(ContextualCard::getCardType)));
final long elapsedTime = System.currentTimeMillis() - mStartTime;
final ContextualCardFeatureProvider contextualCardFeatureProvider =
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
contextualCardFeatureProvider.logHomepageDisplay(mContext, elapsedTime);
}
public ControllerRendererPool getControllerRendererPool() {

View File

@@ -16,8 +16,6 @@
package com.android.settings.homepage.contextualcards.deviceinfo;
import static com.android.settings.slices.CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -37,6 +35,7 @@ import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBuilderUtils;
@@ -66,7 +65,8 @@ public class BatterySlice implements CustomSliceable {
final CharSequence title = mContext.getText(R.string.power_usage_summary_title);
final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
ListBuilder.ICON_IMAGE, title);
final Slice slice = new ListBuilder(mContext, BATTERY_INFO_SLICE_URI, ListBuilder.INFINITY)
final Slice slice = new ListBuilder(mContext, CustomSliceRegistry.BATTERY_INFO_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
.setHeader(new ListBuilder.HeaderBuilder().setTitle(title))
.addRow(new ListBuilder.RowBuilder()
@@ -81,7 +81,7 @@ public class BatterySlice implements CustomSliceable {
@Override
public Uri getUri() {
return BATTERY_INFO_SLICE_URI;
return CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
}
@Override
@@ -95,7 +95,8 @@ public class BatterySlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
PowerUsageSummary.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.BATTERY_INFO_SLICE_URI);
}
@Override

View File

@@ -94,7 +94,8 @@ public class DataUsageSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
DataUsageSummary.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.DATA_USAGE_SLICE_URI);
}
private PendingIntent getPrimaryAction() {

View File

@@ -85,7 +85,8 @@ public class DeviceInfoSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
MyDeviceInfoFragment.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.DEVICE_INFO_SLICE_URI);
}
private PendingIntent getPrimaryAction() {

View File

@@ -16,9 +16,12 @@
package com.android.settings.homepage.contextualcards.deviceinfo;
import static com.android.settings.accounts.EmergencyInfoPreferenceController.ACTION_EDIT_EMERGENCY_INFO;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -27,37 +30,57 @@ import androidx.slice.builders.SliceAction;
import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
// This is a slice helper class for EmergencyInfo
public class EmergencyInfoSlice {
public class EmergencyInfoSlice implements CustomSliceable {
private static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
private final Context mContext;
public static Slice getSlice(Context context) {
final ListBuilder listBuilder = new ListBuilder(context,
public EmergencyInfoSlice(Context context) {
mContext = context;
}
@Override
public Slice getSlice() {
final ListBuilder listBuilder = new ListBuilder(mContext,
CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI,
ListBuilder.INFINITY);
listBuilder.addRow(
new ListBuilder.RowBuilder()
.setTitle(context.getText(R.string.emergency_info_title))
.setTitle(mContext.getText(R.string.emergency_info_title))
.setSubtitle(
context.getText(R.string.emergency_info_contextual_card_summary))
.setPrimaryAction(createPrimaryAction(context)));
mContext.getText(R.string.emergency_info_contextual_card_summary))
.setPrimaryAction(createPrimaryAction()));
return listBuilder.build();
}
private static SliceAction createPrimaryAction(Context context) {
PendingIntent pendingIntent =
@Override
public Uri getUri() {
return CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI;
}
@Override
public Intent getIntent() {
return new Intent(ACTION_EDIT_EMERGENCY_INFO);
}
@Override
public void onNotifyChange(Intent intent) {
}
private SliceAction createPrimaryAction() {
final PendingIntent pendingIntent =
PendingIntent.getActivity(
context,
mContext,
0 /* requestCode */,
new Intent(ACTION_EDIT_EMERGENCY_INFO),
getIntent(),
PendingIntent.FLAG_UPDATE_CURRENT);
return SliceAction.createDeeplink(
pendingIntent,
IconCompat.createWithResource(context, R.drawable.empty_icon),
IconCompat.createWithResource(mContext, R.drawable.empty_icon),
ListBuilder.ICON_IMAGE,
context.getText(R.string.emergency_info_title));
mContext.getText(R.string.emergency_info_title));
}
}

View File

@@ -80,7 +80,8 @@ public class StorageSlice implements CustomSliceable {
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
StorageDashboardFragment.class.getName(), "" /* key */, screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.STORAGE_SLICE_URI);
}
private PendingIntent getPrimaryAction() {

View File

@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards.slices;
import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +41,7 @@ import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.bluetooth.BluetoothPairingDetail;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.slices.CustomSliceRegistry;
@@ -48,7 +50,6 @@ import com.android.settings.slices.SliceBuilderUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.ArrayList;
import java.util.Collection;
@@ -73,6 +74,12 @@ public class ConnectedDeviceSlice implements CustomSliceable {
private static final Comparator<CachedBluetoothDevice> COMPARATOR
= Comparator.naturalOrder();
/**
* Add the "Pair new device" in the end of slice, when the number of Bluetooth devices is less
* than {@link #DEFAULT_EXPANDED_ROW_COUNT}.
*/
private static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
private static final String TAG = "ConnectedDeviceSlice";
private final Context mContext;
@@ -131,10 +138,16 @@ public class ConnectedDeviceSlice implements CustomSliceable {
.setSubtitle(getSubTitle(rows.size()))
.setPrimaryAction(primarySliceAction));
// Add rows.
// Add bluetooth device rows.
for (ListBuilder.RowBuilder rowBuilder : rows) {
listBuilder.addRow(rowBuilder);
}
// Add "Pair new device" if need.
if (rows.size() < DEFAULT_EXPANDED_ROW_COUNT) {
listBuilder.addRow(getPairNewDeviceRowBuilder());
}
return listBuilder.build();
}
@@ -147,7 +160,8 @@ public class ConnectedDeviceSlice implements CustomSliceable {
ConnectedDeviceDashboardFragment.class.getName(), "" /* key */,
screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI);
}
@Override
@@ -193,7 +207,7 @@ public class ConnectedDeviceSlice implements CustomSliceable {
subSettingLauncher.setDestination(BluetoothDeviceDetailsFragment.class.getName())
.setArguments(args)
.setTitleRes(R.string.device_details_title)
.setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN);
.setSourceMetricsCategory(SettingsEnums.BLUETOOTH_DEVICE_DETAILS);
// The requestCode should be unique, use the hashcode of device as request code.
return PendingIntent
@@ -243,4 +257,28 @@ public class ConnectedDeviceSlice implements CustomSliceable {
return mContext.getResources().getQuantityString(R.plurals.show_connected_devices,
deviceCount, deviceCount);
}
private ListBuilder.RowBuilder getPairNewDeviceRowBuilder() {
final CharSequence title = mContext.getText(R.string.bluetooth_pairing_pref_title);
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_menu_add);
final SliceAction sliceAction = SliceAction.createDeeplink(
getPairNewDeviceIntent(),
IconCompat.createWithResource(mContext, R.drawable.ic_settings),
ListBuilder.ICON_IMAGE, title);
return new ListBuilder.RowBuilder()
.setTitleItem(icon, ListBuilder.ICON_IMAGE)
.setTitle(title)
.setPrimaryAction(sliceAction);
}
private PendingIntent getPairNewDeviceIntent() {
final Intent intent = new SubSettingLauncher(mContext)
.setDestination(BluetoothPairingDetail.class.getName())
.setTitleRes(R.string.bluetooth_pairing_page_title)
.setSourceMetricsCategory(SettingsEnums.BLUETOOTH_PAIRING)
.toIntent();
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
}
}

View File

@@ -110,7 +110,8 @@ public class LowStorageSlice implements CustomSliceable {
StorageSettings.class.getName(), "" /* key */,
screenTitle,
MetricsProto.MetricsEvent.SLICE)
.setClassName(mContext.getPackageName(), SubSettings.class.getName());
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(CustomSliceRegistry.LOW_STORAGE_SLICE_URI);
}
private RowBuilder buildRowBuilder(CharSequence title, String summary, IconCompat icon) {

View File

@@ -41,6 +41,7 @@ import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.CardContentProvider;
import com.android.settings.homepage.contextualcards.ContextualCard;
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.homepage.contextualcards.ContextualCardRenderer;
@@ -60,7 +61,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
private static final String TAG = "SliceCardRenderer";
@VisibleForTesting
final Map<String, LiveData<Slice>> mSliceLiveDataMap;
final Map<Uri, LiveData<Slice>> mSliceLiveDataMap;
@VisibleForTesting
final Set<SliceViewHolder> mFlippedCardSet;
@@ -94,9 +95,9 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
public void bindView(RecyclerView.ViewHolder holder, ContextualCard card) {
final SliceViewHolder cardHolder = (SliceViewHolder) holder;
final Uri uri = card.getSliceUri();
//TODO(b/120629936): Take this out once blank card issue is fixed.
Log.d(TAG, "bindView - uri = " + uri);
//TODO(b/116063073): The URI check should be done earlier when we are performing final
// filtering after having the full list.
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Log.w(TAG, "Invalid uri, skipping slice: " + uri);
return;
@@ -106,11 +107,11 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
cardHolder.sliceView.setTag(uri);
//TODO(b/114009676): We will soon have a field to decide what slice mode we should set.
cardHolder.sliceView.setMode(SliceView.MODE_LARGE);
LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri.toString());
LiveData<Slice> sliceLiveData = mSliceLiveDataMap.get(uri);
if (sliceLiveData == null) {
sliceLiveData = SliceLiveData.fromUri(mContext, uri);
mSliceLiveDataMap.put(uri.toString(), sliceLiveData);
mSliceLiveDataMap.put(uri, sliceLiveData);
}
mCardSet.add(card);
@@ -118,6 +119,11 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
sliceLiveData.observe(mLifecycleOwner, slice -> {
if (slice == null) {
Log.w(TAG, "Slice is null");
mContext.getContentResolver().notifyChange(CardContentProvider.URI, null);
return;
} else {
//TODO(b/120629936): Take this out once blank card issue is fixed.
Log.d(TAG, "Slice callback - uri = " + slice.getUri());
}
cardHolder.sliceView.setSlice(slice);
});
@@ -146,6 +152,7 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer,
mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
cardHolder.resetCard();
mFlippedCardSet.remove(cardHolder);
mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
});
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.location;
import android.content.Context;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
@@ -25,11 +26,31 @@ import com.android.settings.core.BasePreferenceController;
public class LocationScanningPreferenceController extends BasePreferenceController {
@VisibleForTesting static final String KEY_LOCATION_SCANNING = "location_scanning";
private final Context mContext;
public LocationScanningPreferenceController(Context context) {
super(context, KEY_LOCATION_SCANNING);
mContext = context;
}
@Override
public CharSequence getSummary() {
final boolean wifiScanOn = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1;
final boolean bleScanOn = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
int resId;
if (wifiScanOn && bleScanOn) {
resId = R.string.scanning_status_text_wifi_on_ble_on;
} else if (wifiScanOn && !bleScanOn) {
resId = R.string.scanning_status_text_wifi_on_ble_off;
} else if (!wifiScanOn && bleScanOn) {
resId = R.string.scanning_status_text_wifi_off_ble_on;
} else {
resId = R.string.scanning_status_text_wifi_off_ble_off;
}
return mContext.getString(resId);
}
@AvailabilityStatus

View File

@@ -38,29 +38,31 @@ import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.Utils;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBuilderUtils;
/**
* Utility class to build an intent-based Location Slice.
*/
public class LocationSliceBuilder {
public class LocationSlice implements CustomSliceable {
private LocationSliceBuilder() {
private final Context mContext;
public LocationSlice(Context context) {
mContext = context;
}
/**
* Return a Location Slice bound to {@link CustomSliceRegistry#LOCATION_SLICE_URI}.
*/
public static Slice getSlice(Context context) {
final IconCompat icon = IconCompat.createWithResource(context,
@Override
public Slice getSlice() {
final IconCompat icon = IconCompat.createWithResource(mContext,
R.drawable.ic_signal_location);
final String title = context.getString(R.string.location_settings_title);
@ColorInt final int color = Utils.getColorAccentDefaultColor(context);
final PendingIntent primaryAction = getPrimaryAction(context);
final CharSequence title = mContext.getText(R.string.location_settings_title);
@ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
final PendingIntent primaryAction = getPrimaryAction();
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
ListBuilder.ICON_IMAGE, title);
return new ListBuilder(context, CustomSliceRegistry.LOCATION_SLICE_URI,
return new ListBuilder(mContext, CustomSliceRegistry.LOCATION_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(new RowBuilder()
@@ -70,19 +72,30 @@ public class LocationSliceBuilder {
.build();
}
public static Intent getIntent(Context context) {
final String screenTitle = context.getText(R.string.location_settings_title).toString();
@Override
public Uri getUri() {
return CustomSliceRegistry.LOCATION_SLICE_URI;
}
@Override
public void onNotifyChange(Intent intent) {
}
@Override
public Intent getIntent() {
final String screenTitle = mContext.getText(R.string.location_settings_title).toString();
final Uri contentUri = new Uri.Builder().appendPath(KEY_LOCATION).build();
return SliceBuilderUtils.buildSearchResultPageIntent(context,
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
LocationSettings.class.getName(), KEY_LOCATION, screenTitle,
MetricsEvent.LOCATION)
.setClassName(context.getPackageName(), SubSettings.class.getName())
.setClassName(mContext.getPackageName(), SubSettings.class.getName())
.setData(contentUri);
}
private static PendingIntent getPrimaryAction(Context context) {
final Intent intent = getIntent(context);
return PendingIntent.getActivity(context, 0 /* requestCode */,
private PendingIntent getPrimaryAction() {
final Intent intent = getIntent();
return PendingIntent.getActivity(mContext, 0 /* requestCode */,
intent, 0 /* flags */);
}
}

View File

@@ -167,7 +167,7 @@ public class ApnEditor extends SettingsPreferenceFragment
Telephony.Carriers.ROAMING_PROTOCOL, // 20
Telephony.Carriers.MVNO_TYPE, // 21
Telephony.Carriers.MVNO_MATCH_DATA, // 22
Telephony.Carriers.EDITED, // 23
Telephony.Carriers.EDITED_STATUS, // 23
Telephony.Carriers.USER_EDITABLE //24
};
@@ -1035,7 +1035,7 @@ public class ApnEditor extends SettingsPreferenceFragment
callUpdate,
CARRIER_ENABLED_INDEX);
values.put(Telephony.Carriers.EDITED, Telephony.Carriers.USER_EDITED);
values.put(Telephony.Carriers.EDITED_STATUS, Telephony.Carriers.USER_EDITED);
if (callUpdate) {
final Uri uri = mApnData.getUri() == null ? mCarrierUri : mApnData.getUri();

View File

@@ -82,7 +82,7 @@ public class ApnSettings extends RestrictedSettingsFragment {
Telephony.Carriers.TYPE,
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
Telephony.Carriers.EDITED,
Telephony.Carriers.EDITED_STATUS,
};
private static final int ID_INDEX = 0;

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 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.network;
import android.content.Context;
import com.android.settings.core.BasePreferenceController;
// This controls a header at the top of the Network & internet page that only appears when there
// are two or more active mobile subscriptions. It shows an overview of available network
// connections with an entry for wifi (if connected) and an entry for each subscription.
public class MultiNetworkHeaderController extends BasePreferenceController {
public MultiNetworkHeaderController(Context context, String key) {
super(context, key);
}
@Override
public int getAvailabilityStatus() {
return UNSUPPORTED_ON_DEVICE;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 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.network;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SubscriptionUtil {
public static List<SubscriptionInfo> getAvailableSubscriptions(SubscriptionManager manager) {
List<SubscriptionInfo> subscriptions = manager.getAvailableSubscriptionInfoList();
if (subscriptions == null) {
subscriptions = new ArrayList<>();
}
// With some carriers such as Google Fi which provide a sort of virtual service that spans
// across multiple underlying networks, we end up with subscription entries for the
// underlying networks that need to be hidden from the user in the UI.
for (Iterator<SubscriptionInfo> iter = subscriptions.iterator(); iter.hasNext(); ) {
SubscriptionInfo info = iter.next();
if (TextUtils.isEmpty(info.getMncString())) {
iter.remove();
}
}
return subscriptions;
}
}

View File

@@ -22,7 +22,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -131,16 +130,12 @@ public class MobileDataPreferenceController extends TogglePreferenceController
@VisibleForTesting
boolean isDialogNeeded() {
final boolean enableData = !mTelephonyManager.isDataEnabled();
final SubscriptionInfo currentSir = mSubscriptionManager.getActiveSubscriptionInfo(
mSubId);
final SubscriptionInfo nextSir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
final boolean isMultiSim = (mTelephonyManager.getSimCount() > 1);
final boolean isMultipleDataOnCapable =
(mTelephonyManager.getNumberOfModemsWithSimultaneousDataConnections() > 1);
final boolean isDefaultDataSubscription = (nextSir != null && currentSir != null
&& currentSir.getSubscriptionId() == nextSir.getSubscriptionId());
final int defaultSubId = mSubscriptionManager.getDefaultDataSubscriptionId();
final boolean needToDisableOthers = mSubscriptionManager
.isActiveSubscriptionId(defaultSubId) && defaultSubId != mSubId;
if (enableData) {
if (isMultiSim && !isMultipleDataOnCapable && !isDefaultDataSubscription) {
if (isMultiSim && needToDisableOthers) {
mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG;
return true;
}

View File

@@ -230,7 +230,8 @@ public class MobileNetworkUtils {
subscriptionManager.getActiveSubscriptionInfoList();
if (subInfoList != null) {
for (SubscriptionInfo subInfo : subInfoList) {
if (subInfo.getSubscriptionId() != subId) {
// We never disable mobile data for opportunistic subscriptions.
if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) {
context.getSystemService(TelephonyManager.class).createForSubscriptionId(
subInfo.getSubscriptionId()).setDataEnabled(false);
}

View File

@@ -73,8 +73,7 @@ public class ZenModeAutomaticRulesPreferenceController extends
// 2. rule was added or deleted, so reload the entire list
if (Objects.equals(pref.mId, sortedRules[i].getKey())) {
AutomaticZenRule rule = sortedRules[i].getValue();
pref.setName(rule.getName());
pref.setChecked(rule.isEnabled());
pref.updatePreference(rule);
} else {
reloadAllRules(sortedRules);
break;

View File

@@ -250,15 +250,17 @@ public class ZenModeBackend {
}
}
protected int getAlarmsTotalSilenceCallsMessagesSummary(int category) {
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
return R.string.zen_mode_from_none_messages;
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){
return R.string.zen_mode_from_none_calls;
}
return 0;
}
protected int getContactsSummary(int category) {
int contactType = -1;
// SOURCE_NONE can be used when in total silence or alarms only
// (policy is based on user's preferences but the UI displayed is based on zenMode)
if (category == SOURCE_NONE) {
return R.string.zen_mode_from_none;
}
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
if (isPriorityCategoryEnabled(category)) {
contactType = getPriorityMessageSenders();
@@ -273,12 +275,16 @@ public class ZenModeBackend {
case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
return R.string.zen_mode_from_anyone;
case NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS:
return R.string.zen_mode_from_contacts;
return R.string.zen_mode_from_contacts;
case NotificationManager.Policy.PRIORITY_SENDERS_STARRED:
return R.string.zen_mode_from_starred;
return R.string.zen_mode_from_starred;
case SOURCE_NONE:
default:
return R.string.zen_mode_from_none;
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
return R.string.zen_mode_from_none_messages;
} else {
return R.string.zen_mode_from_none_calls;
}
}
}

View File

@@ -18,11 +18,11 @@ package com.android.settings.notification;
import android.content.Context;
import androidx.preference.Preference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
import androidx.preference.Preference;
public class ZenModeMessagesPreferenceController extends
AbstractZenModePreferenceController implements PreferenceControllerMixin {
@@ -48,6 +48,7 @@ public class ZenModeMessagesPreferenceController extends
@Override
public void updateState(Preference preference) {
super.updateState(preference);
// TODO: (b/111475013 - beverlyt) set messages summary
preference.setSummary(mSummaryBuilder.getMessagesSettingSummary(getPolicy()));
}
}

View File

@@ -21,14 +21,14 @@ import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModePriorityCallsPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
@@ -80,7 +80,8 @@ public class ZenModePriorityCallsPreferenceController extends AbstractZenModePre
case Settings.Global.ZEN_MODE_ALARMS:
mPreference.setEnabled(false);
mPreference.setValue(ZenModeBackend.ZEN_MODE_FROM_NONE);
mPreference.setSummary(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE));
mPreference.setSummary(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS));
break;
default:
preference.setEnabled(true);

View File

@@ -21,14 +21,14 @@ import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class ZenModePriorityMessagesPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
@@ -80,7 +80,8 @@ public class ZenModePriorityMessagesPreferenceController extends AbstractZenMode
case Settings.Global.ZEN_MODE_ALARMS:
mPreference.setEnabled(false);
mPreference.setValue(ZenModeBackend.ZEN_MODE_FROM_NONE);
mPreference.setSummary(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE));
mPreference.setSummary(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES));
break;
default:
preference.setEnabled(true);

View File

@@ -145,7 +145,7 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|| PRIORITY_CATEGORY_REPEAT_CALLERS == category, false);
int numCategories = enabledCategories.size();
if (numCategories == 0) {
return mContext.getString(R.string.zen_mode_no_exceptions);
return mContext.getString(R.string.zen_mode_from_none_calls);
} else if (numCategories == 1) {
return mContext.getString(R.string.zen_mode_calls_summary_one,
enabledCategories.get(0));
@@ -156,34 +156,14 @@ public class ZenModeSettings extends ZenModeSettingsBase {
}
}
String getMsgEventReminderSettingSummary(Policy policy) {
String getMessagesSettingSummary(Policy policy) {
List<String> enabledCategories = getEnabledCategories(policy,
category -> PRIORITY_CATEGORY_EVENTS == category
|| PRIORITY_CATEGORY_REMINDERS == category
|| PRIORITY_CATEGORY_MESSAGES == category, true);
category -> PRIORITY_CATEGORY_MESSAGES == category, false);
int numCategories = enabledCategories.size();
if (numCategories == 0) {
return mContext.getString(R.string.zen_mode_no_exceptions);
} else if (numCategories == 1) {
return enabledCategories.get(0);
} else if (numCategories == 2) {
return mContext.getString(R.string.join_two_items, enabledCategories.get(0),
enabledCategories.get(1));
} else if (numCategories == 3){
final List<String> summaries = new ArrayList<>();
summaries.add(enabledCategories.get(0));
summaries.add(enabledCategories.get(1));
summaries.add(enabledCategories.get(2));
return ListFormatter.getInstance().format(summaries);
return mContext.getString(R.string.zen_mode_from_none_messages);
} else {
final List<String> summaries = new ArrayList<>();
summaries.add(enabledCategories.get(0));
summaries.add(enabledCategories.get(1));
summaries.add(enabledCategories.get(2));
summaries.add(mContext.getString(R.string.zen_mode_other_options));
return ListFormatter.getInstance().format(summaries);
return enabledCategories.get(0);
}
}
@@ -292,17 +272,11 @@ public class ZenModeSettings extends ZenModeSettingsBase {
}
} else if (category == Policy.PRIORITY_CATEGORY_MESSAGES) {
if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_ANY) {
if (isFirst) {
return mContext.getString(R.string.zen_mode_all_messages);
} else {
return mContext.getString(R.string.zen_mode_all_messages_list);
}
return mContext.getString(R.string.zen_mode_from_anyone);
} else if (policy.priorityMessageSenders == Policy.PRIORITY_SENDERS_CONTACTS){
return mContext.getString(R.string.zen_mode_from_contacts);
} else {
if (isFirst) {
return mContext.getString(R.string.zen_mode_selected_messages);
} else {
return mContext.getString(R.string.zen_mode_selected_messages_list);
}
return mContext.getString(R.string.zen_mode_from_starred);
}
} else if (category == Policy.PRIORITY_CATEGORY_EVENTS) {
if (isFirst) {

View File

@@ -31,6 +31,7 @@ import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
@@ -122,17 +123,17 @@ public class ZenRulePreference extends TwoTargetPreference {
return mChecked;
}
public void setChecked(boolean checked) {
mChecked = checked;
if (mCheckBox != null) {
mCheckBox.setChecked(checked);
}
}
public void setName(String name) {
if (!Objects.equals(mName, name)) {
mName = name;
public void updatePreference(AutomaticZenRule rule) {
if (!mRule.getName().equals(rule.getName())) {
mName = rule.getName();
setTitle(mName);
mRule.setName(mName.toString());
}
if (mRule.isEnabled() != rule.isEnabled()) {
mRule.setEnabled(rule.isEnabled());
setChecked(mRule.isEnabled());
setSummary(computeRuleSummary(mRule));
}
}
@@ -141,6 +142,13 @@ public class ZenRulePreference extends TwoTargetPreference {
mOnCheckBoxClickListener.onClick(null);
}
private void setChecked(boolean checked) {
mChecked = checked;
if (mCheckBox != null) {
mCheckBox.setChecked(checked);
}
}
private View.OnClickListener mOnCheckBoxClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -159,7 +167,7 @@ public class ZenRulePreference extends TwoTargetPreference {
try {
ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
setSummary(computeRuleSummary(rule, mIsSystemRule, info.loadLabel(mPm)));
setSummary(computeRuleSummary(rule));
} catch (PackageManager.NameNotFoundException e) {
appExists = false;
return;
@@ -179,8 +187,7 @@ public class ZenRulePreference extends TwoTargetPreference {
setKey(mId);
}
private String computeRuleSummary(AutomaticZenRule rule, boolean isSystemRule,
CharSequence providerLabel) {
private String computeRuleSummary(AutomaticZenRule rule) {
return (rule == null || !rule.isEnabled())
? mContext.getResources().getString(R.string.switch_off_text)
: mContext.getResources().getString(R.string.switch_on_text);

View File

@@ -22,13 +22,16 @@ import android.util.ArrayMap;
import androidx.annotation.VisibleForTesting;
import com.android.settings.flashlight.FlashlightSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.location.LocationSlice;
import com.android.settings.wifi.WifiSlice;
import java.util.Map;
@@ -106,6 +109,9 @@ public class CustomSliceManager {
mUriMap.put(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI, ConnectedDeviceSlice.class);
mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
mUriMap.put(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
mUriMap.put(CustomSliceRegistry.LOCATION_SLICE_URI, LocationSlice.class);
mUriMap.put(CustomSliceRegistry.LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class);
mUriMap.put(CustomSliceRegistry.WIFI_SLICE_URI, WifiSlice.class);

View File

@@ -41,9 +41,6 @@ import androidx.slice.SliceProvider;
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.flashlight.FlashlightSliceBuilder;
import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.SliceBroadcastRelay;
@@ -182,12 +179,6 @@ public class SettingsSliceProvider extends SliceProvider {
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
registerIntentToUri(BluetoothSliceBuilder.INTENT_FILTER, sliceUri);
return;
} else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
registerIntentToUri(FlashlightSliceBuilder.INTENT_FILTER, sliceUri);
mRegisteredUris.add(sliceUri);
return;
} else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
return;
}
// Start warming the slice, we expect someone will want it soon.
@@ -240,8 +231,6 @@ public class SettingsSliceProvider extends SliceProvider {
return ZenModeSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
return BluetoothSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
return LocationSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.ENHANCED_4G_SLICE_URI.equals(sliceUri)) {
return FeatureFactory.getFactory(getContext())
.getSlicesFeatureProvider()
@@ -252,10 +241,6 @@ public class SettingsSliceProvider extends SliceProvider {
.getSlicesFeatureProvider()
.getNewWifiCallingSliceHelper(getContext())
.createWifiCallingPreferenceSlice(sliceUri);
} else if (CustomSliceRegistry.FLASHLIGHT_SLICE_URI.equals(sliceUri)) {
return FlashlightSliceBuilder.getSlice(getContext());
} else if (CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI.equals(sliceUri)) {
return EmergencyInfoSlice.getSlice(getContext());
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);

View File

@@ -17,7 +17,6 @@
package com.android.settings.slices;
import static com.android.settings.bluetooth.BluetoothSliceBuilder.ACTION_BLUETOOTH_SLICE_CHANGED;
import static com.android.settings.flashlight.FlashlightSliceBuilder.ACTION_FLASHLIGHT_SLICE_CHANGED;
import static com.android.settings.network.telephony.Enhanced4gLteSliceHelper.ACTION_ENHANCED_4G_LTE_CHANGED;
import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED;
import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY;
@@ -46,7 +45,6 @@ import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.flashlight.FlashlightSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
@@ -108,9 +106,6 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
.getNewWifiCallingSliceHelper(context)
.handleWifiCallingPreferenceChanged(intent);
break;
case ACTION_FLASHLIGHT_SLICE_CHANGED:
FlashlightSliceBuilder.handleUriChange(context, intent);
break;
case ACTION_COPY:
handleCopyAction(context, key, isPlatformSlice);
break;

View File

@@ -24,7 +24,6 @@ import android.util.Log;
import androidx.annotation.Keep;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
@@ -66,8 +65,6 @@ public class SliceDeepLinkSpringBoard extends Activity {
launchIntent = ZenModeSliceBuilder.getIntent(this /* context */);
} else if (CustomSliceRegistry.BLUETOOTH_URI.equals(sliceUri)) {
launchIntent = BluetoothSliceBuilder.getIntent(this /* context */);
} else if (CustomSliceRegistry.LOCATION_SLICE_URI.equals(sliceUri)) {
launchIntent = LocationSliceBuilder.getIntent(this /* context */);
} else {
final SlicesDatabaseAccessor slicesDatabaseAccessor =
new SlicesDatabaseAccessor(this /* context */);

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2018 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.widget;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.VisibleForTesting;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.appbar.AppBarLayout;
/**
* This scrolling view behavior will set the background of the {@link AppBarLayout} as
* transparent and without the elevation. Also make header overlapped the scrolling child view.
*/
public class FloatingAppBarScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
private boolean initialized;
public FloatingAppBarScrollingViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
boolean changed = super.onDependentViewChanged(parent, child, dependency);
if (!initialized && dependency instanceof AppBarLayout) {
initialized = true;
AppBarLayout appBarLayout = (AppBarLayout) dependency;
setAppBarLayoutTransparent(appBarLayout);
}
return changed;
}
@VisibleForTesting
void setAppBarLayoutTransparent(AppBarLayout appBarLayout) {
appBarLayout.setBackgroundColor(Color.TRANSPARENT);
appBarLayout.setTargetElevation(0);
}
@Override
protected boolean shouldHeaderOverlapScrollingChild() {
return true;
}
}

View File

@@ -22,10 +22,12 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.LayoutRes;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -34,16 +36,23 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import com.android.settingslib.widget.CandidateInfo;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.xmlpull.v1.XmlPullParserException;
public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements
RadioButtonPreference.OnClickListener {
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
@VisibleForTesting
static final String EXTRA_FOR_WORK = "for_work";
private static final String TAG = "RadioButtonPckrFrgmt";
@VisibleForTesting
boolean mAppendStaticPreferences = false;
private final Map<String, CandidateInfo> mCandidates = new ArrayMap<>();
@@ -69,6 +78,19 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
try {
// Check if the xml specifies if static preferences should go on the top or bottom
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(getContext(),
getPreferenceScreenResId(),
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN |
MetadataFlag.FLAG_NEED_PREF_APPEND);
mAppendStaticPreferences = metadata.get(0)
.getBoolean(PreferenceXmlParserUtils.METADATA_APPEND);
} catch (IOException e) {
Log.e(TAG, "Error trying to open xml file", e);
} catch (XmlPullParserException e) {
Log.e(TAG, "Error parsing xml", e);
}
updateCandidates();
}
@@ -142,7 +164,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
final String systemDefaultKey = getSystemDefaultKey();
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
addStaticPreferences(screen);
if (!mAppendStaticPreferences) {
addStaticPreferences(screen);
}
final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId();
if (shouldShowItemNone()) {
@@ -168,6 +192,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr
}
}
mayCheckOnlyRadioButton();
if (mAppendStaticPreferences) {
addStaticPreferences(screen);
}
}
@VisibleForTesting

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/battery_saver_schedule_settings_title"
settings:staticPreferenceLocation="append">
</PreferenceScreen >

View File

@@ -28,11 +28,12 @@ import static com.android.settings.applications.manageapplications.ManageApplica
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -48,9 +49,11 @@ import android.os.Looper;
import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SearchView;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
@@ -158,6 +161,35 @@ public class ManageApplicationsTest {
verify(loadingContainer, never()).setVisibility(View.VISIBLE);
}
@Test
public void onCreateOptionsMenu_shouldSetSearchQueryListener() {
final SearchView searchView = mock(SearchView.class);
final MenuItem searchMenu = mock(MenuItem.class);
final MenuItem helpMenu = mock(MenuItem.class);
when(searchMenu.getActionView()).thenReturn(searchView);
when(mMenu.findItem(R.id.search_app_list_menu)).thenReturn(searchMenu);
when(mMenu.add(anyInt() /* groupId */, anyInt() /* itemId */, anyInt() /* order */,
anyInt() /* titleRes */)).thenReturn(helpMenu);
doReturn("Test").when(mFragment).getText(anyInt() /* resId */);
doNothing().when(mFragment).updateOptionsMenu();
mFragment.onCreateOptionsMenu(mMenu, mock(MenuInflater.class));
verify(searchView).setOnQueryTextListener(mFragment);
}
@Test
public void onQueryTextChange_shouldFilterSearchInApplicationsAdapter() {
final ManageApplications.ApplicationsAdapter adapter =
mock(ManageApplications.ApplicationsAdapter.class);
final String query = "Test App";
ReflectionHelpers.setField(mFragment, "mApplications", adapter);
mFragment.onQueryTextChange(query);
verify(adapter).filterSearch(query);
}
@Test
public void updateLoading_appLoaded_shouldNotDelayCallToHandleLoadingContainer() {
ReflectionHelpers.setField(mFragment, "mLoadingContainer", mock(View.class));
@@ -249,6 +281,34 @@ public class ManageApplicationsTest {
verify(loadingViewController).showContent(true /* animate */);
}
@Test
public void onRebuildComplete_hasSearchQuery_shouldFilterSearch() {
final String query = "Test";
final RecyclerView recyclerView = mock(RecyclerView.class);
final View emptyView = mock(View.class);
ReflectionHelpers.setField(mFragment, "mRecyclerView", recyclerView);
ReflectionHelpers.setField(mFragment, "mEmptyView", emptyView);
final SearchView searchView = mock(SearchView.class);
ReflectionHelpers.setField(mFragment, "mSearchView", searchView);
when(searchView.isVisibleToUser()).thenReturn(true);
when(searchView.getQuery()).thenReturn(query);
final View listContainer = mock(View.class);
when(listContainer.getVisibility()).thenReturn(View.VISIBLE);
ReflectionHelpers.setField(mFragment, "mListContainer", listContainer);
ReflectionHelpers.setField(
mFragment, "mFilterAdapter", mock(ManageApplications.FilterSpinnerAdapter.class));
final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>();
appList.add(mock(ApplicationsState.AppEntry.class));
final ManageApplications.ApplicationsAdapter adapter =
spy(new ManageApplications.ApplicationsAdapter(mState, mFragment,
AppFilterRegistry.getInstance().get(FILTER_APPS_ALL),
null /* savedInstanceState */));
adapter.onRebuildComplete(appList);
verify(adapter).filterSearch(query);
}
@Test
public void notifyItemChange_recyclerViewIdle_shouldNotify() {
final RecyclerView recyclerView = mock(RecyclerView.class);
@@ -343,6 +403,48 @@ public class ManageApplicationsTest {
verify(holder, never()).updateSwitch(any(), anyBoolean(), anyBoolean());
}
@Test
public void applicationsAdapter_filterSearch_emptyQuery_shouldShowFullList() {
final ManageApplications.ApplicationsAdapter adapter =
new ManageApplications.ApplicationsAdapter(
mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
adapter.filterSearch("");
assertThat(adapter.getItemCount()).isEqualTo(5);
}
@Test
public void applicationsAdapter_filterSearch_noMatch_shouldShowEmptyList() {
final ManageApplications.ApplicationsAdapter adapter =
new ManageApplications.ApplicationsAdapter(
mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
adapter.filterSearch("orange");
assertThat(adapter.getItemCount()).isEqualTo(0);
}
@Test
public void applicationsAdapter_filterSearch_shouldShowMatchedItemsOnly() {
final ManageApplications.ApplicationsAdapter adapter =
new ManageApplications.ApplicationsAdapter(
mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
adapter.filterSearch("an");
assertThat(adapter.getItemCount()).isEqualTo(3);
assertThat(adapter.getAppEntry(0).label).isEqualTo("Banana");
assertThat(adapter.getAppEntry(1).label).isEqualTo("Cantaloupe");
assertThat(adapter.getAppEntry(2).label).isEqualTo("Mango");
}
@Test
public void sortOrderSavedOnRebuild() {
when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[]{});
@@ -375,4 +477,14 @@ public class ManageApplicationsTest {
return new RoboMenuItem(id);
});
}
private ArrayList<ApplicationsState.AppEntry> getTestAppList(String[] appNames) {
final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>();
for (String name : appNames) {
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.label = name;
appList.add(appEntry);
}
return appList;
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.core;
import static com.android.settings.core.PreferenceXmlParserUtils
.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE;
@@ -315,6 +316,32 @@ public class PreferenceXmlParserUtilsTest {
}
}
@Test
@Config(qualifiers = "mcc999")
public void extractMetadata_requestAppendProperty_shouldDefaultToFalse()
throws Exception {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.display_settings,
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
for (Bundle bundle : metadata) {
assertThat(bundle.getBoolean(METADATA_APPEND)).isFalse();
}
}
@Test
@Config(qualifiers = "mcc999")
public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue()
throws Exception {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.battery_saver_schedule_settings,
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
for (Bundle bundle : metadata) {
assertThat(bundle.getBoolean(METADATA_APPEND)).isTrue();
}
}
/**
* @param resId the ID for the XML preference
* @return an XML resource parser that points to the start tag

View File

@@ -37,11 +37,14 @@ import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RunWith(SettingsRobolectricTestRunner.class)
public class ChartDataUsagePreferenceTest {
// Test cycle start date, 20 Mar 2018 22:00: GMT
private static final long TIMESTAMP_START = 1521583200000L;
// Test bucket end date, 22 Mar 2018 00:00:00
private static final long TIMESTAMP_END = 1521676800000L;
private List<NetworkCycleData> mNetworkCycleData;
@@ -55,8 +58,6 @@ public class ChartDataUsagePreferenceTest {
mContext = RuntimeEnvironment.application;
mPreference = new ChartDataUsagePreference(mContext, null);
createTestNetworkData();
mPreference.setNetworkCycleData(mNetworkCycleChartData);
}
@Test
@@ -64,11 +65,13 @@ public class ChartDataUsagePreferenceTest {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor<SparseIntArray> pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
createTestNetworkData();
mPreference.setNetworkCycleData(mNetworkCycleChartData);
mPreference.calcPoints(usageView, mNetworkCycleData.subList(0, 5));
verify(usageView).addPath(pointsCaptor.capture());
SparseIntArray points = pointsCaptor.getValue();
final SparseIntArray points = pointsCaptor.getValue();
// the point should be normal usage data
assertThat(points.valueAt(1)).isNotEqualTo(-1);
}
@@ -78,16 +81,73 @@ public class ChartDataUsagePreferenceTest {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor<SparseIntArray> pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
createTestNetworkData();
mPreference.setNetworkCycleData(mNetworkCycleChartData);
mPreference.calcPoints(usageView, mNetworkCycleData.subList(2, 7));
verify(usageView).addPath(pointsCaptor.capture());
SparseIntArray points = pointsCaptor.getValue();
final SparseIntArray points = pointsCaptor.getValue();
// indicator that no data is available
assertThat(points.keyAt(1)).isEqualTo(points.keyAt(2) - 1);
assertThat(points.valueAt(1)).isEqualTo(-1);
}
@Test
public void calcPoints_shouldNotDrawPointForFutureDate() {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor<SparseIntArray> pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
final long tonight = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(12);
mNetworkCycleData = new ArrayList<>();
// add test usage data for last 5 days
mNetworkCycleData.add(createNetworkCycleData(
tonight - TimeUnit.DAYS.toMillis(5), tonight - TimeUnit.DAYS.toMillis(4), 743823454L));
mNetworkCycleData.add(createNetworkCycleData(
tonight - TimeUnit.DAYS.toMillis(4), tonight - TimeUnit.DAYS.toMillis(3), 64396L));
mNetworkCycleData.add(createNetworkCycleData(
tonight - TimeUnit.DAYS.toMillis(3), tonight - TimeUnit.DAYS.toMillis(2), 2832L));
mNetworkCycleData.add(createNetworkCycleData(
tonight - TimeUnit.DAYS.toMillis(2), tonight - TimeUnit.DAYS.toMillis(1), 83849690L));
mNetworkCycleData.add(createNetworkCycleData(
tonight - TimeUnit.DAYS.toMillis(1), tonight, 1883657L));
// add dummy usage data for next 5 days
mNetworkCycleData.add(createNetworkCycleData(
tonight, tonight + TimeUnit.DAYS.toMillis(1), 0L));
mNetworkCycleData.add(createNetworkCycleData(
tonight + TimeUnit.DAYS.toMillis(1), tonight + TimeUnit.DAYS.toMillis(2), 0L));
mNetworkCycleData.add(createNetworkCycleData(
tonight + TimeUnit.DAYS.toMillis(2), tonight + TimeUnit.DAYS.toMillis(3), 0L));
mNetworkCycleData.add(createNetworkCycleData(
tonight + TimeUnit.DAYS.toMillis(3), tonight + TimeUnit.DAYS.toMillis(4), 0L));
mNetworkCycleData.add(createNetworkCycleData(
tonight + TimeUnit.DAYS.toMillis(4), tonight + TimeUnit.DAYS.toMillis(5), 0L));
mNetworkCycleData.add(createNetworkCycleData(
tonight + TimeUnit.DAYS.toMillis(5), tonight + TimeUnit.DAYS.toMillis(6), 0L));
final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
builder.setUsageBuckets(mNetworkCycleData)
.setStartTime(tonight - TimeUnit.DAYS.toMillis(5))
.setEndTime(tonight + TimeUnit.DAYS.toMillis(6));
mNetworkCycleChartData = builder.build();
mPreference.setNetworkCycleData(mNetworkCycleChartData);
mPreference.calcPoints(usageView, mNetworkCycleData);
verify(usageView).addPath(pointsCaptor.capture());
final SparseIntArray points = pointsCaptor.getValue();
// should only have 7 points: 1 dummy point indicating the start of data, starting point 0,
// and 5 actual data point for each day
assertThat(points.size()).isEqualTo(7);
assertThat(points.keyAt(0)).isEqualTo(-1);
assertThat(points.keyAt(1)).isEqualTo(0);
assertThat(points.keyAt(2)).isEqualTo(TimeUnit.DAYS.toMinutes(1));
assertThat(points.keyAt(3)).isEqualTo(TimeUnit.DAYS.toMinutes(2));
assertThat(points.keyAt(4)).isEqualTo(TimeUnit.DAYS.toMinutes(3));
assertThat(points.keyAt(5)).isEqualTo(TimeUnit.DAYS.toMinutes(4));
assertThat(points.keyAt(6)).isEqualTo(TimeUnit.DAYS.toMinutes(5));
}
private void createTestNetworkData() {
mNetworkCycleData = new ArrayList<>();
// create 10 arbitrary network data

View File

@@ -1,138 +0,0 @@
/*
* Copyright (C) 2018 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.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_ANGLE_ENABLED_APP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class AngleEnabledAppPreferenceControllerTest {
@Mock
private Preference mPreference;
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
@Mock
private PackageManager mPackageManager;
private Context mContext;
private AngleEnabledAppPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = spy(new AngleEnabledAppPreferenceController(mContext, mFragment));
ReflectionHelpers
.setField(mController, "mPackageManager" /* field name */, mPackageManager);
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void handlePreferenceTreeClick_preferenceClicked_launchActivity() {
final Intent activityStartIntent = new Intent(mContext, AppPicker.class);
final String preferenceKey = mController.getPreferenceKey();
doReturn(activityStartIntent).when(mController).getActivityStartIntent();
when(mPreference.getKey()).thenReturn(preferenceKey);
mController.handlePreferenceTreeClick(mPreference);
verify(mFragment).startActivityForResult(activityStartIntent,
REQUEST_CODE_ANGLE_ENABLED_APP);
}
@Test
public void updateState_foobarAppSelected_shouldUpdateSummaryWithAngleEnabledAppLabel() {
final String angleEnabledApp = "foobar";
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver, Settings.Global.ANGLE_ENABLED_APP,
angleEnabledApp);
mController.updateState(mPreference);
verify(mPreference).setSummary(
mContext.getString(R.string.angle_enabled_app_set, angleEnabledApp));
}
@Test
public void updateState_noAppSelected_shouldUpdateSummaryWithNoAppSelected() {
final String angleEnabledApp = null;
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver, Settings.Global.ANGLE_ENABLED_APP,
angleEnabledApp);
mController.updateState(mPreference);
verify(mPreference).setSummary(
mContext.getString(R.string.angle_enabled_app_not_set));
}
@Test
public void onActivityResult_foobarAppSelected_shouldUpdateSummaryWithAngleEnabledLabel() {
Intent activityResultIntent = new Intent(mContext, AppPicker.class);
final String appLabel = "foobar";
activityResultIntent.setAction(appLabel);
final boolean result = mController
.onActivityResult(REQUEST_CODE_ANGLE_ENABLED_APP, Activity.RESULT_OK,
activityResultIntent);
assertThat(result).isTrue();
verify(mPreference).setSummary(
mContext.getString(R.string.angle_enabled_app_set, appLabel));
}
@Test
public void onActivityResult_badRequestCode_shouldReturnFalse() {
assertThat(mController.onActivityResult(
-1 /* requestCode */, -1 /* resultCode */, null /* intent */)).isFalse();
}
@Test
public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isEnabled()).isFalse();
verify(mPreference).setSummary(
mContext.getString(R.string.angle_enabled_app_not_set));
}
}

View File

@@ -28,10 +28,15 @@ import android.content.Context;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch;
@@ -47,12 +52,14 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import org.robolectric.util.ReflectionHelpers;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = ShadowUserManager.class)
@Config(shadows = {ShadowUserManager.class, ShadowAlertDialogCompat.class,
SettingsShadowResourcesImpl.class})
public class DevelopmentSettingsDashboardFragmentTest {
private ToggleSwitch mSwitch;
@@ -178,6 +185,29 @@ public class DevelopmentSettingsDashboardFragmentTest {
assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse();
}
@Test
@Config(shadows = ShadowDisableDevSettingsDialogFragment.class)
public void onSwitchChanged_turnOff_andOffloadIsNotDefaultValue_shouldShowWarningDialog() {
final BluetoothA2dpHwOffloadPreferenceController controller =
mock(BluetoothA2dpHwOffloadPreferenceController.class);
when(mDashboard.getContext()).thenReturn(mContext);
when(mDashboard.getDevelopmentOptionsController(
BluetoothA2dpHwOffloadPreferenceController.class)).thenReturn(controller);
when(controller.isDefaultValue()).thenReturn(false);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowDialog.getTitle()).isEqualTo(
mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_title));
assertThat(shadowDialog.getMessage()).isEqualTo(
mContext.getString(R.string.bluetooth_disable_a2dp_hw_offload_dialog_message));
}
@Test
public void onOemUnlockDialogConfirmed_shouldCallControllerOemConfirmed() {
final OemUnlockPreferenceController controller = mock(OemUnlockPreferenceController.class);
@@ -264,6 +294,18 @@ public class DevelopmentSettingsDashboardFragmentTest {
}
}
@Implements(DisableDevSettingsDialogFragment.class)
public static class ShadowDisableDevSettingsDialogFragment {
@Implementation
public static void show(DevelopmentSettingsDashboardFragment host) {
DisableDevSettingsDialogFragment mFragment =
spy(DisableDevSettingsDialogFragment.newInstance());
FragmentController.setupFragment(mFragment, FragmentActivity.class,
0 /* containerViewId */, null /* bundle */);
}
}
@Implements(PictureColorModePreferenceController.class)
public static class ShadowPictureColorModePreferenceController {
@Implementation

View File

@@ -209,6 +209,7 @@ public class ColorModePreferenceFragmentTest {
@Test
public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() {
when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
doNothing().when(mFragment).addPreferencesFromResource(anyInt());
doNothing().when(mFragment).updateCandidates();

View File

@@ -42,7 +42,7 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class FlashlightSliceBuilderTest {
public class FlashlightSliceTest {
private Context mContext;
@@ -58,7 +58,7 @@ public class FlashlightSliceBuilderTest {
public void getFlashlightSlice_correctData() {
Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
final Slice slice = FlashlightSliceBuilder.getSlice(mContext);
final Slice slice = new FlashlightSlice(mContext).getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
final List<SliceAction> toggles = metadata.getToggles();

View File

@@ -16,13 +16,20 @@
package com.android.settings.homepage.contextualcards;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.UserHandle;
import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -31,6 +38,9 @@ import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class ContextualCardFeatureProviderImplTest {
@@ -48,7 +58,7 @@ public class ContextualCardFeatureProviderImplTest {
final Intent intent = new Intent();
mImpl.sendBroadcast(mContext, intent);
verify(mContext, never()).sendBroadcast(intent);
verify(mContext, never()).sendBroadcastAsUser(intent, UserHandle.ALL);
}
@Test
@@ -57,6 +67,37 @@ public class ContextualCardFeatureProviderImplTest {
final Intent intent = new Intent();
mImpl.sendBroadcast(mContext, intent);
verify(mContext).sendBroadcast(intent);
verify(mContext).sendBroadcastAsUser(intent, UserHandle.ALL);
}
@Test
@Config(qualifiers = "mcc999")
public void logContextualCardDisplay_hasAction_sendBroadcast() {
mImpl.logContextualCardDisplay(mContext, new ArrayList<>(), new ArrayList<>());
verify(mContext).sendBroadcastAsUser(any(Intent.class), any());
}
@Test
public void serialize_hasSizeTwo_returnSizeTwo() {
final List<ContextualCard> cards = new ArrayList<>();
cards.add(new ContextualCard.Builder()
.setName("name1")
.setSliceUri(Uri.parse("uri1"))
.build());
cards.add(new ContextualCard.Builder()
.setName("name2")
.setSliceUri(Uri.parse("uri2"))
.build());
final byte[] data = mImpl.serialize(cards);
try {
assertThat(ContextualCardList
.parseFrom(data).getCardCount()).isEqualTo(cards.size());
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.homepage.contextualcards.slices;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -24,10 +26,12 @@ import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
import androidx.slice.SliceMetadata;
import androidx.slice.SliceProvider;
import androidx.slice.widget.SliceLiveData;
@@ -50,8 +54,8 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class ConnectedDeviceSliceTest {
private static final String BLUETOOTH_SUMMARY = "BluetoothSummary";
private static final String BLUETOOTH_TITLE = "BluetoothTitle";
private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
@@ -90,7 +94,7 @@ public class ConnectedDeviceSliceTest {
}
@Test
public void getSlice_hasConnectedDevices_shouldHaveCorrectTitle() {
public void getSlice_hasConnectedDevices_shouldHaveConnectedDeviceTitle() {
mockBluetoothDeviceList();
doReturn(mBluetoothConnectedDeviceList).when(
mConnectedDeviceSlice).getBluetoothConnectedDevices();
@@ -103,7 +107,7 @@ public class ConnectedDeviceSliceTest {
}
@Test
public void getSlice_hasConnectedDevices_shouldHaveCorrectContent() {
public void getSlice_hasConnectedDevices_shouldMatchBluetoothMockTitle() {
mockBluetoothDeviceList();
doReturn(mBluetoothConnectedDeviceList).when(
mConnectedDeviceSlice).getBluetoothConnectedDevices();
@@ -111,11 +115,24 @@ public class ConnectedDeviceSliceTest {
final Slice slice = mConnectedDeviceSlice.getSlice();
final List<SliceItem> sliceItems = slice.getItems();
SliceTester.assertTitle(sliceItems, BLUETOOTH_TITLE);
SliceTester.assertTitle(sliceItems, BLUETOOTH_MOCK_TITLE);
}
@Test
public void getSlice_noConnectedDevices_shouldHaveCorrectTitle() {
public void getSlice_hasConnectedDevices_shouldHavePairNewDevice() {
mockBluetoothDeviceList();
doReturn(mBluetoothConnectedDeviceList).when(
mConnectedDeviceSlice).getBluetoothConnectedDevices();
final Slice slice = mConnectedDeviceSlice.getSlice();
final List<SliceItem> sliceItems = slice.getItems();
SliceTester.assertTitle(sliceItems,
mContext.getString(R.string.bluetooth_pairing_pref_title));
}
@Test
public void getSlice_noConnectedDevices_shouldHaveNoConnectedDeviceTitle() {
doReturn(mBluetoothConnectedDeviceList).when(
mConnectedDeviceSlice).getBluetoothConnectedDevices();
@@ -125,9 +142,26 @@ public class ConnectedDeviceSliceTest {
SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_connected_devices));
}
@Test
public void getSlice_noConnectedDevices_shouldNotHavePairNewDevice() {
doReturn(mBluetoothConnectedDeviceList).when(
mConnectedDeviceSlice).getBluetoothConnectedDevices();
final Slice slice = mConnectedDeviceSlice.getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
assertThat(hasTitle(metadata,
mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
}
private void mockBluetoothDeviceList() {
doReturn(BLUETOOTH_TITLE).when(mCachedBluetoothDevice).getName();
doReturn(BLUETOOTH_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
mBluetoothConnectedDeviceList.add(mCachedBluetoothDevice);
}
private boolean hasTitle(SliceMetadata metadata, String title) {
final CharSequence sliceTitle = metadata.getTitle();
return TextUtils.equals(sliceTitle, title);
}
}

View File

@@ -52,7 +52,7 @@ import org.robolectric.android.controller.ActivityController;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceContextualCardRendererTest {
private static final String TEST_SLICE_URI = "content://test/test";
private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
@Mock
private LiveData<Slice> mSliceLiveData;
@@ -91,7 +91,7 @@ public class SliceContextualCardRendererTest {
@Test
public void bindView_invalidScheme_sliceShouldBeNull() {
final String sliceUri = "contet://com.android.settings.slices/action/flashlight";
final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
@@ -191,6 +191,23 @@ public class SliceContextualCardRendererTest {
assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
}
@Test
public void viewClick_removeCard_sliceLiveDataShouldRemoveObservers() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
final Button btnRemove = viewHolder.itemView.findViewById(R.id.remove);
final ContextualCard contextualCard = buildContextualCard(TEST_SLICE_URI);
mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
mRenderer.bindView(viewHolder, contextualCard);
doReturn(mController).when(mControllerRendererPool).getController(mActivity,
ContextualCard.CardType.SLICE);
card.performLongClick();
btnRemove.performClick();
assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isFalse();
}
@Test
public void onStop_cardIsFlipped_shouldFlipBack() {
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
@@ -213,11 +230,11 @@ public class SliceContextualCardRendererTest {
return mRenderer.createViewHolder(view);
}
private ContextualCard buildContextualCard(String sliceUri) {
private ContextualCard buildContextualCard(Uri sliceUri) {
return new ContextualCard.Builder()
.setName("test_name")
.setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(Uri.parse(sliceUri))
.setSliceUri(sliceUri)
.build();
}
}

View File

@@ -18,7 +18,11 @@ package com.android.settings.location;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
@@ -28,22 +32,63 @@ import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
public class LocationScanningPreferenceControllerTest {
private Context mContext;
private LocationScanningPreferenceController mController;
private LocationScanningPreferenceController mController;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new LocationScanningPreferenceController(mContext);
}
@Before
public void setUp() {
mController = new LocationScanningPreferenceController(RuntimeEnvironment.application);
}
@Test
public void testLocationScanning_byDefault_shouldBeShown() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void testLocationScanning_byDefault_shouldBeShown() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void testLocationScanning_WifiOnBleOn() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_on_ble_on));
}
@Test
@Config(qualifiers = "mcc999")
public void testLocationScanning_ifDisabled_shouldNotBeShown() {
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void testLocationScanning_WifiOnBleOff() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_on_ble_off));
}
@Test
public void testLocationScanning_WifiOffBleOn() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_off_ble_on));
}
@Test
public void testLocationScanning_WifiOffBleOff() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
assertThat(mController.getSummary()).isEqualTo(
mContext.getString(R.string.scanning_status_text_wifi_off_ble_off));
}
@Test
@Config(qualifiers = "mcc999")
public void testLocationScanning_ifDisabled_shouldNotBeShown() {
assertThat(mController.isAvailable()).isFalse();
}
}

View File

@@ -24,7 +24,7 @@ import org.robolectric.RuntimeEnvironment;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class LocationSliceBuilderTest {
public class LocationSliceTest {
private Context mContext;
@@ -38,7 +38,7 @@ public class LocationSliceBuilderTest {
@Test
public void getLocationSlice_correctSliceContent() {
final Slice LocationSlice = LocationSliceBuilder.getSlice(mContext);
final Slice LocationSlice = new LocationSlice(mContext).getSlice();
final SliceMetadata metadata = SliceMetadata.from(mContext, LocationSlice);
final List<SliceAction> toggles = metadata.getToggles();

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 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.network;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class SubscriptionUtilTest {
@Mock
private SubscriptionManager mManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void getAvailableSubscriptions_nullInfoFromSubscriptionManager_nonNullResult() {
when(mManager.getAvailableSubscriptionInfoList()).thenReturn(null);
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
assertThat(subs).isNotNull();
assertThat(subs).isEmpty();
}
@Test
public void getAvailableSubscriptions_oneSubscription_oneResult() {
final SubscriptionInfo info = mock(SubscriptionInfo.class);
when(info.getMncString()).thenReturn("fake1234");
when(mManager.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info));
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(1);
}
@Test
public void getAvailableSubscriptions_twoSubscriptions_twoResults() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getMncString()).thenReturn("fake1234");
when(info2.getMncString()).thenReturn("fake5678");
when(mManager.getAvailableSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2));
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(2);
}
@Test
public void getAvailableSubscriptions_oneSubWithHiddenNetworks_oneResult() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(1);
when(info1.getMncString()).thenReturn("fake1234");
when(mManager.getAvailableSubscriptionInfoList()).thenReturn(
new ArrayList<>(Arrays.asList(info1, info2, info3)));
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(1);
assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
}
@Test
public void getAvailableSubscriptions_twoSubsWithHiddenNetworks_twoResults() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
final SubscriptionInfo info4 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(1);
when(info1.getMncString()).thenReturn("fake1234");
when(info4.getSubscriptionId()).thenReturn(4);
when(info4.getMncString()).thenReturn("fake5678");
when(mManager.getAvailableSubscriptionInfoList()).thenReturn(new ArrayList<>(
Arrays.asList(info1, info2, info3, info4)));
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(2);
assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
assertThat(subs.get(1).getSubscriptionId()).isEqualTo(4);
}
}

View File

@@ -20,6 +20,7 @@ import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_U
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -104,9 +105,8 @@ public class MobileDataPreferenceControllerTest {
public void isDialogNeeded_enableNonDefaultSimInMultiSimMode_returnTrue() {
doReturn(false).when(mTelephonyManager).isDataEnabled();
doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(SUB_ID);
doReturn(null).when(mSubscriptionManager).getDefaultDataSubscriptionInfo();
doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(anyInt());
doReturn(2).when(mTelephonyManager).getSimCount();
doReturn(1).when(mTelephonyManager).getNumberOfModemsWithSimultaneousDataConnections();
assertThat(mController.isDialogNeeded()).isTrue();
assertThat(mController.mDialogType).isEqualTo(

View File

@@ -144,7 +144,7 @@ public class ZenModeAutomaticRulesPreferenceControllerTest {
mockGetAutomaticZenRules(NUM_RULES, rMap);
FieldSetter.setField(mZenRulePreference, ZenRulePreference.class.getDeclaredField("mId"), testId);
mController.updateState(mockPref);
verify(mZenRulePreference, times(1)).setChecked(false);
verify(mZenRulePreference, times(1)).updatePreference(any());
verify(mController, never()).reloadAllRules(any());
}

View File

@@ -30,6 +30,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -43,9 +46,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModePriorityCallsPreferenceControllerTest {
@@ -86,8 +86,8 @@ public class ZenModePriorityCallsPreferenceControllerTest {
when(mBackend.getPriorityCallSenders())
.thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
when(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE))
.thenCallRealMethod();
when(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)).thenCallRealMethod();
when(mBackend.getContactsSummary(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS))
.thenCallRealMethod();
@@ -110,7 +110,7 @@ public class ZenModePriorityCallsPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
verify(mockPref).setSummary(R.string.zen_mode_from_none);
verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
}
@Test
@@ -121,7 +121,7 @@ public class ZenModePriorityCallsPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
verify(mockPref).setSummary(R.string.zen_mode_from_none);
verify(mockPref).setSummary(R.string.zen_mode_from_none_calls);
}
@Test

View File

@@ -30,6 +30,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -43,9 +46,6 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModePriorityMessagesPreferenceControllerTest {
@@ -86,8 +86,8 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
when(mBackend.getPriorityMessageSenders())
.thenReturn(NotificationManager.Policy.PRIORITY_SENDERS_STARRED);
when(mBackend.getContactsSummary(ZenModeBackend.SOURCE_NONE))
.thenCallRealMethod();
when(mBackend.getAlarmsTotalSilenceCallsMessagesSummary(
NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)).thenCallRealMethod();
when(mBackend.getContactsSummary(NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES))
.thenCallRealMethod();
@@ -110,7 +110,7 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
verify(mockPref).setSummary(R.string.zen_mode_from_none);
verify(mockPref).setSummary(R.string.zen_mode_from_none_messages);
}
@Test
@@ -121,7 +121,7 @@ public class ZenModePriorityMessagesPreferenceControllerTest {
mController.updateState(mockPref);
verify(mockPref).setEnabled(false);
verify(mockPref).setSummary(R.string.zen_mode_from_none);
verify(mockPref).setSummary(R.string.zen_mode_from_none_messages);
}
@Test

View File

@@ -71,20 +71,20 @@ public class ZenModeSettingsTest {
@Test
public void testGetCallsSettingSummary_none() {
Policy policy = new Policy(0, 0, 0, 0);
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("None");
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Don\u2019t allow any calls");
}
@Test
public void testGetCallsSettingSummary_contacts() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | Policy.PRIORITY_CATEGORY_CALLS,
Policy.PRIORITY_SENDERS_CONTACTS, 0, 0);
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From contacts");
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from contacts");
}
@Test
public void testGetCallsSettingSummary_repeatCallers() {
Policy policy = new Policy(Policy.PRIORITY_CATEGORY_REPEAT_CALLERS, 0, 0, 0);
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("From repeat callers");
assertThat(mBuilder.getCallsSettingSummary(policy)).isEqualTo("Allow from repeat callers");
}
@Test
@@ -93,7 +93,7 @@ public class ZenModeSettingsTest {
Policy.PRIORITY_CATEGORY_REPEAT_CALLERS | Policy.PRIORITY_CATEGORY_CALLS,
Policy.PRIORITY_SENDERS_STARRED, 0, 0);
assertThat(mBuilder.getCallsSettingSummary(policy))
.isEqualTo("From starred contacts and repeat callers");
.isEqualTo("Allow from starred contacts and repeat callers");
}
@Test

View File

@@ -236,6 +236,7 @@ public class SliceTester {
assertKeywords(metadata, sliceData);
}
// TODO(b/120592507): Clean up method of SliceTester
public static void assertTitle(List<SliceItem> sliceItems, String title) {
boolean hasTitle = false;
for (SliceItem item : sliceItems) {
@@ -255,6 +256,7 @@ public class SliceTester {
assertThat(hasTitle).isTrue();
}
// TODO(b/120592507): Clean up method of SliceTester
private static void assertKeywords(SliceMetadata metadata, SliceData data) {
final List<String> keywords = metadata.getSliceKeywords();
final Set<String> expectedKeywords = Arrays.stream(data.getKeywords().split(","))

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 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.widget;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.google.android.material.appbar.AppBarLayout;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class FloatingAppBarScrollingViewBehaviorTest {
private FloatingAppBarScrollingViewBehavior mScrollingViewBehavior;
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mScrollingViewBehavior = new FloatingAppBarScrollingViewBehavior(mContext,
Robolectric.buildAttributeSet().build());
}
@Test
public void shouldHeaderOverlapScrollingChild_returnTrue() {
assertThat(mScrollingViewBehavior.shouldHeaderOverlapScrollingChild()).isTrue();
}
@Test
public void setAppBarLayoutTransparent_backgroundDefaultAsWhite_shouldBeTransparent() {
mContext.setTheme(R.style.Theme_Settings_Home);
final AppBarLayout appBarLayout = new AppBarLayout(mContext);
appBarLayout.setBackgroundColor(Color.WHITE);
mScrollingViewBehavior.setAppBarLayoutTransparent(appBarLayout);
assertThat(((ColorDrawable) appBarLayout.getBackground()).getColor()).isEqualTo(
Color.TRANSPARENT);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.widget;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -37,7 +38,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -98,6 +101,26 @@ public class RadioButtonPickerFragmentTest {
assertThat(mFragment.setDefaultKeyCalled).isTrue();
}
@Test
public void staticPreferencesPrepended_addedFirst() {
mFragment.mAppendStaticPreferences = false;
mFragment.updateCandidates();
InOrder inOrder = Mockito.inOrder(mFragment);
inOrder.verify(mFragment).addStaticPreferences(any());
inOrder.verify(mFragment).getRadioButtonPreferenceCustomLayoutResId();
}
@Test
public void staticPreferencesAppended_addedLast() {
mFragment.mAppendStaticPreferences = true;
mFragment.updateCandidates();
InOrder inOrder = Mockito.inOrder(mFragment);
inOrder.verify(mFragment).mayCheckOnlyRadioButton();
inOrder.verify(mFragment).addStaticPreferences(any());
}
@Test
public void shouldHaveNoCustomPreferenceLayout() {
assertThat(mFragment.getRadioButtonPreferenceCustomLayoutResId()).isEqualTo(0);