Merge "Clarify text shown in a11y service warning dialog"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7689b11..7807f0e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -69,6 +69,7 @@
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE" />
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
<uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REBOOT" />
@@ -114,6 +115,14 @@
<uses-library android:name="org.apache.http.legacy" />
<!-- Settings -->
+ <!-- TODO(b/118444000): Remove this. -->
+ <activity android:name="SettingsActivity"
+ android:label="@string/settings_label_launcher"
+ android:launchMode="singleTask">
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
<activity android:name=".homepage.SettingsHomepageActivity"
android:label="@string/settings_label_launcher"
android:theme="@style/Theme.Settings.Home"
@@ -3036,7 +3045,14 @@
</provider>
<activity
- android:name=".wifi.dpp.WifiDppConfiguratorActivity"/>
+ android:name=".wifi.dpp.WifiDppConfiguratorActivity">
+ <intent-filter>
+ <action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER"/>
+ <action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR"/>
+ <action android:name="android.settings.WIFI_DPP_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
<activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
diff --git a/protos/contextual_card_list.proto b/protos/contextual_card_list.proto
index ea82408..3496c8c 100644
--- a/protos/contextual_card_list.proto
+++ b/protos/contextual_card_list.proto
@@ -28,4 +28,6 @@
optional string cardName = 3;
optional Category card_category = 4;
+
+ optional double card_score = 5;
}
diff --git a/res/drawable/ic_find_in_page_24px.xml b/res/drawable/ic_find_in_page_24px.xml
new file mode 100644
index 0000000..18895e4
--- /dev/null
+++ b/res/drawable/ic_find_in_page_24px.xml
@@ -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>
diff --git a/res/drawable/ic_qrcode_24dp.xml b/res/drawable/ic_qrcode_24dp.xml
new file mode 100644
index 0000000..ff7806f
--- /dev/null
+++ b/res/drawable/ic_qrcode_24dp.xml
@@ -0,0 +1,39 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7,4v3H4V4H7M9,2H2v7h7V2L9,2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15,11l-8,0l0,2l8,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,2l-2,0l0,11l2,0l0,-11z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,15l-11,0l0,2l11,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13,17l-2,0l0,5l2,0l0,-5z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17,13l-2,0l0,9l2,0l0,-9z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,19l-3,0l0,3l3,0l0,-3z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M5,11l-3,0l0,2l3,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,11l-5,0l0,2l5,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,4v3h-3V4H20M22,2h-7v7h7V2L22,2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7,17v3H4v-3H7M9,15H2v7h7V15L9,15z"/>
+</vector>
diff --git a/res/drawable/ic_scan_24dp.xml b/res/drawable/ic_scan_24dp.xml
new file mode 100644
index 0000000..bcef8e3
--- /dev/null
+++ b/res/drawable/ic_scan_24dp.xml
@@ -0,0 +1,33 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,2l-7,0l0,2l7,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,2l-7,0l0,2l7,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,11l-20,0l0,2l20,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,2l-2,0l0,7l2,0l0,-7z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4,2l-2,0l0,7l2,0l0,-7z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,20l-7,0l0,2l7,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,20l-7,0l0,2l7,0l0,-2z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M22,15l-2,0l0,7l2,0l0,-7z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4,15l-2,0l0,7l2,0l0,-7z"/>
+</vector>
diff --git a/res/drawable/ic_wifi_privacy_24dp.xml b/res/drawable/ic_wifi_privacy_24dp.xml
new file mode 100644
index 0000000..c23fbc1
--- /dev/null
+++ b/res/drawable/ic_wifi_privacy_24dp.xml
@@ -0,0 +1,32 @@
+<?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:viewportWidth="24"
+ android:viewportHeight="24"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21.25,16.5v-0.66c0,-1.13 -1.03,-2.09 -2.25,-2.09s-2.25,0.96 -2.25,2.09v0.66H16V22h6v-5.5H21.25zM19.75,16.5h-1.5v-0.66c0,-0.29 0.38,-0.59 0.75,-0.59s0.75,0.3 0.75,0.59V16.5z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,17c-3.79,0 -7.17,-2.13 -8.82,-5.5C4.83,8.13 8.21,6 12,6s7.17,2.13 8.82,5.5H23C21.27,7.11 17,4 12,4S2.73,7.11 1,11.5C2.73,15.89 7,19 12,19c0.68,0 1.35,-0.06 2,-0.17v-2.05C13.35,16.91 12.69,17 12,17z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M16.43,12.23c0.04,-0.24 0.07,-0.48 0.07,-0.73C16.5,9.02 14.48,7 12,7s-4.5,2.02 -4.5,4.5S9.52,16 12,16c0.77,0 1.48,-0.21 2.12,-0.55C14.41,14.08 15.27,12.93 16.43,12.23zM12,14.2c-1.49,0 -2.7,-1.21 -2.7,-2.7s1.21,-2.7 2.7,-2.7s2.7,1.21 2.7,2.7S13.49,14.2 12,14.2z"/>
+</vector>
diff --git a/res/layout/homepage_condition_half_tile.xml b/res/layout/homepage_condition_half_tile.xml
index fb83389..eff167a 100644
--- a/res/layout/homepage_condition_half_tile.xml
+++ b/res/layout/homepage_condition_half_tile.xml
@@ -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>
diff --git a/res/layout/settings_action_buttons.xml b/res/layout/settings_action_buttons.xml
deleted file mode 100644
index 56e1a36..0000000
--- a/res/layout/settings_action_buttons.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="8dp"
- android:orientation="horizontal">
-
- <Button
- android:id="@+id/button1"
- style="@style/SettingsActionButton"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"/>
-
- <Button
- android:id="@+id/button2"
- style="@style/SettingsActionButton"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"/>
-
- <Button
- android:id="@+id/button3"
- style="@style/SettingsActionButton"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"/>
-
- <Button
- android:id="@+id/button4"
- style="@style/SettingsActionButton"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"/>
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index 8d81e82..75d449f 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -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>
diff --git a/res/layout/settings_main_dashboard.xml b/res/layout/settings_main_dashboard.xml
new file mode 100644
index 0000000..ee84576
--- /dev/null
+++ b/res/layout/settings_main_dashboard.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<!-- TODO(118444000): Remove this -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <include layout="@layout/search_bar" />
+
+ <FrameLayout
+ android:id="@+id/main_content"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/zen_rule_widget.xml b/res/layout/zen_rule_widget.xml
index d502243..c6214e7 100644
--- a/res/layout/zen_rule_widget.xml
+++ b/res/layout/zen_rule_widget.xml
@@ -20,13 +20,13 @@
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
- android:id="@+id/delete_zen_rule"
+ android:id="@+id/zen_automatic_rule_widget"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="16dip"
android:paddingEnd="16dip"
- android:src="@drawable/ic_delete"
- android:contentDescription="@string/zen_mode_delete_rule"
+ android:src="@drawable/ic_settings"
+ android:contentDescription="zen_mode_rule_settings"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
diff --git a/res/menu/manage_apps.xml b/res/menu/manage_apps.xml
index 99dba37..51189a0 100644
--- a/res/menu/manage_apps.xml
+++ b/res/menu/manage_apps.xml
@@ -16,6 +16,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"
android:icon="@drawable/ic_settings_24dp"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 0ddd3ea..f95809e 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -701,6 +701,15 @@
<item>120000</item>
</integer-array>
+ <!-- Summaries of accessibility timeout, pairs to Values -->
+ <string-array name="accessibility_timeout_summaries" translatable="false">
+ <item>@string/accessibility_timeout_default</item>
+ <item>@string/accessibility_timeout_10secs</item>
+ <item>@string/accessibility_timeout_30secs</item>
+ <item>@string/accessibility_timeout_1min</item>
+ <item>@string/accessibility_timeout_2mins</item>
+ </string-array>
+
<!-- Titles for the list of long press timeout options. -->
<string-array name="long_press_timeout_selector_titles">
<!-- A title for the option for short long-press timeout [CHAR LIMIT=25] -->
@@ -1068,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">
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 752fd3d..86763b7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -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" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 83848af..a6c6c37 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -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>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4700d3f..b6d9239 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -653,6 +653,8 @@
<string name="done">Done</string>
<!-- Button label for generic apply action [CHAR LIMIT=20] -->
<string name="apply">Apply</string>
+ <!-- Button label for generic share action [CHAR LIMIT=20] -->
+ <string name="share">Share</string>
<!-- Title of the Settings activity shown within the application itself. -->
<string name="settings_label">Settings</string>
@@ -670,7 +672,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 +2880,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 +3622,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 -->
@@ -3757,6 +3767,8 @@
<string name="lockpassword_choose_your_pattern_header_for_face">To use face authentication, set pattern</string>
<!-- Header on first screen of choose password/PIN as backup for face authentication flow. If this string cannot be translated in under 40 characters, please translate "Set face authentication backup" [CHAR LIMIT=40] -->
<string name="lockpassword_choose_your_pin_header_for_face">To use face authentication, set PIN</string>
+ <!-- Message on Wi-Fi Sharing screen [CHAR LIMIT=NONE] -->
+ <string name="wifi_sharing_message">Your Wi\u2011Fi name and password for \"<xliff:g id="SSID" example="GoogleGuest">%1$s</xliff:g>\" will be shared.</string>
<!-- Message to be used to explain the user that he needs to enter his pattern to continue a
particular operation. [CHAR LIMIT=70]-->
@@ -5407,6 +5419,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>
@@ -7084,8 +7102,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]-->
@@ -7118,11 +7136,17 @@
<!-- Do not disturb: Title for the zen mode automation option in Settings. [CHAR LIMIT=40] -->
<string name="zen_mode_automation_settings_title">Schedules</string>
+ <!-- Do not disturb: Title for dialog that allows users to delete DND rules/schedules[CHAR LIMIT=40] -->
+ <string name="zen_mode_delete_automatic_rules">Delete schedules</string>
+
+ <!-- Do not disturb: Delete text button presented in a dialog to confirm the user would like to delete the selected DND rules. [CHAR LIMIT=30] -->
+ <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>
@@ -7137,7 +7161,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>
@@ -7161,7 +7185,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] -->
@@ -7254,6 +7278,9 @@
<!-- [CHAR LIMIT=110] Zen mode settings footer: Footer how DND was triggered by an app -->
<string name="zen_mode_settings_dnd_automatic_rule_app">Do Not Disturb was automatically turned on by an app (<xliff:g id="app_name" example="Android Services">%s</xliff:g>)</string>
+ <!-- [CHAR LIMIT=120] Zen mode settings footer: Footer informing user DND has custom settings. -->
+ <string name="zen_mode_settings_dnd_custom_settings_footer">Do Not Disturb is on for <xliff:g id="rule_names" example="Sleeping and Work">%s</xliff:g> with custom settings.</string>
+
<!--[CHAR LIMIT=40] Zen Interruption level: Priority. -->
<string name="zen_interruption_level_priority">Priority only</string>
@@ -7264,7 +7291,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>
@@ -7289,12 +7316,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]-->
@@ -7745,28 +7772,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>
@@ -7847,7 +7874,16 @@
<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>
+
+ <!-- [CHAR LIMIT=120] Zen mode settings: Summay text indicating the currenty dnd schedule is using the default dnd settings -->
+ <string name="zen_mode_custom_behavior_summary_default">Use default settings</string>
+
+ <!-- [CHAR LIMIT=120] Zen mode settings: Summay text indicating the currenty dnd schedule is using custom behavior -->
+ <string name="zen_mode_custom_behavior_summary">Create custom settings for this schedule</string>
<!-- [CHAR LIMIT=40] General divider text when concatenating multiple items in a text summary -->
<string name="summary_divider_text">,\u0020</string>
@@ -7859,10 +7895,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>
@@ -7877,25 +7913,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>
@@ -7915,9 +7939,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>
@@ -7925,7 +7955,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>
@@ -7949,7 +7979,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">
@@ -7980,10 +8010,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>
@@ -8959,7 +8989,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>
@@ -8971,7 +9001,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 & 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>
@@ -9433,6 +9463,11 @@
<string name="managed_profile_contact_search_title">Contact search</string>
<!-- [CHAR LIMIT=NONE] The preference summary for enabling cross-profile remote contact search -->
<string name="managed_profile_contact_search_summary">Allow contact searches by your organization to identify callers and contacts</string>
+ <!-- [CHAR LIMIT=60] The preference title for enabling cross profile calendar sync -->
+ <string name="cross_profile_calendar_title">Cross-profile calendar</string>
+ <!-- [CHAR LIMIT=NONE] The preference summary for enabling cross profile calendar sync -->
+ <string name="cross_profile_calendar_summary">Show work events on personal calendar</string>
+
<!-- Time in hours -->
<plurals name="hours">
@@ -10218,15 +10253,17 @@
<!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] -->
<string name="network_connection_timeout_dialog_message">No devices found. Make sure the device is turned on and available to connect.</string>
<!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] -->
- <string name="network_connection_timeout_dialog_ok">Scan again</string>
+ <string name="network_connection_timeout_dialog_ok">Try again</string>
+ <!-- Message for Network connection error state Dialog [CHAR LIMIT=NONE] -->
+ <string name="network_connection_errorstate_dialog_message">Something came up. The application has cancelled the request to choose a device.</string>
- <!-- Summary for connected devices count in connected device slice. [CHAR LIMIT=NONE] -->
- <plurals name="show_connected_devices">
+ <!-- Summary for bluetooth devices count in Bluetooth devices slice. [CHAR LIMIT=NONE] -->
+ <plurals name="show_bluetooth_devices">
<item quantity="one"><xliff:g id="number_device_count">%1$d</xliff:g> device connected</item>
<item quantity="other"><xliff:g id="number_device_count">%1$d</xliff:g> devices connected</item>
</plurals>
- <!-- Title for no connected devices in connected device slice. [CHAR LIMIT=NONE] -->
- <string name="no_connected_devices">No connected devices</string>
+ <!-- Title for no bluetooth devices in Bluetooth devices slice. [CHAR LIMIT=NONE] -->
+ <string name="no_bluetooth_devices">No Bluetooth devices</string>
<!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
<string name="settings_panel_title">Settings Panel</string>
@@ -10234,6 +10271,9 @@
<!-- Title for the Internet Connectivity dialog (settings panel) with Internet related settings [CHAR LIMIT=50] -->
<string name="internet_connectivity_panel_title">Internet Connectivity</string>
+ <!-- Title for the Volume dialog (settings panel) with all volume streams[CHAR LIMIT=50] -->
+ <string name="volume_connectivity_panel_title">Volume</string>
+
<!-- UI debug setting: force desktop mode [CHAR LIMIT=50] -->
<string name="force_desktop_mode">Force desktop mode</string>
<!-- UI debug setting: force desktop mode summary [CHAR LIMIT=NONE] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8a92eaa..19ce333 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -401,16 +401,6 @@
<style name="ActionSecondaryButton" parent="android:Widget.DeviceDefault.Button"/>
- <style name="SettingsActionButton"
- parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
- <item name="android:drawablePadding">4dp</item>
- <item name="android:drawableTint">@*android:color/btn_colored_borderless_text_material
- </item>
- <item name="android:layout_marginEnd">8dp</item>
- <item name="android:paddingTop">20dp</item>
- <item name="android:paddingBottom">20dp</item>
- </style>
-
<style name="LockPatternContainerStyle">
<item name="android:maxHeight">400dp</item>
<item name="android:maxWidth">420dp</item>
@@ -471,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"
diff --git a/res/values/themes.xml b/res/values/themes.xml
index be57bd3..1e24770 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -54,6 +54,10 @@
<item name="batteryGoodColor">@color/battery_good_color_light</item>
<item name="batteryMaybeColor">@color/battery_maybe_color_light</item>
<item name="batteryBadColor">@color/battery_bad_color_light</item>
+
+ <!-- TODO(118444000): Remove colorPrimary and colorPrimaryVariant -->
+ <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
+ <item name="colorPrimaryVariant">@android:color/white</item>
</style>
<!-- Variant of the settings theme with no action bar. -->
@@ -185,6 +189,8 @@
<item name="batteryGoodColor">@color/battery_good_color_light</item>
<item name="batteryMaybeColor">@color/battery_maybe_color_light</item>
<item name="batteryBadColor">@color/battery_bad_color_light</item>
+ <!-- Define this color for material design -->
+ <item name="colorPrimaryVariant">@android:color/white</item>
</style>
<style name="Theme.Settings.Home" parent="Theme.Settings.HomeBase">
diff --git a/res/xml/accessibility_content_timeout_settings.xml b/res/xml/accessibility_content_timeout_settings.xml
index d450449..2d9072b 100644
--- a/res/xml/accessibility_content_timeout_settings.xml
+++ b/res/xml/accessibility_content_timeout_settings.xml
@@ -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>
diff --git a/res/xml/accessibility_control_timeout_settings.xml b/res/xml/accessibility_control_timeout_settings.xml
index 6d8e1d0..ea8d8c6 100644
--- a/res/xml/accessibility_control_timeout_settings.xml
+++ b/res/xml/accessibility_control_timeout_settings.xml
@@ -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>
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index 8f99ce1..506686a 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -36,7 +36,7 @@
settings:allowDividerAbove="true"
settings:allowDividerBelow="true"/>
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons"
android:order="-9998" />
@@ -72,12 +72,6 @@
settings:controller="com.android.settings.applications.appinfo.AppDataUsagePreferenceController" />
<Preference
- android:key="data_settings_v2"
- android:title="@string/data_usage_app_summary_title"
- android:summary="@string/summary_placeholder"
- settings:controller="com.android.settings.applications.appinfo.AppDataUsagePreferenceControllerV2" />
-
- <Preference
android:key="time_spent_in_app"
android:title="@string/time_spent_in_app_pref_title"
settings:controller="com.android.settings.applications.appinfo.TimeSpentInAppPreferenceController" />
@@ -185,4 +179,4 @@
settings:allowDividerAbove="true"
settings:enableCopying="true"/>
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/res/xml/app_storage_settings.xml b/res/xml/app_storage_settings.xml
index 7036d27..376f09e 100644
--- a/res/xml/app_storage_settings.xml
+++ b/res/xml/app_storage_settings.xml
@@ -19,7 +19,7 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/storage_label">
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="header_view" />
<com.android.settings.applications.SpacePreference
diff --git a/res/xml/battery_saver_schedule_settings.xml b/res/xml/battery_saver_schedule_settings.xml
new file mode 100644
index 0000000..f91e4ca
--- /dev/null
+++ b/res/xml/battery_saver_schedule_settings.xml
@@ -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 >
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 6449e4b..40ce93d 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -25,7 +25,7 @@
android:selectable="false"
settings:allowDividerBelow="true"/>
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons" />
<PreferenceCategory
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index a0f019d..be45cd0 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -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" />
diff --git a/res/xml/enterprise_privacy_settings.xml b/res/xml/enterprise_privacy_settings.xml
index 4fa50e7..e8b26b0 100644
--- a/res/xml/enterprise_privacy_settings.xml
+++ b/res/xml/enterprise_privacy_settings.xml
@@ -21,82 +21,107 @@
<!-- Header -->
<Preference android:key="enterprise_privacy_header"
+ android:order="100"
android:icon="@drawable/ic_info_outline_24dp"
android:summary="@string/enterprise_privacy_header"
android:selectable="false"/>
<PreferenceCategory android:key="exposure_category"
+ android:order="200"
android:title="@string/enterprise_privacy_exposure_category"
android:contentDescription="@string/enterprise_privacy_exposure_category">
<Preference android:key="enterprise_privacy_enterprise_data"
+ android:order="210"
android:layout_height="wrap_content"
android:title="@string/enterprise_privacy_enterprise_data"
android:selectable="false"/>
<Preference android:key="enterprise_privacy_installed_packages"
+ android:order="220"
android:title="@string/enterprise_privacy_installed_packages"
android:selectable="false"/>
<Preference android:key="enterprise_privacy_usage_stats"
+ android:order="230"
android:title="@string/enterprise_privacy_usage_stats"
android:selectable="false"/>
<Preference android:key="network_logs"
+ android:order="240"
android:title="@string/enterprise_privacy_network_logs"
android:selectable="false"/>
<Preference android:key="bug_reports"
+ android:order="250"
android:title="@string/enterprise_privacy_bug_reports"
android:selectable="false"/>
<Preference android:key="security_logs"
+ android:order="260"
android:title="@string/enterprise_privacy_security_logs"
android:selectable="false"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/enterprise_privacy_exposure_changes_category"
+ android:order="300"
android:key="exposure_changes_category">
<Preference android:fragment="com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages"
+ android:order="310"
android:key="number_enterprise_installed_packages"
android:title="@string/enterprise_privacy_enterprise_installed_packages"/>
<Preference android:fragment="com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionLocation"
+ android:order="320"
android:key="enterprise_privacy_number_location_access_packages"
android:title="@string/enterprise_privacy_location_access"/>
<Preference android:fragment="com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMicrophone"
+ android:order="330"
android:key="enterprise_privacy_number_microphone_access_packages"
android:title="@string/enterprise_privacy_microphone_access"/>
<Preference android:fragment="com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionCamera"
+ android:order="340"
android:key="enterprise_privacy_number_camera_access_packages"
android:title="@string/enterprise_privacy_camera_access"/>
<Preference android:fragment="com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment"
+ android:order="350"
android:key="number_enterprise_set_default_apps"
android:title="@string/enterprise_privacy_enterprise_set_default_apps"/>
<Preference android:key="always_on_vpn_primary_user"
+ android:order="360"
android:selectable="false"/>
<Preference android:key="always_on_vpn_managed_profile"
+ android:order="370"
android:title="@string/enterprise_privacy_always_on_vpn_work"
android:selectable="false"/>
<Preference android:key="input_method"
+ android:order="380"
android:title="@string/enterprise_privacy_input_method"
android:selectable="false"/>
<Preference android:key="global_http_proxy"
+ android:order="390"
android:title="@string/enterprise_privacy_global_http_proxy"
android:selectable="false"/>
<Preference android:key="ca_certs_current_user"
+ android:order="400"
android:title="@string/enterprise_privacy_ca_certs_personal"
android:selectable="false"/>
<Preference android:key="ca_certs_managed_profile"
+ android:order="410"
android:title="@string/enterprise_privacy_ca_certs_work"
android:selectable="false"/>
</PreferenceCategory>
<PreferenceCategory android:key="device_access_category"
+ android:order="500"
android:title="@string/enterprise_privacy_device_access_category">
<Preference android:key="enterprise_privacy_lock_device"
+ android:order="510"
android:title="@string/enterprise_privacy_lock_device"
android:selectable="false"/>
<Preference android:key="enterprise_privacy_wipe_device"
+ android:order="520"
android:title="@string/enterprise_privacy_wipe_device"
android:selectable="false"/>
<Preference android:key="failed_password_wipe_current_user"
+ android:order="530"
android:title="@string/enterprise_privacy_failed_password_wipe_device"
android:selectable="false"/>
<Preference android:key="failed_password_wipe_managed_profile"
+ android:order="540"
android:title="@string/enterprise_privacy_failed_password_wipe_work"
android:selectable="false"/>
</PreferenceCategory>
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index ee1e4fa..bd44cc1 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -32,4 +32,11 @@
settings:useAdditionalSummary="true"
settings:controller="com.android.settings.accounts.ContactSearchPreferenceController"/>
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="cross_profile_calendar"
+ android:summary="@string/cross_profile_calendar_summary"
+ android:title="@string/cross_profile_calendar_title"
+ settings:useAdditionalSummary="true"
+ settings:controller="com.android.settings.accounts.CrossProfileCalendarPreferenceController"/>
+
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/network_and_internet_v2.xml b/res/xml/network_and_internet_v2.xml
index 680b268..974739d 100644
--- a/res/xml/network_and_internet_v2.xml
+++ b/res/xml/network_and_internet_v2.xml
@@ -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"
diff --git a/res/xml/power_usage_detail.xml b/res/xml/power_usage_detail.xml
index 12c7e21..945ceed 100644
--- a/res/xml/power_usage_detail.xml
+++ b/res/xml/power_usage_detail.xml
@@ -26,7 +26,7 @@
android:order="-10000"
settings:allowDividerBelow="true"/>
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons"
android:order="-9999"/>
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index d38a8e4..ee8613d 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -28,6 +28,7 @@
android:icon="@drawable/ic_media_stream"
android:title="@string/media_volume_option_title"
android:order="-180"
+ settings:allowDynamicSummaryInSlice="true"
settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
<!-- Media output switcher -->
@@ -44,6 +45,7 @@
android:icon="@drawable/ic_local_phone_24_lib"
android:title="@string/call_volume_option_title"
android:order="-170"
+ settings:allowDynamicSummaryInSlice="true"
settings:controller="com.android.settings.notification.CallVolumePreferenceController"/>
<!-- Hands free profile output switcher -->
@@ -60,6 +62,7 @@
android:icon="@drawable/ic_notifications"
android:title="@string/ring_volume_option_title"
android:order="-160"
+ settings:allowDynamicSummaryInSlice="true"
settings:controller="com.android.settings.notification.RingVolumePreferenceController"/>
@@ -69,6 +72,7 @@
android:icon="@*android:drawable/ic_audio_alarm"
android:title="@string/alarm_volume_option_title"
android:order="-150"
+ settings:allowDynamicSummaryInSlice="true"
settings:controller="com.android.settings.notification.AlarmVolumePreferenceController"/>
<!-- Notification volume -->
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index e76cdb7..92bf5d7 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -50,7 +50,7 @@
android:defaultValue="100"
android:max="400"/>
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons" />
</PreferenceCategory>
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
index 8ec320a..15ab1aa 100644
--- a/res/xml/wifi_configure_settings.xml
+++ b/res/xml/wifi_configure_settings.xml
@@ -41,7 +41,8 @@
<SwitchPreference
android:key="wifi_cellular_data_fallback"
android:title="@string/wifi_cellular_data_fallback_title"
- android:summary="@string/wifi_cellular_data_fallback_summary" />
+ android:summary="@string/wifi_cellular_data_fallback_summary"
+ settings:controller="com.android.settings.wifi.CellularFallbackPreferenceController" />
<Preference
android:key="install_credentials"
diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
index 8b027e2..70bd194 100644
--- a/res/xml/wifi_network_details_fragment.xml
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -27,7 +27,7 @@
settings:allowDividerBelow="true"/>
<!-- Buttons -->
- <com.android.settings.widget.ActionButtonPreference
+ <com.android.settingslib.widget.ActionButtonsPreference
android:key="buttons"
android:selectable="false" />
@@ -60,6 +60,7 @@
<DropDownPreference
android:key="privacy"
+ android:icon="@drawable/ic_wifi_privacy_24dp"
android:title="@string/wifi_privacy_settings"
android:entries="@array/wifi_privacy_entries"
android:entryValues="@array/wifi_privacy_values"/>
diff --git a/res/xml/zen_mode_calls_settings.xml b/res/xml/zen_mode_calls_settings.xml
index 74b6986..4616cf8 100644
--- a/res/xml/zen_mode_calls_settings.xml
+++ b/res/xml/zen_mode_calls_settings.xml
@@ -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
diff --git a/res/xml/zen_mode_messages_settings.xml b/res/xml/zen_mode_messages_settings.xml
index 4ca6c92..2d0129e 100644
--- a/res/xml/zen_mode_messages_settings.xml
+++ b/res/xml/zen_mode_messages_settings.xml
@@ -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
diff --git a/res/xml/zen_mode_schedule_rule_settings.xml b/res/xml/zen_mode_schedule_rule_settings.xml
index d05bbd2..c257d87 100644
--- a/res/xml/zen_mode_schedule_rule_settings.xml
+++ b/res/xml/zen_mode_schedule_rule_settings.xml
@@ -43,4 +43,10 @@
android:summary="@string/zen_mode_schedule_alarm_summary"
android:order="99" />
+ <!-- Custom Do Not Disturb Setting-->
+ <Preference
+ android:key="zen_schedule_custom_setting"
+ android:title="@string/zen_mode_custom_behavior_title"
+ android:order="100" />
+
</PreferenceScreen>
diff --git a/res/xml/zen_mode_sound_vibration_settings.xml b/res/xml/zen_mode_sound_vibration_settings.xml
index 30e2abb..73b5b05 100644
--- a/res/xml/zen_mode_sound_vibration_settings.xml
+++ b/res/xml/zen_mode_sound_vibration_settings.xml
@@ -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 -->
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java
index 7b0be94..5ab543f 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/CredentialStorage.java
@@ -172,8 +172,9 @@
dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
return;
}
- installIfAvailable();
- finish();
+ if (installIfAvailable()) {
+ finish();
+ }
return;
}
}
@@ -217,10 +218,13 @@
/**
* Install credentials if available, otherwise do nothing.
+ *
+ * @return true if the installation is done and the activity should be finished, false if
+ * an asynchronous task is pending and will finish the activity when it's done.
*/
- private void installIfAvailable() {
+ private boolean installIfAvailable() {
if (mInstallBundle == null || mInstallBundle.isEmpty()) {
- return;
+ return true;
}
final Bundle bundle = mInstallBundle;
@@ -235,16 +239,17 @@
if (uid != Process.WIFI_UID) {
Log.e(TAG, "Failed to install credentials as uid " + uid + ": cross-user installs"
+ " may only target wifi uids");
- return;
+ return true;
}
final Intent installIntent = new Intent(ACTION_INSTALL)
.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
.putExtras(bundle);
startActivityAsUser(installIntent, new UserHandle(dstUserId));
- return;
+ return true;
}
+ boolean shouldFinish = true;
if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
@@ -259,7 +264,7 @@
if (!mKeyStore.importKey(key, value, uid, flags)) {
Log.e(TAG, "Failed to install " + key + " as uid " + uid);
- return;
+ return true;
}
// The key was prepended USER_PRIVATE_KEY by the CredentialHelper. However,
// KeyChain internally uses the raw alias name and only prepends USER_PRIVATE_KEY
@@ -270,6 +275,7 @@
if (uid == Process.SYSTEM_UID || uid == KeyStore.UID_SELF) {
new MarkKeyAsUserSelectable(
key.replaceFirst("^" + Credentials.USER_PRIVATE_KEY, "")).execute();
+ shouldFinish = false;
}
}
@@ -281,7 +287,7 @@
if (!mKeyStore.put(certName, certData, uid, flags)) {
Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
- return;
+ return shouldFinish;
}
}
@@ -291,7 +297,7 @@
if (!mKeyStore.put(caListName, caListData, uid, flags)) {
Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
- return;
+ return shouldFinish;
}
}
@@ -300,6 +306,7 @@
sendBroadcast(broadcast);
setResult(RESULT_OK);
+ return shouldFinish;
}
/**
@@ -411,6 +418,13 @@
return false;
}
}
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ Log.i(TAG, String.format("Marked alias %s as selectable, success? %s",
+ mAlias, result));
+ CredentialStorage.this.finish();
+ }
}
/**
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1f331d7..05054b4 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -33,11 +33,11 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
+import android.sysprop.VoldProperties;
import android.telecom.TelecomManager;
import android.telephony.TelephonyManager;
import android.text.Editable;
@@ -400,7 +400,7 @@
super.onCreate(savedInstanceState);
// If we are not encrypted or encrypting, get out quickly.
- final String state = SystemProperties.get("vold.decrypt");
+ final String state = VoldProperties.decrypt().orElse("");
if (!isDebugView() && ("".equals(state) || DECRYPT_STATE.equals(state))) {
disableCryptKeeperComponent(this);
// Typically CryptKeeper is launched as the home app. We didn't
@@ -468,7 +468,7 @@
return;
}
- final String progress = SystemProperties.get("vold.encrypt_progress");
+ final String progress = VoldProperties.encrypt_progress().orElse("");
if (!"".equals(progress) || isDebugView(FORCE_VIEW_PROGRESS)) {
setContentView(R.layout.crypt_keeper_progress);
encryptionProgressInit();
@@ -636,7 +636,7 @@
}
private void updateProgress() {
- final String state = SystemProperties.get("vold.encrypt_progress");
+ final String state = VoldProperties.encrypt_progress().orElse("");
if ("error_partially_encrypted".equals(state)) {
showFactoryReset(false);
@@ -657,8 +657,7 @@
// Now try to get status as time remaining and replace as appropriate
Log.v(TAG, "Encryption progress: " + progress);
try {
- final String timeProperty = SystemProperties.get("vold.encrypt_time_remaining");
- int time = Integer.parseInt(timeProperty);
+ int time = VoldProperties.encrypt_time_remaining().get();
if (time >= 0) {
// Round up to multiple of 10 - this way display is less jerky
time = (time + 9) / 10 * 10;
@@ -773,9 +772,10 @@
if (imeSwitcher != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
imeSwitcher.setVisibility(View.VISIBLE);
imeSwitcher.setOnClickListener(new OnClickListener() {
- @Override
+ @Override
public void onClick(View v) {
- imm.showInputMethodPicker(false /* showAuxiliarySubtypes */);
+ imm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */,
+ v.getDisplay().getDisplayId());
}
});
}
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 97942fe..307bbc1 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -39,6 +39,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.sysprop.VoldProperties;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
@@ -440,7 +441,7 @@
}
private boolean isExtStorageEncrypted() {
- String state = SystemProperties.get("vold.decrypt");
+ String state = VoldProperties.decrypt().orElse("");
return !"".equals(state);
}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 222c18c..9b5fc00 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -35,9 +35,9 @@
import android.transition.TransitionManager;
import android.util.Log;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.Toolbar;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -168,6 +168,12 @@
private Button mNextButton;
+ /**
+ * TODO(b/118444000): Remove this and all related code.
+ */
+ @Deprecated
+ private boolean mIsShowingDashboard;
+
private ViewGroup mContent;
// Categories
@@ -250,7 +256,11 @@
setTheme(R.style.Theme_SubSettings);
}
- setContentView(R.layout.settings_main_prefs);
+ mIsShowingDashboard = TextUtils.equals(
+ SettingsActivity.class.getName(), intent.getComponent().getClassName());
+
+ setContentView(mIsShowingDashboard ?
+ R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
mContent = findViewById(R.id.main_content);
@@ -273,12 +283,21 @@
}
final boolean deviceProvisioned = Utils.isDeviceProvisioned(this);
+ if (mIsShowingDashboard) {
+ findViewById(R.id.search_bar).setVisibility(
+ deviceProvisioned ? View.VISIBLE : View.INVISIBLE);
+ findViewById(R.id.action_bar).setVisibility(View.GONE);
+ final Toolbar toolbar = findViewById(R.id.search_action_bar);
+ setActionBar(toolbar);
+ FeatureFactory.getFactory(this).getSearchFeatureProvider()
+ .initSearchToolbar(this, toolbar);
+ }
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(deviceProvisioned);
actionBar.setHomeButtonEnabled(deviceProvisioned);
- actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setDisplayShowTitleEnabled(!mIsShowingDashboard);
}
mSwitchBar = findViewById(R.id.switch_bar);
if (mSwitchBar != null) {
@@ -292,26 +311,20 @@
if (buttonBar != null) {
buttonBar.setVisibility(View.VISIBLE);
- Button backButton = (Button) findViewById(R.id.back_button);
- backButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- setResult(RESULT_CANCELED, null);
- finish();
- }
+ Button backButton = findViewById(R.id.back_button);
+ backButton.setOnClickListener(v -> {
+ setResult(RESULT_CANCELED, null);
+ finish();
});
- Button skipButton = (Button) findViewById(R.id.skip_button);
- skipButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- setResult(RESULT_OK, null);
- finish();
- }
+ Button skipButton = findViewById(R.id.skip_button);
+ skipButton.setOnClickListener(v -> {
+ setResult(RESULT_OK, null);
+ finish();
});
- mNextButton = (Button) findViewById(R.id.next_button);
- mNextButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- setResult(RESULT_OK, null);
- finish();
- }
+ mNextButton = findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(v -> {
+ setResult(RESULT_OK, null);
+ finish();
});
// set our various button parameters
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 65b0e86..76be66d 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -21,6 +21,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -63,6 +64,8 @@
import com.android.settingslib.accessibility.AccessibilityUtils;
import com.android.settingslib.search.SearchIndexable;
+import com.google.common.primitives.Ints;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -125,6 +128,11 @@
"vibration_preference_screen";
private static final String DISPLAY_DALTONIZER_PREFERENCE_SCREEN =
"daltonizer_preference";
+ private static final String ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE =
+ "accessibility_content_timeout_preference_fragment";
+ private static final String ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE =
+ "accessibility_control_timeout_preference_fragment";
+
// Extras passed to sub-fragments.
static final String EXTRA_PREFERENCE_KEY = "preference_key";
@@ -659,6 +667,8 @@
mToggleInversionPreference.getOrder() + 1);
mToggleDisableAnimationsPreference.setOrder(
mToggleLargePointerIconPreference.getOrder() + 1);
+ findPreference(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE).setOrder(
+ mToggleDisableAnimationsPreference.getOrder() + 1);
mToggleInversionPreference.setSummary(R.string.summary_empty);
displayCategory.addPreference(mToggleInversionPreference);
displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen);
@@ -718,6 +728,31 @@
updateAutoclickSummary(mAutoclickPreferenceScreen);
updateAccessibilityShortcut(mAccessibilityShortcutPreferenceScreen);
+
+ updateAccessibilityTimeoutSummary(getContentResolver(),
+ findPreference(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE));
+ updateAccessibilityTimeoutSummary(getContentResolver(),
+ findPreference(ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE));
+ }
+
+ void updateAccessibilityTimeoutSummary(ContentResolver resolver, Preference pref) {
+
+ String[] timeoutSummarys = getResources().getStringArray(
+ R.array.accessibility_timeout_summaries);
+ int[] timeoutValues = getResources().getIntArray(
+ R.array.accessibility_timeout_selector_values);
+
+ int timeoutValue = 0;
+ if (pref.getKey().equals(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE)) {
+ timeoutValue = AccessibilityTimeoutController.getSecureAccessibilityTimeoutValue(
+ resolver, AccessibilityTimeoutController.CONTENT_TIMEOUT_SETTINGS_SECURE);
+ } else if (pref.getKey().equals(ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE)) {
+ timeoutValue = AccessibilityTimeoutController.getSecureAccessibilityTimeoutValue(
+ resolver, AccessibilityTimeoutController.CONTROL_TIMEOUT_SETTINGS_SECURE);
+ }
+
+ int idx = Ints.indexOf(timeoutValues, timeoutValue);
+ pref.setSummary(timeoutSummarys[idx == -1 ? 0 : idx]);
}
private void updateMagnificationSummary(Preference pref) {
diff --git a/src/com/android/settings/accessibility/AccessibilityTimeoutController.java b/src/com/android/settings/accessibility/AccessibilityTimeoutController.java
index 2995df5..d933d92 100644
--- a/src/com/android/settings/accessibility/AccessibilityTimeoutController.java
+++ b/src/com/android/settings/accessibility/AccessibilityTimeoutController.java
@@ -31,6 +31,8 @@
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.google.common.primitives.Ints;
+
import java.lang.Integer;
import java.util.HashMap;
@@ -38,6 +40,10 @@
public class AccessibilityTimeoutController extends AbstractPreferenceController implements
LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
+ static final String CONTENT_TIMEOUT_SETTINGS_SECURE =
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS;
+ static final String CONTROL_TIMEOUT_SETTINGS_SECURE =
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS;
// pair the preference key and timeout value
private final Map<String, Integer> mAccessibilityTimeoutKeyToValueMap = new HashMap<>();
@@ -64,6 +70,15 @@
mfragmentTag = fragmentTag;
}
+ protected static int getSecureAccessibilityTimeoutValue(ContentResolver resolver, String name) {
+ String timeOutSec = Settings.Secure.getString(resolver, name);
+ if (timeOutSec == null) {
+ return 0;
+ }
+ Integer timeOutValue = Ints.tryParse(timeOutSec);
+ return timeOutValue == null ? 0 : timeOutValue;
+ }
+
public void setOnChangeListener(OnChangeListener listener) {
mOnChangeListener = listener;
}
@@ -131,16 +146,17 @@
}
}
- protected void getAccessibilityUiValue() {
- String timeoutValue = null;
- if (mfragmentTag.equals(AccessibilityContentTimeoutPreferenceFragment.TAG)) {
- timeoutValue = Settings.Secure.getString(mContentResolver,
- Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
- } else if (mfragmentTag.equals(AccessibilityControlTimeoutPreferenceFragment.TAG)) {
- timeoutValue = Settings.Secure.getString(mContentResolver,
- Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
+ private int getAccessibilityTimeoutValue(String fragmentTag) {
+ int timeoutValue = 0;
+ // two kinds of Secure value, one is content timeout, the other is control timeout.
+ if (AccessibilityContentTimeoutPreferenceFragment.TAG.equals(fragmentTag)) {
+ timeoutValue = getSecureAccessibilityTimeoutValue(mContentResolver,
+ CONTENT_TIMEOUT_SETTINGS_SECURE);
+ } else if (AccessibilityControlTimeoutPreferenceFragment.TAG.equals(fragmentTag)) {
+ timeoutValue = getSecureAccessibilityTimeoutValue(mContentResolver,
+ CONTROL_TIMEOUT_SETTINGS_SECURE);
}
- mAccessibilityUiTimeoutValue = timeoutValue == null? 0: Integer.parseInt(timeoutValue);
+ return timeoutValue;
}
protected void updatePreferenceCheckedState(int value) {
@@ -153,7 +169,7 @@
public void updateState(Preference preference) {
super.updateState(preference);
- getAccessibilityUiValue();
+ mAccessibilityUiTimeoutValue = getAccessibilityTimeoutValue(mfragmentTag);
// reset RadioButton
mPreference.setChecked(false);
diff --git a/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java b/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java
new file mode 100644
index 0000000..38c95dc
--- /dev/null
+++ b/src/com/android/settings/accounts/CrossProfileCalendarPreferenceController.java
@@ -0,0 +1,79 @@
+/*
+ * 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.accounts;
+
+import static android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.slices.SliceData;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import androidx.preference.Preference;
+
+public class CrossProfileCalendarPreferenceController extends TogglePreferenceController {
+
+ private UserHandle mManagedUser;
+
+ public CrossProfileCalendarPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ public void setManagedUser(UserHandle managedUser) {
+ mManagedUser = managedUser;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (preference instanceof RestrictedSwitchPreference && mManagedUser != null) {
+ final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+ final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
+ RestrictedLockUtilsInternal.getCrossProfileCalendarEnforcingAdmin(
+ mContext, mManagedUser.getIdentifier());
+ pref.setDisabledByAdmin(enforcedAdmin);
+ }
+ }
+
+ @Override
+ public boolean isChecked() {
+ if (mManagedUser == null) {
+ return false;
+ }
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, /* default= */ 0,
+ mManagedUser.getIdentifier()) == 1;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (mManagedUser == null) {
+ return false;
+ }
+ final int value = isChecked ? 1 : 0;
+ return Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, value, mManagedUser.getIdentifier());
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
index 408db09..33e7771 100644
--- a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
+++ b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
@@ -36,8 +36,9 @@
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 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));
}
diff --git a/src/com/android/settings/accounts/ManagedProfileSettings.java b/src/com/android/settings/accounts/ManagedProfileSettings.java
index 07e5845..dccd7f6 100644
--- a/src/com/android/settings/accounts/ManagedProfileSettings.java
+++ b/src/com/android/settings/accounts/ManagedProfileSettings.java
@@ -23,17 +23,25 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.SearchIndexableResource;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Setting page for managed profile.
* FIXME: It currently assumes there is only one managed profile.
*/
+@SearchIndexable
public class ManagedProfileSettings extends DashboardFragment {
private UserManager mUserManager;
@@ -63,6 +71,7 @@
}
use(WorkModePreferenceController.class).setManagedUser(mManagedUser);
use(ContactSearchPreferenceController.class).setManagedUser(mManagedUser);
+ use(CrossProfileCalendarPreferenceController.class).setManagedUser(mManagedUser);
}
@Override
@@ -99,6 +108,23 @@
return MetricsProto.MetricsEvent.ACCOUNTS_WORK_PROFILE_SETTINGS;
}
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final ArrayList<SearchIndexableResource> result = new ArrayList<>();
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.managed_profile_settings;
+ result.add(sir);
+ return result;
+ }
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return false;
+ }
+ };
+
private class ManagedProfileBroadcastReceiver extends BroadcastReceiver {
@Override
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
index 61ce33d..61293c5 100644
--- a/src/com/android/settings/applications/AppStorageSettings.java
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -53,11 +53,11 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
-import com.android.settings.widget.ActionButtonPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.ApplicationsState.Callbacks;
import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
+import com.android.settingslib.widget.ActionButtonsPreference;
import com.android.settingslib.widget.LayoutPreference;
import java.util.Collections;
@@ -107,7 +107,7 @@
// Views related to cache info
@VisibleForTesting
- ActionButtonPreference mButtonsPref;
+ ActionButtonsPreference mButtonsPref;
private Preference mStorageUsed;
private Button mChangeStorageButton;
@@ -168,7 +168,7 @@
.setComputingString(R.string.computing_size)
.setErrorString(R.string.invalid_size_value)
.build();
- mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS));
+ mButtonsPref = ((ActionButtonsPreference) findPreference(KEY_HEADER_BUTTONS));
mStorageUsed = findPreference(KEY_STORAGE_USED);
mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
.findViewById(R.id.button);
diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
index 9740ecb..2e528a7 100644
--- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
@@ -54,7 +54,6 @@
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.widget.ActionButtonPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.applications.AppUtils;
@@ -64,6 +63,7 @@
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.widget.ActionButtonsPreference;
import java.util.ArrayList;
import java.util.HashSet;
@@ -99,8 +99,9 @@
@VisibleForTesting
boolean mDisableAfterUninstall = false;
@VisibleForTesting
- ActionButtonPreference mButtonsPref;
+ ActionButtonsPreference mButtonsPref;
+ private final int mUserId;
private final int mRequestUninstall;
private final int mRequestRemoveDeviceAdmin;
private final DevicePolicyManager mDpm;
@@ -110,8 +111,8 @@
private final InstrumentedPreferenceFragment mFragment;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final ApplicationFeatureProvider mApplicationFeatureProvider;
- private final int mUserId;
+ private Intent mAppLaunchIntent;
private ApplicationsState.Session mSession;
private RestrictedLockUtils.EnforcedAdmin mAppsControlDisallowedAdmin;
@@ -144,6 +145,7 @@
mUserId = UserHandle.myUserId();
mRequestUninstall = requestUninstall;
mRequestRemoveDeviceAdmin = requestRemoveDeviceAdmin;
+ mAppLaunchIntent = mPm.getLaunchIntentForPackage(mPackageName);
if (packageName != null) {
mAppEntry = mState.getEntry(packageName, mUserId);
@@ -158,21 +160,25 @@
public int getAvailabilityStatus() {
// TODO(b/37313605): Re-enable once this controller supports instant apps
return mAppEntry != null && !AppUtils.isInstant(mAppEntry.info)
- ? AVAILABLE : DISABLED_FOR_USER ;
+ ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (isAvailable()) {
- mButtonsPref = ((ActionButtonPreference) screen.findPreference(KEY_ACTION_BUTTONS))
- .setButton1Text(R.string.uninstall_text)
- .setButton1Icon(R.drawable.ic_settings_delete)
- .setButton2Text(R.string.force_stop)
- .setButton2Icon(R.drawable.ic_settings_force_stop)
- .setButton1OnClickListener(new UninstallAndDisableButtonListener())
- .setButton2OnClickListener(new ForceStopButtonListener())
- .setButton2Enabled(false);
+ mButtonsPref = ((ActionButtonsPreference) screen.findPreference(
+ KEY_ACTION_BUTTONS))
+ .setButton1Text(R.string.launch_instant_app)
+ .setButton1Icon(R.drawable.ic_settings_open)
+ .setButton1OnClickListener(v -> launchApplication())
+ .setButton2Text(R.string.uninstall_text)
+ .setButton2Icon(R.drawable.ic_settings_delete)
+ .setButton2OnClickListener(new UninstallAndDisableButtonListener())
+ .setButton3Text(R.string.force_stop)
+ .setButton3Icon(R.drawable.ic_settings_force_stop)
+ .setButton3OnClickListener(new ForceStopButtonListener())
+ .setButton3Enabled(false);
}
}
@@ -361,6 +367,12 @@
}
@VisibleForTesting
+ void updateOpenButton() {
+ mAppLaunchIntent = mPm.getLaunchIntentForPackage(mPackageName);
+ mButtonsPref.setButton1Visible(mAppLaunchIntent != null);
+ }
+
+ @VisibleForTesting
void updateUninstallButton() {
final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
boolean enabled = true;
@@ -430,7 +442,7 @@
enabled = false;
}
- mButtonsPref.setButton1Enabled(enabled);
+ mButtonsPref.setButton2Enabled(enabled);
}
/**
@@ -484,7 +496,7 @@
} else {
Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
Uri.fromParts("package", mAppEntry.info.packageName, null));
- intent.putExtra(Intent.EXTRA_PACKAGES, new String[] {mAppEntry.info.packageName});
+ intent.putExtra(Intent.EXTRA_PACKAGES, new String[]{mAppEntry.info.packageName});
intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
Log.d(TAG, "Sending broadcast to query restart status for "
@@ -497,9 +509,9 @@
@VisibleForTesting
void updateForceStopButtonInner(boolean enabled) {
if (mAppsControlDisallowedBySystem) {
- mButtonsPref.setButton2Enabled(false);
+ mButtonsPref.setButton3Enabled(false);
} else {
- mButtonsPref.setButton2Enabled(enabled);
+ mButtonsPref.setButton3Enabled(enabled);
}
}
@@ -547,16 +559,16 @@
if (mHomePackages.contains(mAppEntry.info.packageName)
|| isSystemPackage(mActivity.getResources(), mPm, mPackageInfo)) {
// Disable button for core system applications.
- mButtonsPref.setButton1Text(R.string.uninstall_text)
- .setButton1Icon(R.drawable.ic_settings_delete);
+ mButtonsPref.setButton2Text(R.string.uninstall_text)
+ .setButton2Icon(R.drawable.ic_settings_delete);
} else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
- mButtonsPref.setButton1Text(R.string.uninstall_text)
- .setButton1Icon(R.drawable.ic_settings_delete);
+ mButtonsPref.setButton2Text(R.string.uninstall_text)
+ .setButton2Icon(R.drawable.ic_settings_delete);
disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
.contains(mAppEntry.info.packageName);
} else {
- mButtonsPref.setButton1Text(R.string.install_text)
- .setButton1Icon(R.drawable.ic_settings_install);
+ mButtonsPref.setButton2Text(R.string.install_text)
+ .setButton2Icon(R.drawable.ic_settings_install);
disableable = true;
}
@@ -639,6 +651,7 @@
}
}
+ updateOpenButton();
updateUninstallButton();
updateForceStopButton();
@@ -663,6 +676,11 @@
mActivity.unregisterReceiver(mPackageRemovedReceiver);
}
+ private void launchApplication() {
+ if (mAppLaunchIntent != null) {
+ mContext.startActivityAsUser(mAppLaunchIntent, new UserHandle(mUserId));
+ }
+ }
/**
* Changes the status of disable/enable for a package
diff --git a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
index 9443c93..1bfcd7d 100644
--- a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -17,15 +17,10 @@
package com.android.settings.applications.appinfo;
import android.content.Context;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
import android.net.NetworkTemplate;
import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.text.format.DateUtils;
import android.text.format.Formatter;
-import android.util.FeatureFlagUtils;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
@@ -36,53 +31,35 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.datausage.AppDataUsage;
-import com.android.settings.datausage.DataUsageList;
import com.android.settings.datausage.DataUsageUtils;
import com.android.settingslib.AppItem;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
-import com.android.settingslib.net.ChartData;
-import com.android.settingslib.net.ChartDataLoaderCompat;
+import com.android.settingslib.net.NetworkCycleDataForUid;
+import com.android.settingslib.net.NetworkCycleDataForUidLoader;
-/**
- * Deprecated in favor of {@link AppDataUsagePreferenceControllerV2}
- *
- * @deprecated
- */
-@Deprecated
+import java.util.List;
+
public class AppDataUsagePreferenceController extends AppInfoPreferenceControllerBase
- implements LoaderManager.LoaderCallbacks<ChartData>, LifecycleObserver, OnResume, OnPause {
+ implements LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>, LifecycleObserver,
+ OnResume, OnPause {
- private ChartData mChartData;
- private INetworkStatsSession mStatsSession;
+ private List<NetworkCycleDataForUid> mAppUsageData;
- public AppDataUsagePreferenceController(Context context,String key) {
+ public AppDataUsagePreferenceController(Context context, String key) {
super(context, key);
}
@Override
public int getAvailabilityStatus() {
- if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.DATA_USAGE_V2)) {
- return UNSUPPORTED_ON_DEVICE;
- }
return isBandwidthControlEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- if (isAvailable()) {
- final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- try {
- mStatsSession = statsService.openSession();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
}
@Override
@@ -92,36 +69,42 @@
@Override
public void onResume() {
- if (mStatsSession != null) {
+ if (isAvailable()) {
final int uid = mParent.getAppEntry().info.uid;
final AppItem app = new AppItem(uid);
app.addUid(uid);
- mParent.getLoaderManager().restartLoader(mParent.LOADER_CHART_DATA,
- ChartDataLoaderCompat.buildArgs(getTemplate(mContext), app),
+ mParent.getLoaderManager().restartLoader(mParent.LOADER_CHART_DATA, null /* args */,
this);
}
}
@Override
public void onPause() {
- if (mStatsSession != null) {
+ if (isAvailable()) {
mParent.getLoaderManager().destroyLoader(mParent.LOADER_CHART_DATA);
}
}
@Override
- public Loader<ChartData> onCreateLoader(int id, Bundle args) {
- return new ChartDataLoaderCompat(mContext, mStatsSession, args);
+ public Loader<List<NetworkCycleDataForUid>> onCreateLoader(int id, Bundle args) {
+ final NetworkTemplate template = getTemplate(mContext);
+ return NetworkCycleDataForUidLoader.builder(mContext)
+ .setUid(mParent.getAppEntry().info.uid)
+ .setRetrieveDetail(false)
+ .setNetworkTemplate(template)
+ .setSubscriberId(template.getSubscriberId())
+ .build();
}
@Override
- public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
- mChartData = data;
+ public void onLoadFinished(Loader<List<NetworkCycleDataForUid>> loader,
+ List<NetworkCycleDataForUid> data) {
+ mAppUsageData = data;
updateState(mPreference);
}
@Override
- public void onLoaderReset(Loader<ChartData> loader) {
+ public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
// Leave last result.
}
@@ -131,14 +114,22 @@
}
private CharSequence getDataSummary() {
- if (mChartData != null) {
- final long totalBytes = mChartData.detail.getTotalBytes();
+ if (mAppUsageData != null) {
+ long totalBytes = 0;
+ long startTime = System.currentTimeMillis();
+ for (NetworkCycleDataForUid data : mAppUsageData) {
+ totalBytes += data.getTotalUsage();
+ final long cycleStart = data.getStartTime();
+ if (cycleStart < startTime) {
+ startTime = cycleStart;
+ }
+ }
if (totalBytes == 0) {
return mContext.getString(R.string.no_data_usage);
}
return mContext.getString(R.string.data_summary_format,
Formatter.formatFileSize(mContext, totalBytes),
- DateUtils.formatDateTime(mContext, mChartData.detail.getStart(),
+ DateUtils.formatDateTime(mContext, startTime,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH));
}
return mContext.getString(R.string.computing_size);
diff --git a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java
deleted file mode 100644
index 9bbc5c0..0000000
--- a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java
+++ /dev/null
@@ -1,158 +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.applications.appinfo;
-
-import android.content.Context;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.util.FeatureFlagUtils;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.Loader;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-import com.android.settings.core.FeatureFlags;
-import com.android.settings.datausage.AppDataUsageV2;
-import com.android.settings.datausage.DataUsageUtils;
-import com.android.settingslib.AppItem;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-import com.android.settingslib.net.NetworkCycleDataForUid;
-import com.android.settingslib.net.NetworkCycleDataForUidLoader;
-
-import java.util.List;
-
-public class AppDataUsagePreferenceControllerV2 extends AppInfoPreferenceControllerBase
- implements LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>, LifecycleObserver,
- OnResume, OnPause {
-
- private List<NetworkCycleDataForUid> mAppUsageData;
-
- public AppDataUsagePreferenceControllerV2(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public int getAvailabilityStatus() {
- if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlags.DATA_USAGE_V2)) {
- return UNSUPPORTED_ON_DEVICE;
- }
- return isBandwidthControlEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- }
-
- @Override
- public void updateState(Preference preference) {
- preference.setSummary(getDataSummary());
- }
-
- @Override
- public void onResume() {
- if (isAvailable()) {
- final int uid = mParent.getAppEntry().info.uid;
- final AppItem app = new AppItem(uid);
- app.addUid(uid);
- mParent.getLoaderManager().restartLoader(mParent.LOADER_CHART_DATA, null /* args */,
- this);
- }
- }
-
- @Override
- public void onPause() {
- if (isAvailable()) {
- mParent.getLoaderManager().destroyLoader(mParent.LOADER_CHART_DATA);
- }
- }
-
- @Override
- public Loader<List<NetworkCycleDataForUid>> onCreateLoader(int id, Bundle args) {
- final NetworkTemplate template = getTemplate(mContext);
- return NetworkCycleDataForUidLoader.builder(mContext)
- .setUid(mParent.getAppEntry().info.uid)
- .setRetrieveDetail(false)
- .setNetworkTemplate(template)
- .setSubscriberId(template.getSubscriberId())
- .build();
- }
-
- @Override
- public void onLoadFinished(Loader<List<NetworkCycleDataForUid>> loader,
- List<NetworkCycleDataForUid> data) {
- mAppUsageData = data;
- updateState(mPreference);
- }
-
- @Override
- public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
- // Leave last result.
- }
-
- @Override
- protected Class<? extends SettingsPreferenceFragment> getDetailFragmentClass() {
- return AppDataUsageV2.class;
- }
-
- private CharSequence getDataSummary() {
- if (mAppUsageData != null) {
- long totalBytes = 0;
- long startTime = System.currentTimeMillis();
- for (NetworkCycleDataForUid data : mAppUsageData) {
- totalBytes += data.getTotalUsage();
- final long cycleStart = data.getStartTime();
- if (cycleStart < startTime) {
- startTime = cycleStart;
- }
- }
- if (totalBytes == 0) {
- return mContext.getString(R.string.no_data_usage);
- }
- return mContext.getString(R.string.data_summary_format,
- Formatter.formatFileSize(mContext, totalBytes),
- DateUtils.formatDateTime(mContext, startTime,
- DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH));
- }
- return mContext.getString(R.string.computing_size);
- }
-
- private static NetworkTemplate getTemplate(Context context) {
- if (DataUsageUtils.hasReadyMobileRadio(context)) {
- return NetworkTemplate.buildTemplateMobileWildcard();
- }
- if (DataUsageUtils.hasWifiRadio(context)) {
- return NetworkTemplate.buildTemplateWifiWildcard();
- }
- return NetworkTemplate.buildTemplateEthernet();
- }
-
- @VisibleForTesting
- boolean isBandwidthControlEnabled() {
- return Utils.isBandwidthControlEnabled();
- }
-
-}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 32880d3..80cc6ae 100755
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -34,7 +34,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -49,7 +48,6 @@
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.applications.specialaccess.pictureinpicture
.PictureInPictureDetailPreferenceController;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -141,11 +139,7 @@
final String packageName = getPackageName();
use(TimeSpentInAppPreferenceController.class).setPackageName(packageName);
- if (FeatureFlagUtils.isEnabled(context, FeatureFlags.DATA_USAGE_V2)) {
- use(AppDataUsagePreferenceControllerV2.class).setParentFragment(this);
- } else {
- use(AppDataUsagePreferenceController.class).setParentFragment(this);
- }
+ use(AppDataUsagePreferenceController.class).setParentFragment(this);
final AppInstallerInfoPreferenceController installer =
use(AppInstallerInfoPreferenceController.class);
installer.setPackageName(packageName);
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 6b2fb91..c2db019 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -67,11 +67,14 @@
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 @@
* 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 @@
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 @@
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 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 @@
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 @@
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 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 @@
entries = removeDuplicateIgnoringUser(entries);
}
mEntries = entries;
+ mOriginalEntries = entries;
notifyDataSetChanged();
if (getItemCount() == 0) {
mManageApplications.mRecyclerView.setVisibility(View.GONE);
@@ -1153,6 +1185,14 @@
} 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 @@
}
}
}
+
+ /**
+ * 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 {
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
index 4bb2103..a438f09 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
@@ -22,9 +22,9 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.widget.ActionButtonPreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.ActionButtonsPreference;
/**
* This class adds two buttons: one to connect/disconnect from a device (depending on the current
@@ -35,7 +35,7 @@
private boolean mIsConnected;
private boolean mConnectButtonInitialized;
- private ActionButtonPreference mActionButtons;
+ private ActionButtonsPreference mActionButtons;
public BluetoothDetailsButtonsController(Context context, PreferenceFragmentCompat fragment,
CachedBluetoothDevice device, Lifecycle lifecycle) {
@@ -51,7 +51,8 @@
@Override
protected void init(PreferenceScreen screen) {
- mActionButtons = ((ActionButtonPreference) screen.findPreference(getPreferenceKey()))
+ mActionButtons = ((ActionButtonsPreference) screen.findPreference(
+ getPreferenceKey()))
.setButton1Text(R.string.forget)
.setButton1Icon(R.drawable.ic_settings_delete)
.setButton1OnClickListener((view) -> onForgetButtonPressed())
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
index de8902a..19339cd 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
@@ -199,20 +199,7 @@
private void onNegative() {
if (DEBUG) Log.d(TAG, "onNegative");
-
- boolean always = true;
- if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
- LocalBluetoothManager bluetoothManager = Utils.getLocalBtManager(this);
- CachedBluetoothDeviceManager cachedDeviceManager =
- bluetoothManager.getCachedDeviceManager();
- CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice);
- if (cachedDevice == null) {
- cachedDevice = cachedDeviceManager.addDevice(mDevice);
- }
- always = cachedDevice.checkAndIncreaseMessageRejectionCount();
- }
-
- sendReplyIntentToReceiver(false, always);
+ sendReplyIntentToReceiver(false, true);
}
private void sendReplyIntentToReceiver(final boolean allowed, final boolean always) {
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 0a26b79..b350778 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -24,7 +24,7 @@
public static final String DYNAMIC_HOMEPAGE = "settings_dynamic_homepage";
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
- public static final String DATA_USAGE_V2 = "settings_data_usage_v2";
public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization";
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
+ public static final String WIFI_SHARING = "settings_wifi_sharing";
}
diff --git a/src/com/android/settings/core/PreferenceXmlParserUtils.java b/src/com/android/settings/core/PreferenceXmlParserUtils.java
index 9fdeeef..ce5c505 100644
--- a/src/com/android/settings/core/PreferenceXmlParserUtils.java
+++ b/src/com/android/settings/core/PreferenceXmlParserUtils.java
@@ -55,6 +55,8 @@
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 @@
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 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 @@
// 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 @@
}
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 @@
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 @@
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;
}
}
diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
index 8b5d521..2f447d4 100644
--- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
+++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
@@ -28,6 +28,7 @@
import com.android.settings.development.DevelopmentSettingsDashboardFragment;
import com.android.settings.deviceinfo.StorageDashboardFragment;
import com.android.settings.display.NightDisplaySettings;
+import com.android.settings.enterprise.EnterprisePrivacySettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.gestures.GestureSettings;
import com.android.settings.homepage.TopLevelSettings;
@@ -107,6 +108,8 @@
CategoryKey.CATEGORY_NIGHT_DISPLAY);
PARENT_TO_CATEGORY_KEY_MAP.put(PrivacyDashboardFragment.class.getName(),
CategoryKey.CATEGORY_PRIVACY);
+ PARENT_TO_CATEGORY_KEY_MAP.put(EnterprisePrivacySettings.class.getName(),
+ CategoryKey.CATEGORY_ENTERPRISE_PRIVACY);
CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size());
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 78aa6c2..b6c95dd 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
@@ -22,13 +22,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.net.INetworkStatsSession;
-import android.net.NetworkPolicy;
-import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.net.TrafficStats;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
@@ -51,11 +46,13 @@
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.net.ChartData;
-import com.android.settingslib.net.ChartDataLoaderCompat;
+import com.android.settingslib.net.NetworkCycleDataForUid;
+import com.android.settingslib.net.NetworkCycleDataForUidLoader;
import com.android.settingslib.net.UidDetail;
import com.android.settingslib.net.UidDetailProvider;
+import java.util.List;
+
public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceChangeListener,
DataSaverBackend.Listener {
@@ -73,7 +70,7 @@
private static final String KEY_CYCLE = "cycle";
private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
- private static final int LOADER_CHART_DATA = 2;
+ private static final int LOADER_APP_USAGE_DATA = 2;
private static final int LOADER_APP_PREF = 3;
private PackageManager mPackageManager;
@@ -88,14 +85,10 @@
private Drawable mIcon;
private CharSequence mLabel;
private String mPackageName;
- private INetworkStatsSession mStatsSession;
private CycleAdapter mCycleAdapter;
- private long mStart;
- private long mEnd;
- private ChartData mChartData;
+ private List<NetworkCycleDataForUid> mUsageData;
private NetworkTemplate mTemplate;
- private NetworkPolicy mPolicy;
private AppItem mAppItem;
private Intent mAppSettingsIntent;
private SpinnerPreference mCycle;
@@ -108,12 +101,6 @@
mPackageManager = getPackageManager();
final Bundle args = getArguments();
- try {
- mStatsSession = services.mStatsService.openSession();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
-
mAppItem = (args != null) ? (AppItem) args.getParcelable(ARG_APP_ITEM) : null;
mTemplate = (args != null) ? (NetworkTemplate) args.getParcelable(ARG_NETWORK_TEMPLATE)
: null;
@@ -210,20 +197,13 @@
}
@Override
- public void onDestroy() {
- TrafficStats.closeQuietly(mStatsSession);
- super.onDestroy();
- }
-
- @Override
public void onResume() {
super.onResume();
if (mDataSaverBackend != null) {
mDataSaverBackend.addListener(this);
}
- mPolicy = services.mPolicyEditor.getPolicy(mTemplate);
- LoaderManager.getInstance(this).restartLoader(LOADER_CHART_DATA,
- ChartDataLoaderCompat.buildArgs(mTemplate, mAppItem), mChartDataCallbacks);
+ LoaderManager.getInstance(this).restartLoader(LOADER_APP_USAGE_DATA, null /* args */,
+ mUidDataCallbacks);
updatePrefs();
}
@@ -301,19 +281,17 @@
}
}
- private void bindData() {
+ @VisibleForTesting
+ void bindData(int position) {
final long backgroundBytes, foregroundBytes;
- if (mChartData == null || mStart == 0) {
+ if (mUsageData == null || position >= mUsageData.size()) {
backgroundBytes = foregroundBytes = 0;
mCycle.setVisible(false);
} else {
mCycle.setVisible(true);
- final long now = System.currentTimeMillis();
- NetworkStatsHistory.Entry entry = null;
- entry = mChartData.detailDefault.getValues(mStart, mEnd, now, entry);
- backgroundBytes = entry.rxBytes + entry.txBytes;
- entry = mChartData.detailForeground.getValues(mStart, mEnd, now, entry);
- foregroundBytes = entry.rxBytes + entry.txBytes;
+ final NetworkCycleDataForUid data = mUsageData.get(position);
+ backgroundBytes = data.getBackgroudUsage();
+ foregroundBytes = data.getForegroudUsage();
}
final long totalBytes = backgroundBytes + foregroundBytes;
final Context context = getContext();
@@ -377,11 +355,7 @@
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) mCycle.getSelectedItem();
-
- mStart = cycle.start;
- mEnd = cycle.end;
- bindData();
+ bindData(position);
}
@Override
@@ -390,24 +364,30 @@
}
};
- private final LoaderManager.LoaderCallbacks<ChartData> mChartDataCallbacks =
- new LoaderManager.LoaderCallbacks<ChartData>() {
- @Override
- public Loader<ChartData> onCreateLoader(int id, Bundle args) {
- return new ChartDataLoaderCompat(getActivity(), mStatsSession, args);
- }
+ private final LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>> mUidDataCallbacks =
+ new LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>() {
+ @Override
+ public Loader<List<NetworkCycleDataForUid>> onCreateLoader(int id, Bundle args) {
+ return NetworkCycleDataForUidLoader.builder(getContext())
+ .setUid(mAppItem.key)
+ .setRetrieveDetail(true)
+ .setNetworkTemplate(mTemplate)
+ .setSubscriberId(mTemplate.getSubscriberId())
+ .build();
+ }
- @Override
- public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
- mChartData = data;
- mCycleAdapter.updateCycleList(mPolicy, mChartData);
- bindData();
- }
+ @Override
+ public void onLoadFinished(Loader<List<NetworkCycleDataForUid>> loader,
+ List<NetworkCycleDataForUid> data) {
+ mUsageData = data;
+ mCycleAdapter.updateCycleList(data);
+ bindData(0 /* position */);
+ }
- @Override
- public void onLoaderReset(Loader<ChartData> loader) {
- }
- };
+ @Override
+ public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
+ }
+ };
private final LoaderManager.LoaderCallbacks<ArraySet<Preference>> mAppPrefCallbacks =
new LoaderManager.LoaderCallbacks<ArraySet<Preference>>() {
diff --git a/src/com/android/settings/datausage/AppDataUsageV2.java b/src/com/android/settings/datausage/AppDataUsageV2.java
deleted file mode 100644
index 6a31726..0000000
--- a/src/com/android/settings/datausage/AppDataUsageV2.java
+++ /dev/null
@@ -1,432 +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.datausage;
-
-import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.IconDrawableFactory;
-import android.util.Log;
-import android.view.View;
-import android.widget.AdapterView;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.Loader;
-import androidx.preference.Preference;
-import androidx.preference.Preference.OnPreferenceChangeListener;
-import androidx.preference.PreferenceCategory;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.applications.AppInfoBase;
-import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.AppItem;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.net.NetworkCycleDataForUid;
-import com.android.settingslib.net.NetworkCycleDataForUidLoader;
-import com.android.settingslib.net.UidDetail;
-import com.android.settingslib.net.UidDetailProvider;
-
-import java.util.List;
-
-public class AppDataUsageV2 extends DataUsageBaseFragment implements OnPreferenceChangeListener,
- DataSaverBackend.Listener {
-
- private static final String TAG = "AppDataUsageV2";
-
- public static final String ARG_APP_ITEM = "app_item";
- public static final String ARG_NETWORK_TEMPLATE = "network_template";
-
- private static final String KEY_TOTAL_USAGE = "total_usage";
- private static final String KEY_FOREGROUND_USAGE = "foreground_usage";
- private static final String KEY_BACKGROUND_USAGE = "background_usage";
- private static final String KEY_APP_SETTINGS = "app_settings";
- private static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
- private static final String KEY_APP_LIST = "app_list";
- private static final String KEY_CYCLE = "cycle";
- private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
-
- private static final int LOADER_APP_USAGE_DATA = 2;
- private static final int LOADER_APP_PREF = 3;
-
- private PackageManager mPackageManager;
- private final ArraySet<String> mPackages = new ArraySet<>();
- private Preference mTotalUsage;
- private Preference mForegroundUsage;
- private Preference mBackgroundUsage;
- private Preference mAppSettings;
- private RestrictedSwitchPreference mRestrictBackground;
- private PreferenceCategory mAppList;
-
- private Drawable mIcon;
- private CharSequence mLabel;
- private String mPackageName;
- private CycleAdapter mCycleAdapter;
-
- private List<NetworkCycleDataForUid> mUsageData;
- private NetworkTemplate mTemplate;
- private AppItem mAppItem;
- private Intent mAppSettingsIntent;
- private SpinnerPreference mCycle;
- private RestrictedSwitchPreference mUnrestrictedData;
- private DataSaverBackend mDataSaverBackend;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mPackageManager = getPackageManager();
- final Bundle args = getArguments();
-
- mAppItem = (args != null) ? (AppItem) args.getParcelable(ARG_APP_ITEM) : null;
- mTemplate = (args != null) ? (NetworkTemplate) args.getParcelable(ARG_NETWORK_TEMPLATE)
- : null;
- if (mTemplate == null) {
- Context context = getContext();
- mTemplate = DataUsageUtils.getDefaultTemplate(context,
- DataUsageUtils.getDefaultSubscriptionId(context));
- }
- if (mAppItem == null) {
- int uid = (args != null) ? args.getInt(AppInfoBase.ARG_PACKAGE_UID, -1)
- : getActivity().getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1);
- if (uid == -1) {
- // TODO: Log error.
- getActivity().finish();
- } else {
- addUid(uid);
- mAppItem = new AppItem(uid);
- mAppItem.addUid(uid);
- }
- } else {
- for (int i = 0; i < mAppItem.uids.size(); i++) {
- addUid(mAppItem.uids.keyAt(i));
- }
- }
-
- mTotalUsage = findPreference(KEY_TOTAL_USAGE);
- mForegroundUsage = findPreference(KEY_FOREGROUND_USAGE);
- mBackgroundUsage = findPreference(KEY_BACKGROUND_USAGE);
-
- mCycle = (SpinnerPreference) findPreference(KEY_CYCLE);
- mCycleAdapter = new CycleAdapter(getContext(), mCycle, mCycleListener);
-
- if (mAppItem.key > 0) {
- if (mPackages.size() != 0) {
- try {
- ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(
- mPackages.valueAt(0), 0, UserHandle.getUserId(mAppItem.key));
- mIcon = IconDrawableFactory.newInstance(getActivity()).getBadgedIcon(info);
- mLabel = info.loadLabel(mPackageManager);
- mPackageName = info.packageName;
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
- if (!UserHandle.isApp(mAppItem.key)) {
- removePreference(KEY_UNRESTRICTED_DATA);
- removePreference(KEY_RESTRICT_BACKGROUND);
- } else {
- mRestrictBackground = (RestrictedSwitchPreference) findPreference(
- KEY_RESTRICT_BACKGROUND);
- mRestrictBackground.setOnPreferenceChangeListener(this);
- mUnrestrictedData = (RestrictedSwitchPreference) findPreference(
- KEY_UNRESTRICTED_DATA);
- mUnrestrictedData.setOnPreferenceChangeListener(this);
- }
- mDataSaverBackend = new DataSaverBackend(getContext());
- mAppSettings = findPreference(KEY_APP_SETTINGS);
-
- mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
- mAppSettingsIntent.addCategory(Intent.CATEGORY_DEFAULT);
-
- PackageManager pm = getPackageManager();
- boolean matchFound = false;
- for (String packageName : mPackages) {
- mAppSettingsIntent.setPackage(packageName);
- if (pm.resolveActivity(mAppSettingsIntent, 0) != null) {
- matchFound = true;
- break;
- }
- }
- if (!matchFound) {
- removePreference(KEY_APP_SETTINGS);
- mAppSettings = null;
- }
-
- if (mPackages.size() > 1) {
- mAppList = (PreferenceCategory) findPreference(KEY_APP_LIST);
- LoaderManager.getInstance(this).restartLoader(LOADER_APP_PREF, Bundle.EMPTY,
- mAppPrefCallbacks);
- } else {
- removePreference(KEY_APP_LIST);
- }
- } else {
- final Context context = getActivity();
- UidDetail uidDetail = new UidDetailProvider(context).getUidDetail(mAppItem.key, true);
- mIcon = uidDetail.icon;
- mLabel = uidDetail.label;
- mPackageName = context.getPackageName();
-
- removePreference(KEY_UNRESTRICTED_DATA);
- removePreference(KEY_APP_SETTINGS);
- removePreference(KEY_RESTRICT_BACKGROUND);
- removePreference(KEY_APP_LIST);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mDataSaverBackend != null) {
- mDataSaverBackend.addListener(this);
- }
- LoaderManager.getInstance(this).restartLoader(LOADER_APP_USAGE_DATA, null /* args */,
- mUidDataCallbacks);
- updatePrefs();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (mDataSaverBackend != null) {
- mDataSaverBackend.remListener(this);
- }
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (preference == mRestrictBackground) {
- mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
- updatePrefs();
- return true;
- } else if (preference == mUnrestrictedData) {
- mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onPreferenceTreeClick(Preference preference) {
- if (preference == mAppSettings) {
- // TODO: target towards entire UID instead of just first package
- getActivity().startActivityAsUser(mAppSettingsIntent, new UserHandle(
- UserHandle.getUserId(mAppItem.key)));
- return true;
- }
- return super.onPreferenceTreeClick(preference);
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.app_data_usage;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @VisibleForTesting
- void updatePrefs() {
- updatePrefs(getAppRestrictBackground(), getUnrestrictData());
- }
-
- private void updatePrefs(boolean restrictBackground, boolean unrestrictData) {
- final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfMeteredDataRestricted(
- getContext(), mPackageName, UserHandle.getUserId(mAppItem.key));
- if (mRestrictBackground != null) {
- mRestrictBackground.setChecked(!restrictBackground);
- mRestrictBackground.setDisabledByAdmin(admin);
- }
- if (mUnrestrictedData != null) {
- if (restrictBackground) {
- mUnrestrictedData.setVisible(false);
- } else {
- mUnrestrictedData.setVisible(true);
- mUnrestrictedData.setChecked(unrestrictData);
- mUnrestrictedData.setDisabledByAdmin(admin);
- }
- }
- }
-
- private void addUid(int uid) {
- String[] packages = getPackageManager().getPackagesForUid(uid);
- if (packages != null) {
- for (int i = 0; i < packages.length; i++) {
- mPackages.add(packages[i]);
- }
- }
- }
-
- @VisibleForTesting
- void bindData(int position) {
- final long backgroundBytes, foregroundBytes;
- if (mUsageData == null || position >= mUsageData.size()) {
- backgroundBytes = foregroundBytes = 0;
- mCycle.setVisible(false);
- } else {
- mCycle.setVisible(true);
- final NetworkCycleDataForUid data = mUsageData.get(position);
- backgroundBytes = data.getBackgroudUsage();
- foregroundBytes = data.getForegroudUsage();
- }
- final long totalBytes = backgroundBytes + foregroundBytes;
- final Context context = getContext();
-
- mTotalUsage.setSummary(DataUsageUtils.formatDataUsage(context, totalBytes));
- mForegroundUsage.setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
- mBackgroundUsage.setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
- }
-
- private boolean getAppRestrictBackground() {
- final int uid = mAppItem.key;
- final int uidPolicy = services.mPolicyManager.getUidPolicy(uid);
- return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
- }
-
- private boolean getUnrestrictData() {
- if (mDataSaverBackend != null) {
- return mDataSaverBackend.isWhitelisted(mAppItem.key);
- }
- return false;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- String pkg = mPackages.size() != 0 ? mPackages.valueAt(0) : null;
- int uid = 0;
- if (pkg != null) {
- try {
- uid = mPackageManager.getPackageUidAsUser(pkg,
- UserHandle.getUserId(mAppItem.key));
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Skipping UID because cannot find package " + pkg);
- }
- }
-
- final boolean showInfoButton = mAppItem.key > 0;
-
- final Activity activity = getActivity();
- final Preference pref = EntityHeaderController
- .newInstance(activity, this, null /* header */)
- .setRecyclerView(getListView(), getSettingsLifecycle())
- .setUid(uid)
- .setHasAppInfoLink(showInfoButton)
- .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
- EntityHeaderController.ActionType.ACTION_NONE)
- .setIcon(mIcon)
- .setLabel(mLabel)
- .setPackageName(pkg)
- .done(activity, getPrefContext());
- getPreferenceScreen().addPreference(pref);
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.APP_DATA_USAGE;
- }
-
- private AdapterView.OnItemSelectedListener mCycleListener =
- new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- bindData(position);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // ignored
- }
- };
-
- private final LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>> mUidDataCallbacks =
- new LoaderManager.LoaderCallbacks<List<NetworkCycleDataForUid>>() {
- @Override
- public Loader<List<NetworkCycleDataForUid>> onCreateLoader(int id, Bundle args) {
- return NetworkCycleDataForUidLoader.builder(getContext())
- .setUid(mAppItem.key)
- .setRetrieveDetail(true)
- .setNetworkTemplate(mTemplate)
- .setSubscriberId(mTemplate.getSubscriberId())
- .build();
- }
-
- @Override
- public void onLoadFinished(Loader<List<NetworkCycleDataForUid>> loader,
- List<NetworkCycleDataForUid> data) {
- mUsageData = data;
- mCycleAdapter.updateCycleList(data);
- bindData(0 /* position */);
- }
-
- @Override
- public void onLoaderReset(Loader<List<NetworkCycleDataForUid>> loader) {
- }
- };
-
- private final LoaderManager.LoaderCallbacks<ArraySet<Preference>> mAppPrefCallbacks =
- new LoaderManager.LoaderCallbacks<ArraySet<Preference>>() {
- @Override
- public Loader<ArraySet<Preference>> onCreateLoader(int i, Bundle bundle) {
- return new AppPrefLoader(getPrefContext(), mPackages, getPackageManager());
- }
-
- @Override
- public void onLoadFinished(Loader<ArraySet<Preference>> loader,
- ArraySet<Preference> preferences) {
- if (preferences != null && mAppList != null) {
- for (Preference preference : preferences) {
- mAppList.addPreference(preference);
- }
- }
- }
-
- @Override
- public void onLoaderReset(Loader<ArraySet<Preference>> loader) {
- }
- };
-
- @Override
- public void onDataSaverChanged(boolean isDataSaving) {
-
- }
-
- @Override
- public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) {
- if (mAppItem.uids.get(uid, false)) {
- updatePrefs(getAppRestrictBackground(), isWhitelisted);
- }
- }
-
- @Override
- public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) {
- if (mAppItem.uids.get(uid, false)) {
- updatePrefs(isBlacklisted, getUnrestrictData());
- }
- }
-}
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index a0cef3a..17f23c4 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -16,14 +16,12 @@
import android.content.Context;
import android.net.NetworkPolicy;
-import android.net.NetworkStatsHistory;
import android.net.TrafficStats;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
-import android.util.FeatureFlagUtils;
import android.util.SparseIntArray;
import androidx.annotation.VisibleForTesting;
@@ -32,7 +30,6 @@
import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.widget.UsageView;
import com.android.settingslib.net.NetworkCycleChartData;
import com.android.settingslib.net.NetworkCycleData;
@@ -51,8 +48,6 @@
private NetworkPolicy mPolicy;
private long mStart;
private long mEnd;
- @Deprecated
- private NetworkStatsHistory mNetwork;
private NetworkCycleChartData mNetworkCycleChartData;
private int mSecondaryColor;
private int mSeriesColor;
@@ -69,24 +64,14 @@
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final UsageView chart = (UsageView) holder.findViewById(R.id.data_usage);
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_V2)) {
- if (mNetworkCycleChartData == null) {
- return;
- }
- } else {
- if (mNetwork == null) {
- return;
- }
+ if (mNetworkCycleChartData == null) {
+ return;
}
final int top = getTop();
chart.clearPaths();
chart.configureGraph(toInt(mEnd - mStart), top);
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_V2)) {
- calcPoints(chart, mNetworkCycleChartData.getUsageBuckets());
- } else {
- calcPoints(chart);
- }
+ calcPoints(chart, mNetworkCycleChartData.getUsageBuckets());
chart.setBottomLabels(new CharSequence[] {
Utils.formatDateRange(getContext(), mStart, mStart),
Utils.formatDateRange(getContext(), mEnd, mEnd),
@@ -96,58 +81,12 @@
}
public int getTop() {
- long totalData = 0;
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_V2)) {
- totalData = mNetworkCycleChartData.getTotalUsage();
- } else {
- NetworkStatsHistory.Entry entry = null;
- final int start = mNetwork.getIndexBefore(mStart);
- final int end = mNetwork.getIndexAfter(mEnd);
-
- for (int i = start; i <= end; i++) {
- entry = mNetwork.getValues(i, entry);
-
- // increment by current bucket total
- totalData += entry.rxBytes + entry.txBytes;
- }
- }
- long policyMax = mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0;
+ final long totalData = mNetworkCycleChartData.getTotalUsage();
+ final long policyMax =
+ mPolicy != null ? Math.max(mPolicy.limitBytes, mPolicy.warningBytes) : 0;
return (int) (Math.max(totalData, policyMax) / RESOLUTION);
}
- @Deprecated
- @VisibleForTesting
- void calcPoints(UsageView chart) {
- SparseIntArray points = new SparseIntArray();
- NetworkStatsHistory.Entry entry = null;
-
- long totalData = 0;
-
- final int start = mNetwork.getIndexAfter(mStart);
- final int end = mNetwork.getIndexAfter(mEnd);
- if (start < 0) return;
-
- points.put(0, 0);
- for (int i = start; i <= end; i++) {
- entry = mNetwork.getValues(i, entry);
-
- final long startTime = entry.bucketStart;
- final long endTime = startTime + entry.bucketDuration;
-
- // increment by current bucket total
- totalData += entry.rxBytes + entry.txBytes;
-
- if (i == 0) {
- points.put(toInt(startTime - mStart) - 1, -1);
- }
- points.put(toInt(startTime - mStart + 1), (int) (totalData / RESOLUTION));
- points.put(toInt(endTime - mStart), (int) (totalData / RESOLUTION));
- }
- if (points.size() > 1) {
- chart.addPath(points);
- }
- }
-
@VisibleForTesting
void calcPoints(UsageView chart, List<NetworkCycleData> usageSummary) {
if (usageSummary == null) {
@@ -156,9 +95,13 @@
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
@@ -220,13 +163,6 @@
notifyChanged();
}
- @Deprecated
- public void setVisibleRange(long start, long end) {
- mStart = start;
- mEnd = end;
- notifyChanged();
- }
-
public long getInspectStart() {
return mStart;
}
@@ -235,12 +171,6 @@
return mEnd;
}
- @Deprecated
- public void setNetworkStats(NetworkStatsHistory network) {
- mNetwork = network;
- notifyChanged();
- }
-
public void setNetworkCycleData(NetworkCycleChartData data) {
mNetworkCycleChartData = data;
mStart = data.getStartTime();
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index 24192cd..326b0d4 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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
@@ -15,20 +15,22 @@
package com.android.settings.datausage;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
+import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
+import android.app.Activity;
import android.app.ActivityManager;
+import android.app.usage.NetworkStats;
+import android.app.usage.NetworkStats.Bucket;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.Color;
-import android.net.INetworkStatsSession;
+import android.net.ConnectivityManager;
import android.net.NetworkPolicy;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.net.TrafficStats;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
@@ -37,6 +39,7 @@
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -58,9 +61,9 @@
import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.AppItem;
-import com.android.settingslib.net.ChartData;
-import com.android.settingslib.net.ChartDataLoaderCompat;
-import com.android.settingslib.net.SummaryForAllUidLoaderCompat;
+import com.android.settingslib.net.NetworkCycleChartDataLoader;
+import com.android.settingslib.net.NetworkCycleChartData;
+import com.android.settingslib.net.NetworkStatsSummaryLoader;
import com.android.settingslib.net.UidDetailProvider;
import java.util.ArrayList;
@@ -70,16 +73,12 @@
/**
* Panel showing data usage history across various networks, including options
* to inspect based on usage cycle and control through {@link NetworkPolicy}.
-
- * Deprecated in favor of {@link DataUsageListV2}
- *
- * @deprecated
*/
-@Deprecated
public class DataUsageList extends DataUsageBaseFragment {
- public static final String EXTRA_SUB_ID = "sub_id";
- public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+ static final String EXTRA_SUB_ID = "sub_id";
+ static final String EXTRA_NETWORK_TEMPLATE = "network_template";
+ static final String EXTRA_NETWORK_TYPE = "network_type";
private static final String TAG = "DataUsageList";
private static final boolean LOGD = false;
@@ -87,6 +86,9 @@
private static final String KEY_USAGE_AMOUNT = "usage_amount";
private static final String KEY_CHART_DATA = "chart_data";
private static final String KEY_APPS_GROUP = "apps_group";
+ private static final String KEY_TEMPLATE = "template";
+ private static final String KEY_APP = "app";
+ private static final String KEY_FIELDS = "fields";
private static final int LOADER_CHART_DATA = 2;
private static final int LOADER_SUMMARY = 3;
@@ -99,14 +101,16 @@
}
};
- private INetworkStatsSession mStatsSession;
private ChartDataUsagePreference mChart;
+ private TelephonyManager mTelephonyManager;
@VisibleForTesting
NetworkTemplate mTemplate;
@VisibleForTesting
int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private ChartData mChartData;
+ @VisibleForTesting
+ int mNetworkType;
+ private List<NetworkCycleChartData> mCycleData;
private LoadingViewController mLoadingViewController;
private UidDetailProvider mUidDetailProvider;
@@ -116,7 +120,6 @@
private PreferenceGroup mApps;
private View mHeader;
-
@Override
public int getMetricsCategory() {
return MetricsEvent.DATA_USAGE_LIST;
@@ -125,21 +128,15 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final Context context = getActivity();
+ final Activity activity = getActivity();
if (!isBandwidthControlEnabled()) {
Log.w(TAG, "No bandwidth control; leaving");
- getActivity().finish();
+ activity.finish();
}
- try {
- mStatsSession = services.mStatsService.openSession();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
-
- mUidDetailProvider = new UidDetailProvider(context);
-
+ mUidDetailProvider = new UidDetailProvider(activity);
+ mTelephonyManager = activity.getSystemService(TelephonyManager.class);
mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
mChart = (ChartDataUsagePreference) findPreference(KEY_CHART_DATA);
mApps = (PreferenceGroup) findPreference(KEY_APPS_GROUP);
@@ -193,23 +190,7 @@
public void onResume() {
super.onResume();
mDataStateListener.setListener(true, mSubId, getContext());
-
- // kick off background task to update stats
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- try {
- services.mStatsService.forceUpdate();
- } catch (RemoteException e) {
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- updateBody();
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ updateBody();
}
@Override
@@ -223,8 +204,6 @@
mUidDetailProvider.clearCache();
mUidDetailProvider = null;
- TrafficStats.closeQuietly(mStatsSession);
-
super.onDestroy();
}
@@ -243,6 +222,7 @@
if (args != null) {
mSubId = args.getInt(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mTemplate = args.getParcelable(EXTRA_NETWORK_TEMPLATE);
+ mNetworkType = args.getInt(EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_MOBILE);
}
if (mTemplate == null && mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
final Intent intent = getIntent();
@@ -253,8 +233,7 @@
}
/**
- * Update body content based on current tab. Loads
- * {@link NetworkStatsHistory} and {@link NetworkPolicy} from system, and
+ * Update body content based on current tab. Loads network cycle data from system, and
* binds them to visible controls.
*/
private void updateBody() {
@@ -266,7 +245,7 @@
// TODO: consider chaining two loaders together instead of reloading
// network history when showing app detail.
getLoaderManager().restartLoader(LOADER_CHART_DATA,
- ChartDataLoaderCompat.buildArgs(mTemplate, null), mChartDataCallbacks);
+ buildArgs(mTemplate), mNetworkCycleDataCallbacks);
// detail mode can change visible menus, invalidate
getActivity().invalidateOptionsMenu();
@@ -286,6 +265,14 @@
mChart.setColors(seriesColor, secondaryColor);
}
+ private Bundle buildArgs(NetworkTemplate template) {
+ final Bundle args = new Bundle();
+ args.putParcelable(KEY_TEMPLATE, template);
+ args.putParcelable(KEY_APP, null);
+ args.putInt(KEY_FIELDS, FIELD_RX_BYTES | FIELD_TX_BYTES);
+ return args;
+ }
+
/**
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
* current {@link #mTemplate}.
@@ -305,7 +292,7 @@
}
// generate cycle list based on policy and available history
- if (mCycleAdapter.updateCycleList(policy, mChartData)) {
+ if (mCycleAdapter.updateCycleList(mCycleData)) {
updateDetailData();
}
}
@@ -318,23 +305,13 @@
private void updateDetailData() {
if (LOGD) Log.d(TAG, "updateDetailData()");
- final long start = mChart.getInspectStart();
- final long end = mChart.getInspectEnd();
- final long now = System.currentTimeMillis();
-
- final Context context = getActivity();
-
- NetworkStatsHistory.Entry entry = null;
- if (mChartData != null) {
- entry = mChartData.network.getValues(start, end, now, null);
- }
-
// kick off loader for detailed stats
- getLoaderManager().restartLoader(LOADER_SUMMARY,
- SummaryForAllUidLoaderCompat.buildArgs(mTemplate, start, end), mSummaryCallbacks);
+ getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
+ mNetworkStatsDetailCallbacks);
- final long totalBytes = entry != null ? entry.rxBytes + entry.txBytes : 0;
- final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(context, totalBytes);
+ final long totalBytes = mCycleData != null
+ ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
+ final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
}
@@ -342,22 +319,26 @@
* Bind the given {@link NetworkStats}, or {@code null} to clear list.
*/
private void bindStats(NetworkStats stats, int[] restrictedUids) {
- ArrayList<AppItem> items = new ArrayList<>();
+ mApps.removeAll();
+ if (stats == null) {
+ if (LOGD) {
+ Log.d(TAG, "No network stats data. App list cleared.");
+ }
+ return;
+ }
+
+ final ArrayList<AppItem> items = new ArrayList<>();
long largest = 0;
final int currentUserId = ActivityManager.getCurrentUser();
- UserManager userManager = UserManager.get(getContext());
+ final UserManager userManager = UserManager.get(getContext());
final List<UserHandle> profiles = userManager.getUserProfiles();
final SparseArray<AppItem> knownItems = new SparseArray<AppItem>();
- NetworkStats.Entry entry = null;
- final int size = stats != null ? stats.size() : 0;
- for (int i = 0; i < size; i++) {
- entry = stats.getValues(i, entry);
-
+ final Bucket bucket = new Bucket();
+ while (stats.hasNextBucket() && stats.getNextBucket(bucket)) {
// Decide how to collapse items together
- final int uid = entry.uid;
-
+ final int uid = bucket.getUid();
final int collapseKey;
final int category;
final int userId = UserHandle.getUserId(uid);
@@ -366,8 +347,8 @@
if (userId != currentUserId) {
// Add to a managed user item.
final int managedKey = UidDetailProvider.buildKeyForUser(userId);
- largest = accumulate(managedKey, knownItems, entry, AppItem.CATEGORY_USER,
- items, largest);
+ largest = accumulate(managedKey, knownItems, bucket,
+ AppItem.CATEGORY_USER, items, largest);
}
// Add to app item.
collapseKey = uid;
@@ -391,8 +372,9 @@
collapseKey = android.os.Process.SYSTEM_UID;
category = AppItem.CATEGORY_APP;
}
- largest = accumulate(collapseKey, knownItems, entry, category, items, largest);
+ largest = accumulate(collapseKey, knownItems, bucket, category, items, largest);
}
+ stats.close();
final int restrictedUidsMax = restrictedUids.length;
for (int i = 0; i < restrictedUidsMax; ++i) {
@@ -413,7 +395,6 @@
}
Collections.sort(items);
- mApps.removeAll();
for (int i = 0; i < items.size(); i++) {
final int percentTotal = largest != 0 ? (int) (items.get(i).total * 100 / largest) : 0;
AppDataUsagePreference preference = new AppDataUsagePreference(getContext(),
@@ -450,12 +431,12 @@
*
* @param collapseKey the collapse key used to map the item.
* @param knownItems collection of known (already existing) items.
- * @param entry the network stats entry to extract data usage from.
+ * @param bucket the network stats bucket to extract data usage from.
* @param itemCategory the item is categorized on the list view by this category. Must be
*/
- private long accumulate(int collapseKey, final SparseArray<AppItem> knownItems,
- NetworkStats.Entry entry, int itemCategory, ArrayList<AppItem> items, long largest) {
- final int uid = entry.uid;
+ private static long accumulate(int collapseKey, final SparseArray<AppItem> knownItems,
+ Bucket bucket, int itemCategory, ArrayList<AppItem> items, long largest) {
+ final int uid = bucket.getUid();
AppItem item = knownItems.get(collapseKey);
if (item == null) {
item = new AppItem(collapseKey);
@@ -464,7 +445,7 @@
knownItems.put(item.key, item);
}
item.addUid(uid);
- item.total += entry.rxBytes + entry.txBytes;
+ item.total += bucket.getRxBytes() + bucket.getTxBytes();
return Math.max(largest, item.total);
}
@@ -481,7 +462,7 @@
// update chart to show selected cycle, and update detail data
// to match updated sweep bounds.
- mChart.setVisibleRange(cycle.start, cycle.end);
+ mChart.setNetworkCycleData(mCycleData.get(position));
updateDetailData();
}
@@ -492,35 +473,41 @@
}
};
- private final LoaderCallbacks<ChartData> mChartDataCallbacks = new LoaderCallbacks<
- ChartData>() {
+ private final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
+ new LoaderCallbacks<List<NetworkCycleChartData>>() {
@Override
- public Loader<ChartData> onCreateLoader(int id, Bundle args) {
- return new ChartDataLoaderCompat(getActivity(), mStatsSession, args);
+ public Loader<List<NetworkCycleChartData>> onCreateLoader(int id, Bundle args) {
+ return NetworkCycleChartDataLoader.builder(getContext())
+ .setNetworkTemplate(mTemplate)
+ .setSubscriberId(mTelephonyManager.getSubscriberId(mSubId))
+ .build();
}
@Override
- public void onLoadFinished(Loader<ChartData> loader, ChartData data) {
+ public void onLoadFinished(Loader<List<NetworkCycleChartData>> loader,
+ List<NetworkCycleChartData> data) {
mLoadingViewController.showContent(false /* animate */);
- mChartData = data;
- mChart.setNetworkStats(mChartData.network);
-
+ mCycleData = data;
// calculate policy cycles based on available data
updatePolicy();
}
@Override
- public void onLoaderReset(Loader<ChartData> loader) {
- mChartData = null;
- mChart.setNetworkStats(null);
+ public void onLoaderReset(Loader<List<NetworkCycleChartData>> loader) {
+ mCycleData = null;
}
};
- private final LoaderCallbacks<NetworkStats> mSummaryCallbacks = new LoaderCallbacks<
- NetworkStats>() {
+ private final LoaderCallbacks<NetworkStats> mNetworkStatsDetailCallbacks =
+ new LoaderCallbacks<NetworkStats>() {
@Override
public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
- return new SummaryForAllUidLoaderCompat(getActivity(), mStatsSession, args);
+ return new NetworkStatsSummaryLoader.Builder(getContext())
+ .setStartTime(mChart.getInspectStart())
+ .setEndTime(mChart.getInspectEnd())
+ .setNetworkType(mNetworkType)
+ .setSubscriberId(mTelephonyManager.getSubscriberId(mSubId))
+ .build();
}
@Override
diff --git a/src/com/android/settings/datausage/DataUsageListV2.java b/src/com/android/settings/datausage/DataUsageListV2.java
deleted file mode 100644
index 3a71935..0000000
--- a/src/com/android/settings/datausage/DataUsageListV2.java
+++ /dev/null
@@ -1,527 +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.datausage;
-
-import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.usage.NetworkStats;
-import android.app.usage.NetworkStats.Bucket;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.UserInfo;
-import android.graphics.Color;
-import android.net.ConnectivityManager;
-import android.net.NetworkPolicy;
-import android.net.NetworkTemplate;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ImageView;
-import android.widget.Spinner;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.loader.app.LoaderManager.LoaderCallbacks;
-import androidx.loader.content.Loader;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
-import com.android.settings.widget.LoadingViewController;
-import com.android.settingslib.AppItem;
-import com.android.settingslib.net.ChartDataLoaderCompat;
-import com.android.settingslib.net.NetworkCycleChartDataLoader;
-import com.android.settingslib.net.NetworkCycleChartData;
-import com.android.settingslib.net.NetworkStatsSummaryLoader;
-import com.android.settingslib.net.UidDetailProvider;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Panel showing data usage history across various networks, including options
- * to inspect based on usage cycle and control through {@link NetworkPolicy}.
- */
-public class DataUsageListV2 extends DataUsageBaseFragment {
-
- static final String EXTRA_SUB_ID = "sub_id";
- static final String EXTRA_NETWORK_TEMPLATE = "network_template";
- static final String EXTRA_NETWORK_TYPE = "network_type";
-
- private static final String TAG = "DataUsageListV2";
- private static final boolean LOGD = false;
-
- private static final String KEY_USAGE_AMOUNT = "usage_amount";
- private static final String KEY_CHART_DATA = "chart_data";
- private static final String KEY_APPS_GROUP = "apps_group";
-
- private static final int LOADER_CHART_DATA = 2;
- private static final int LOADER_SUMMARY = 3;
-
- private final CellDataPreference.DataStateListener mDataStateListener =
- new CellDataPreference.DataStateListener() {
- @Override
- public void onChange(boolean selfChange) {
- updatePolicy();
- }
- };
-
- private ChartDataUsagePreference mChart;
- private TelephonyManager mTelephonyManager;
-
- @VisibleForTesting
- NetworkTemplate mTemplate;
- @VisibleForTesting
- int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- @VisibleForTesting
- int mNetworkType;
- private List<NetworkCycleChartData> mCycleData;
-
- private LoadingViewController mLoadingViewController;
- private UidDetailProvider mUidDetailProvider;
- private CycleAdapter mCycleAdapter;
- private Spinner mCycleSpinner;
- private Preference mUsageAmount;
- private PreferenceGroup mApps;
- private View mHeader;
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.DATA_USAGE_LIST;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final Activity activity = getActivity();
-
- if (!isBandwidthControlEnabled()) {
- Log.w(TAG, "No bandwidth control; leaving");
- activity.finish();
- }
-
- mUidDetailProvider = new UidDetailProvider(activity);
- mTelephonyManager = activity.getSystemService(TelephonyManager.class);
- mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
- mChart = (ChartDataUsagePreference) findPreference(KEY_CHART_DATA);
- mApps = (PreferenceGroup) findPreference(KEY_APPS_GROUP);
- processArgument();
- }
-
- @Override
- public void onViewCreated(View v, Bundle savedInstanceState) {
- super.onViewCreated(v, savedInstanceState);
-
- mHeader = setPinnedHeaderView(R.layout.apps_filter_spinner);
- mHeader.findViewById(R.id.filter_settings).setOnClickListener(btn -> {
- final Bundle args = new Bundle();
- args.putParcelable(DataUsageListV2.EXTRA_NETWORK_TEMPLATE, mTemplate);
- new SubSettingLauncher(getContext())
- .setDestination(BillingCycleSettings.class.getName())
- .setTitleRes(R.string.billing_cycle)
- .setSourceMetricsCategory(getMetricsCategory())
- .setArguments(args)
- .launch();
- });
- mCycleSpinner = mHeader.findViewById(R.id.filter_spinner);
- mCycleAdapter = new CycleAdapter(mCycleSpinner.getContext(), new SpinnerInterface() {
- @Override
- public void setAdapter(CycleAdapter cycleAdapter) {
- mCycleSpinner.setAdapter(cycleAdapter);
- }
-
- @Override
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mCycleSpinner.setOnItemSelectedListener(listener);
- }
-
- @Override
- public Object getSelectedItem() {
- return mCycleSpinner.getSelectedItem();
- }
-
- @Override
- public void setSelection(int position) {
- mCycleSpinner.setSelection(position);
- }
- }, mCycleListener);
-
- mLoadingViewController = new LoadingViewController(
- getView().findViewById(R.id.loading_container), getListView());
- mLoadingViewController.showLoadingViewDelayed();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mDataStateListener.setListener(true, mSubId, getContext());
- updateBody();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mDataStateListener.setListener(false, mSubId, getContext());
- }
-
- @Override
- public void onDestroy() {
- mUidDetailProvider.clearCache();
- mUidDetailProvider = null;
-
- super.onDestroy();
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.data_usage_list;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- void processArgument() {
- final Bundle args = getArguments();
- if (args != null) {
- mSubId = args.getInt(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- mTemplate = args.getParcelable(EXTRA_NETWORK_TEMPLATE);
- mNetworkType = args.getInt(EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_MOBILE);
- }
- if (mTemplate == null && mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- final Intent intent = getIntent();
- mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- mTemplate = intent.getParcelableExtra(Settings.EXTRA_NETWORK_TEMPLATE);
- }
- }
-
- /**
- * Update body content based on current tab. Loads network cycle data from system, and
- * binds them to visible controls.
- */
- private void updateBody() {
- if (!isAdded()) return;
-
- final Context context = getActivity();
-
- // kick off loader for network history
- // TODO: consider chaining two loaders together instead of reloading
- // network history when showing app detail.
- getLoaderManager().restartLoader(LOADER_CHART_DATA,
- ChartDataLoaderCompat.buildArgs(mTemplate, null), mNetworkCycleDataCallbacks);
-
- // detail mode can change visible menus, invalidate
- getActivity().invalidateOptionsMenu();
-
- int seriesColor = context.getColor(R.color.sim_noitification);
- if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- final SubscriptionInfo sir = services.mSubscriptionManager
- .getActiveSubscriptionInfo(mSubId);
-
- if (sir != null) {
- seriesColor = sir.getIconTint();
- }
- }
-
- final int secondaryColor = Color.argb(127, Color.red(seriesColor), Color.green(seriesColor),
- Color.blue(seriesColor));
- mChart.setColors(seriesColor, secondaryColor);
- }
-
- /**
- * Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
- * current {@link #mTemplate}.
- */
- private void updatePolicy() {
- final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
- final View configureButton = mHeader.findViewById(R.id.filter_settings);
- //SUB SELECT
- if (isNetworkPolicyModifiable(policy, mSubId) && isMobileDataAvailable(mSubId)) {
- mChart.setNetworkPolicy(policy);
- configureButton.setVisibility(View.VISIBLE);
- ((ImageView) configureButton).setColorFilter(android.R.color.white);
- } else {
- // controls are disabled; don't bind warning/limit sweeps
- mChart.setNetworkPolicy(null);
- configureButton.setVisibility(View.GONE);
- }
-
- // generate cycle list based on policy and available history
- if (mCycleAdapter.updateCycleList(mCycleData)) {
- updateDetailData();
- }
- }
-
- /**
- * Update details based on {@link #mChart} inspection range depending on
- * current mode. Updates {@link #mAdapter} with sorted list
- * of applications data usage.
- */
- private void updateDetailData() {
- if (LOGD) Log.d(TAG, "updateDetailData()");
-
- // kick off loader for detailed stats
- getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
- mNetworkStatsDetailCallbacks);
-
- final long totalBytes = mCycleData != null
- ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
- final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
- mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
- }
-
- /**
- * Bind the given {@link NetworkStats}, or {@code null} to clear list.
- */
- private void bindStats(NetworkStats stats, int[] restrictedUids) {
- mApps.removeAll();
- if (stats == null) {
- if (LOGD) {
- Log.d(TAG, "No network stats data. App list cleared.");
- }
- return;
- }
-
- final ArrayList<AppItem> items = new ArrayList<>();
- long largest = 0;
-
- final int currentUserId = ActivityManager.getCurrentUser();
- final UserManager userManager = UserManager.get(getContext());
- final List<UserHandle> profiles = userManager.getUserProfiles();
- final SparseArray<AppItem> knownItems = new SparseArray<AppItem>();
-
- final Bucket bucket = new Bucket();
- while (stats.hasNextBucket() && stats.getNextBucket(bucket)) {
- // Decide how to collapse items together
- final int uid = bucket.getUid();
- final int collapseKey;
- final int category;
- final int userId = UserHandle.getUserId(uid);
- if (UserHandle.isApp(uid)) {
- if (profiles.contains(new UserHandle(userId))) {
- if (userId != currentUserId) {
- // Add to a managed user item.
- final int managedKey = UidDetailProvider.buildKeyForUser(userId);
- largest = accumulate(managedKey, knownItems, bucket,
- AppItem.CATEGORY_USER, items, largest);
- }
- // Add to app item.
- collapseKey = uid;
- category = AppItem.CATEGORY_APP;
- } else {
- // If it is a removed user add it to the removed users' key
- final UserInfo info = userManager.getUserInfo(userId);
- if (info == null) {
- collapseKey = UID_REMOVED;
- category = AppItem.CATEGORY_APP;
- } else {
- // Add to other user item.
- collapseKey = UidDetailProvider.buildKeyForUser(userId);
- category = AppItem.CATEGORY_USER;
- }
- }
- } else if (uid == UID_REMOVED || uid == UID_TETHERING) {
- collapseKey = uid;
- category = AppItem.CATEGORY_APP;
- } else {
- collapseKey = android.os.Process.SYSTEM_UID;
- category = AppItem.CATEGORY_APP;
- }
- largest = accumulate(collapseKey, knownItems, bucket, category, items, largest);
- }
- stats.close();
-
- final int restrictedUidsMax = restrictedUids.length;
- for (int i = 0; i < restrictedUidsMax; ++i) {
- final int uid = restrictedUids[i];
- // Only splice in restricted state for current user or managed users
- if (!profiles.contains(new UserHandle(UserHandle.getUserId(uid)))) {
- continue;
- }
-
- AppItem item = knownItems.get(uid);
- if (item == null) {
- item = new AppItem(uid);
- item.total = -1;
- items.add(item);
- knownItems.put(item.key, item);
- }
- item.restricted = true;
- }
-
- Collections.sort(items);
- for (int i = 0; i < items.size(); i++) {
- final int percentTotal = largest != 0 ? (int) (items.get(i).total * 100 / largest) : 0;
- AppDataUsagePreference preference = new AppDataUsagePreference(getContext(),
- items.get(i), percentTotal, mUidDetailProvider);
- preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- AppDataUsagePreference pref = (AppDataUsagePreference) preference;
- AppItem item = pref.getItem();
- startAppDataUsage(item);
- return true;
- }
- });
- mApps.addPreference(preference);
- }
- }
-
- private void startAppDataUsage(AppItem item) {
- final Bundle args = new Bundle();
- args.putParcelable(AppDataUsageV2.ARG_APP_ITEM, item);
- args.putParcelable(AppDataUsageV2.ARG_NETWORK_TEMPLATE, mTemplate);
-
- new SubSettingLauncher(getContext())
- .setDestination(AppDataUsageV2.class.getName())
- .setTitleRes(R.string.app_data_usage)
- .setArguments(args)
- .setSourceMetricsCategory(getMetricsCategory())
- .launch();
- }
-
- /**
- * Accumulate data usage of a network stats entry for the item mapped by the collapse key.
- * Creates the item if needed.
- *
- * @param collapseKey the collapse key used to map the item.
- * @param knownItems collection of known (already existing) items.
- * @param bucket the network stats bucket to extract data usage from.
- * @param itemCategory the item is categorized on the list view by this category. Must be
- */
- private static long accumulate(int collapseKey, final SparseArray<AppItem> knownItems,
- Bucket bucket, int itemCategory, ArrayList<AppItem> items, long largest) {
- final int uid = bucket.getUid();
- AppItem item = knownItems.get(collapseKey);
- if (item == null) {
- item = new AppItem(collapseKey);
- item.category = itemCategory;
- items.add(item);
- knownItems.put(item.key, item);
- }
- item.addUid(uid);
- item.total += bucket.getRxBytes() + bucket.getTxBytes();
- return Math.max(largest, item.total);
- }
-
- private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem)
- mCycleSpinner.getSelectedItem();
-
- if (LOGD) {
- Log.d(TAG, "showing cycle " + cycle + ", start=" + cycle.start + ", end="
- + cycle.end + "]");
- }
-
- // update chart to show selected cycle, and update detail data
- // to match updated sweep bounds.
- mChart.setNetworkCycleData(mCycleData.get(position));
-
- updateDetailData();
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // ignored
- }
- };
-
- private final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
- new LoaderCallbacks<List<NetworkCycleChartData>>() {
- @Override
- public Loader<List<NetworkCycleChartData>> onCreateLoader(int id, Bundle args) {
- return NetworkCycleChartDataLoader.builder(getContext())
- .setNetworkTemplate(mTemplate)
- .setSubscriberId(mTelephonyManager.getSubscriberId(mSubId))
- .build();
- }
-
- @Override
- public void onLoadFinished(Loader<List<NetworkCycleChartData>> loader,
- List<NetworkCycleChartData> data) {
- mLoadingViewController.showContent(false /* animate */);
- mCycleData = data;
- // calculate policy cycles based on available data
- updatePolicy();
- }
-
- @Override
- public void onLoaderReset(Loader<List<NetworkCycleChartData>> loader) {
- mCycleData = null;
- }
- };
-
- private final LoaderCallbacks<NetworkStats> mNetworkStatsDetailCallbacks =
- new LoaderCallbacks<NetworkStats>() {
- @Override
- public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
- return new NetworkStatsSummaryLoader.Builder(getContext())
- .setStartTime(mChart.getInspectStart())
- .setEndTime(mChart.getInspectEnd())
- .setNetworkType(mNetworkType)
- .setSubscriberId(mTelephonyManager.getSubscriberId(mSubId))
- .build();
- }
-
- @Override
- public void onLoadFinished(Loader<NetworkStats> loader, NetworkStats data) {
- final int[] restrictedUids = services.mPolicyManager.getUidsWithPolicy(
- POLICY_REJECT_METERED_BACKGROUND);
- bindStats(data, restrictedUids);
- updateEmptyVisible();
- }
-
- @Override
- public void onLoaderReset(Loader<NetworkStats> loader) {
- bindStats(null, new int[0]);
- updateEmptyVisible();
- }
-
- private void updateEmptyVisible() {
- if ((mApps.getPreferenceCount() != 0) !=
- (getPreferenceScreen().getPreferenceCount() != 0)) {
- if (mApps.getPreferenceCount() != 0) {
- getPreferenceScreen().addPreference(mUsageAmount);
- getPreferenceScreen().addPreference(mApps);
- } else {
- getPreferenceScreen().removeAll();
- }
- }
- }
- };
-}
diff --git a/src/com/android/settings/datausage/DataUsagePreference.java b/src/com/android/settings/datausage/DataUsagePreference.java
index aa4e646..21c0503 100644
--- a/src/com/android/settings/datausage/DataUsagePreference.java
+++ b/src/com/android/settings/datausage/DataUsagePreference.java
@@ -21,7 +21,6 @@
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.FeatureFlagUtils;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.TypedArrayUtils;
@@ -29,7 +28,6 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.net.DataUsageController;
@@ -78,23 +76,14 @@
public Intent getIntent() {
final Bundle args = new Bundle();
final SubSettingLauncher launcher;
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DATA_USAGE_V2)) {
- args.putParcelable(DataUsageListV2.EXTRA_NETWORK_TEMPLATE, mTemplate);
- args.putInt(DataUsageListV2.EXTRA_SUB_ID, mSubId);
- args.putInt(DataUsageListV2.EXTRA_NETWORK_TYPE, mTemplate.isMatchRuleMobile()
- ? ConnectivityManager.TYPE_MOBILE : ConnectivityManager.TYPE_WIFI);
- launcher = new SubSettingLauncher(getContext())
- .setArguments(args)
- .setDestination(DataUsageListV2.class.getName())
- .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN);
- } else {
- args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
- args.putInt(DataUsageList.EXTRA_SUB_ID, mSubId);
- launcher = new SubSettingLauncher(getContext())
- .setArguments(args)
- .setDestination(DataUsageList.class.getName())
- .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN);
- }
+ args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
+ args.putInt(DataUsageList.EXTRA_SUB_ID, mSubId);
+ args.putInt(DataUsageList.EXTRA_NETWORK_TYPE, mTemplate.isMatchRuleMobile()
+ ? ConnectivityManager.TYPE_MOBILE : ConnectivityManager.TYPE_WIFI);
+ launcher = new SubSettingLauncher(getContext())
+ .setArguments(args)
+ .setDestination(DataUsageList.class.getName())
+ .setSourceMetricsCategory(MetricsProto.MetricsEvent.VIEW_UNKNOWN);
if (mTemplate.isMatchRuleMobile()) {
launcher.setTitleRes(R.string.app_cellular_data_usage);
} else {
diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java
index 53565ac..b3d0e61 100644
--- a/src/com/android/settings/datausage/DataUsageUtils.java
+++ b/src/com/android/settings/datausage/DataUsageUtils.java
@@ -22,12 +22,8 @@
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
import android.net.NetworkTemplate;
-import android.net.TrafficStats;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -35,11 +31,8 @@
import android.text.BidiFormatter;
import android.text.format.Formatter;
import android.text.format.Formatter.BytesResult;
-import android.util.FeatureFlagUtils;
import android.util.Log;
-import com.android.settings.core.FeatureFlags;
-
import java.util.List;
/**
@@ -78,44 +71,21 @@
return false;
}
- if (FeatureFlagUtils.isEnabled(context, FeatureFlags.DATA_USAGE_V2)) {
- final TelephonyManager telephonyManager = TelephonyManager.from(context);;
- final NetworkStatsManager networkStatsManager =
- context.getSystemService(NetworkStatsManager.class);
- boolean hasEthernetUsage = false;
- try {
- final Bucket bucket = networkStatsManager.querySummaryForUser(
- ConnectivityManager.TYPE_ETHERNET, telephonyManager.getSubscriberId(),
- 0L /* startTime */, System.currentTimeMillis() /* endTime */);
- if (bucket != null) {
- hasEthernetUsage = bucket.getRxBytes() > 0 || bucket.getTxBytes() > 0;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception querying network detail.", e);
+ final TelephonyManager telephonyManager = TelephonyManager.from(context);;
+ final NetworkStatsManager networkStatsManager =
+ context.getSystemService(NetworkStatsManager.class);
+ boolean hasEthernetUsage = false;
+ try {
+ final Bucket bucket = networkStatsManager.querySummaryForUser(
+ ConnectivityManager.TYPE_ETHERNET, telephonyManager.getSubscriberId(),
+ 0L /* startTime */, System.currentTimeMillis() /* endTime */);
+ if (bucket != null) {
+ hasEthernetUsage = bucket.getRxBytes() > 0 || bucket.getTxBytes() > 0;
}
- return hasEthernetUsage;
- } else {
- final long ethernetBytes;
- try {
- INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
-
- INetworkStatsSession statsSession = statsService.openSession();
- if (statsSession != null) {
- ethernetBytes = statsSession.getSummaryForNetwork(
- NetworkTemplate.buildTemplateEthernet(), Long.MIN_VALUE, Long.MAX_VALUE)
- .getTotalBytes();
- TrafficStats.closeQuietly(statsSession);
- } else {
- ethernetBytes = 0;
- }
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
-
- // only show ethernet when both hardware present and traffic has occurred
- return ethernetBytes > 0;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying network detail.", e);
}
+ return hasEthernetUsage;
}
/**
diff --git a/src/com/android/settings/development/AngleEnabledAppPreferenceController.java b/src/com/android/settings/development/AngleEnabledAppPreferenceController.java
deleted file mode 100644
index 3a7f6bf..0000000
--- a/src/com/android/settings/development/AngleEnabledAppPreferenceController.java
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
index 0fcec05..95e663b 100644
--- a/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothA2dpHwOffloadPreferenceController.java
@@ -66,6 +66,25 @@
}
}
+ @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);
diff --git a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
index 3532a15..e65d2ad 100644
--- a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
+++ b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java
@@ -26,7 +26,11 @@
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;
}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 762686a..aa9918c 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -221,7 +221,16 @@
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 @@
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 @@
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));
diff --git a/src/com/android/settings/development/DisableDevSettingsDialogFragment.java b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
new file mode 100644
index 0000000..9b3ba58
--- /dev/null
+++ b/src/com/android/settings/development/DisableDevSettingsDialogFragment.java
@@ -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();
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java b/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java
index ce425c6..00a79a0 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuController.java
@@ -67,7 +67,8 @@
if (migrate != null) {
migrate.setVisible((privateVol != null)
&& (privateVol.getType() == VolumeInfo.TYPE_PRIVATE)
- && !Objects.equals(mVolumeInfo, privateVol));
+ && !Objects.equals(mVolumeInfo, privateVol)
+ && privateVol.isMountedWritable());
}
}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index 1812974..f516926 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -416,7 +416,8 @@
.getPrimaryStorageCurrentVolume();
migrate.setVisible((privateVol != null)
&& (privateVol.getType() == VolumeInfo.TYPE_PRIVATE)
- && !Objects.equals(mVolume, privateVol));
+ && !Objects.equals(mVolume, privateVol)
+ && privateVol.isMountedWritable());
}
@Override
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 4679436..5d6a412 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -14,11 +14,7 @@
package com.android.settings.display;
import android.content.Context;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
+import android.hardware.display.ColorDisplayManager;
import androidx.annotation.VisibleForTesting;
@@ -29,19 +25,16 @@
public class ColorModePreferenceController extends BasePreferenceController {
private static final String TAG = "ColorModePreference";
- private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT = 1030;
-
- private final ConfigurationWrapper mConfigWrapper;
private ColorDisplayController mColorDisplayController;
public ColorModePreferenceController(Context context, String key) {
super(context, key);
- mConfigWrapper = new ConfigurationWrapper();
}
@Override
public int getAvailabilityStatus() {
- return mConfigWrapper.isDeviceColorManaged()
+ return mContext.getSystemService(ColorDisplayManager.class)
+ .isDeviceColorManaged()
&& !getColorDisplayController().getAccessibilityTransformActivated() ?
AVAILABLE_UNSEARCHABLE : DISABLED_FOR_USER;
}
@@ -68,32 +61,4 @@
}
return mColorDisplayController;
}
-
- @VisibleForTesting
- static class ConfigurationWrapper {
- private final IBinder mSurfaceFlinger;
-
- ConfigurationWrapper() {
- mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
- }
-
- boolean isDeviceColorManaged() {
- if (mSurfaceFlinger != null) {
- final Parcel data = Parcel.obtain();
- final Parcel reply = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- try {
- mSurfaceFlinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGEMENT,
- data, reply, 0);
- return reply.readBoolean();
- } catch (RemoteException ex) {
- Log.e(TAG, "Failed to query color management support", ex);
- } finally {
- data.recycle();
- reply.recycle();
- }
- }
- return false;
- }
- }
}
diff --git a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
index 8ad5e63..1710f51 100644
--- a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.display;
import android.content.Context;
-
import android.hardware.display.ColorDisplayManager;
import androidx.preference.DropDownPreference;
diff --git a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java b/src/com/android/settings/flashlight/FlashlightSlice.java
similarity index 66%
rename from src/com/android/settings/flashlight/FlashlightSliceBuilder.java
rename to src/com/android/settings/flashlight/FlashlightSlice.java
index 5833229..a2c4561 100644
--- a/src/com/android/settings/flashlight/FlashlightSliceBuilder.java
+++ b/src/com/android/settings/flashlight/FlashlightSlice.java
@@ -28,6 +28,7 @@
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 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 @@
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(
diff --git a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
index 2e9b5a5..00b7a0c 100644
--- a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
+++ b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
@@ -52,7 +52,7 @@
for (AbstractPreferenceController controller : mGestureControllers) {
isAvailable = isAvailable || controller.isAvailable();
}
- return isAvailable ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
+ return isAvailable ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
/**
@@ -101,4 +101,4 @@
}
return mContext.getText(R.string.language_input_gesture_summary_off);
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index e437e2b..32a86e8 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -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.slice.widget.EventInfo;
import com.android.settings.R;
+import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import java.util.List;
@@ -38,10 +41,6 @@
// 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 @@
// 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 @@
@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 @@
}
@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 @@
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 @@
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();
+ }
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 3ef4653..e631d22 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -20,6 +20,9 @@
import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
+import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_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.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 @@
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 @@
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(BLUETOOTH_DEVICES_SLICE_URI))
.count();
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 5f397d7..28ad0d3 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -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.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 @@
private final List<LifecycleObserver> mLifecycleObservers;
private ContextualCardUpdateListener mListener;
+ private long mStartTime;
public ContextualCardManager(Context context, Lifecycle lifecycle) {
mContext = context;
@@ -86,6 +87,7 @@
}
void loadContextualCards(ContextualCardsFragment fragment) {
+ mStartTime = System.currentTimeMillis();
final CardContentLoaderCallbacks cardContentLoaderCallbacks =
new CardContentLoaderCallbacks(mContext);
cardContentLoaderCallbacks.setListener(this);
@@ -168,6 +170,10 @@
@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() {
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index 376bb83..d5500fb 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -40,8 +40,8 @@
.build();
final ContextualCard connectedDeviceCard =
ContextualCard.newBuilder()
- .setSliceUri(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI.toString())
- .setCardName(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI.toString())
+ .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString())
+ .setCardName(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI.toString())
.setCardCategory(ContextualCard.Category.IMPORTANT)
.build();
final ContextualCard lowStorageCard =
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
index b0d6963..5271e12 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/BatterySlice.java
@@ -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.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 @@
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 @@
@Override
public Uri getUri() {
- return BATTERY_INFO_SLICE_URI;
+ return CustomSliceRegistry.BATTERY_INFO_SLICE_URI;
}
@Override
@@ -95,7 +95,8 @@
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
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
index bb78586..6e94f6d 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/DataUsageSlice.java
@@ -94,7 +94,8 @@
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() {
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
index 694336d..1f75ab1 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/DeviceInfoSlice.java
@@ -85,7 +85,8 @@
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() {
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
index 2484e53..f8be2d6 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/EmergencyInfoSlice.java
@@ -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 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));
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java b/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
index eba831a..799a701 100644
--- a/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/deviceinfo/StorageSlice.java
@@ -80,7 +80,8 @@
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() {
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
similarity index 67%
rename from src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
rename to src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index 6a1f1f0..ad8d4a6 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -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.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.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;
@@ -56,28 +57,27 @@
import java.util.List;
import java.util.stream.Collectors;
-/**
- * TODO(b/114807655): Contextual Home Page - Connected Device
- *
- * Show connected device info if one is currently connected. UI for connected device should
- * match Connected Devices > Currently Connected Devices
- *
- * TODO This class will be refactor for Bluetooth connected devices only.
- */
-public class ConnectedDeviceSlice implements CustomSliceable {
+public class BluetoothDevicesSlice implements CustomSliceable {
/**
- * To sort the Bluetooth devices by {@link CachedBluetoothDevice}.
- * Refer compareTo method from {@link com.android.settings.bluetooth.BluetoothDevicePreference}.
+ * TODO(b/114807655): Contextual Home Page - Connected Device
+ * Re-design sorting for new rule:
+ * Sorting rule: Audio Streaming > Last connected > Recently connected.
*/
private static final Comparator<CachedBluetoothDevice> COMPARATOR
= Comparator.naturalOrder();
- private static final String TAG = "ConnectedDeviceSlice";
+ /**
+ * 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 = "BluetoothDevicesSlice";
private final Context mContext;
- public ConnectedDeviceSlice(Context context) {
+ public BluetoothDevicesSlice(Context context) {
mContext = context;
}
@@ -94,47 +94,53 @@
@Override
public Uri getUri() {
- return CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI;
+ return CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
}
@Override
public Slice getSlice() {
final IconCompat icon = IconCompat.createWithResource(mContext,
- R.drawable.ic_homepage_connected_device);
- final CharSequence title = mContext.getText(R.string.connected_devices_dashboard_title);
- final CharSequence titleNoConnectedDevices = mContext.getText(
- R.string.no_connected_devices);
+ R.drawable.ic_settings_bluetooth);
+ final CharSequence title = mContext.getText(R.string.bluetooth_devices);
+ final CharSequence titleNoBluetoothDevices = mContext.getText(
+ R.string.no_bluetooth_devices);
final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, 0,
getIntent(), 0);
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
ListBuilder.ICON_IMAGE, title);
final ListBuilder listBuilder =
- new ListBuilder(mContext, CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI,
+ new ListBuilder(mContext, CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext));
- // Get row builders by connected devices, e.g. Bluetooth.
+ // Get row builders by Bluetooth devices.
final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
- // Return a header with IsError flag, if no connected devices.
+ // Return a header with IsError flag, if no Bluetooth devices.
if (rows.isEmpty()) {
return listBuilder.setHeader(new ListBuilder.HeaderBuilder()
- .setTitle(titleNoConnectedDevices)
+ .setTitle(titleNoBluetoothDevices)
.setPrimaryAction(primarySliceAction))
.setIsError(true)
.build();
}
- // According the number of connected devices to set sub title of header.
+ // According the number of Bluetooth devices to set sub title of header.
listBuilder.setHeader(new ListBuilder.HeaderBuilder()
.setTitle(title)
.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 +153,8 @@
ConnectedDeviceDashboardFragment.class.getName(), "" /* key */,
screenTitle,
MetricsProto.MetricsEvent.SLICE)
- .setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI);
}
@Override
@@ -160,25 +167,30 @@
}
@VisibleForTesting
- List<CachedBluetoothDevice> getBluetoothConnectedDevices() {
- final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>();
+ List<CachedBluetoothDevice> getBluetoothDevices() {
+ final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();
// If Bluetooth is disable, skip to get the bluetooth devices.
if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
- Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is disabled.");
- return connectedBluetoothList;
+ Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
+ return bluetoothDeviceList;
}
// Get the Bluetooth devices from LocalBluetoothManager.
final LocalBluetoothManager bluetoothManager =
com.android.settings.bluetooth.Utils.getLocalBtManager(mContext);
if (bluetoothManager == null) {
- Log.i(TAG, "Cannot get Bluetooth connected devices, Bluetooth is unsupported.");
- return connectedBluetoothList;
+ Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is unsupported.");
+ return bluetoothDeviceList;
}
final Collection<CachedBluetoothDevice> cachedDevices =
bluetoothManager.getCachedDeviceManager().getCachedDevicesCopy();
+ /**
+ * TODO(b/114807655): Contextual Home Page - Connected Device
+ * Re-design to get all Bluetooth devices and sort them by new rule:
+ * Sorting rule: Audio Streaming > Last connected > Recently connected.
+ */
// Get connected Bluetooth devices and sort them.
return cachedDevices.stream().filter(device -> device.isConnected()).sorted(
COMPARATOR).collect(Collectors.toList());
@@ -193,7 +205,7 @@
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
@@ -203,25 +215,29 @@
}
@VisibleForTesting
- IconCompat getConnectedDeviceIcon(CachedBluetoothDevice device) {
+ IconCompat getBluetoothDeviceIcon(CachedBluetoothDevice device) {
final Pair<Drawable, String> pair = BluetoothUtils
.getBtClassDrawableWithDescription(mContext, device);
if (pair.first != null) {
return IconCompat.createWithBitmap(getBitmapFromVectorDrawable(pair.first));
} else {
- return IconCompat.createWithResource(mContext, R.drawable.ic_homepage_connected_device);
+ return IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
}
}
private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
- // According Bluetooth connected device to create row builders.
- final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothConnectedDevices();
+ /**
+ * TODO(b/114807655): Contextual Home Page - Connected Device
+ * Re-design to do action "activating" in primary action.
+ */
+ // According Bluetooth device to create row builders.
+ final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothDevices();
for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
bluetoothRows.add(new ListBuilder.RowBuilder()
- .setTitleItem(getConnectedDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
+ .setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
.setTitle(bluetoothDevice.getName())
.setSubtitle(bluetoothDevice.getConnectionSummary())
.setPrimaryAction(primarySliceAction)
@@ -240,7 +256,31 @@
}
private CharSequence getSubTitle(int deviceCount) {
- return mContext.getResources().getQuantityString(R.plurals.show_connected_devices,
+ return mContext.getResources().getQuantityString(R.plurals.show_bluetooth_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 */);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
index d893587..e0f3116 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
@@ -22,7 +22,6 @@
import android.net.Uri;
import android.os.storage.StorageManager;
import android.text.format.Formatter;
-import android.util.Log;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -45,10 +44,8 @@
public class LowStorageSlice implements CustomSliceable {
- private static final String TAG = "LowStorageSlice";
-
/**
- * If user used >= 85% storage.
+ * If used storage >= 85%, it would be low storage.
*/
private static final double LOW_STORAGE_THRESHOLD = 0.85;
@@ -60,45 +57,37 @@
@Override
public Slice getSlice() {
- // Get current storage percentage from StorageManager.
+ // Get used storage percentage from StorageManager.
final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
new StorageManagerVolumeProvider(mContext.getSystemService(StorageManager.class)));
- final double currentStoragePercentage =
- (double) (info.totalBytes - info.freeBytes) / info.totalBytes;
+ final double usedPercentage = (double) (info.totalBytes - info.freeBytes) / info.totalBytes;
- // Used storage < 85%. NOT show Low storage Slice.
- if (currentStoragePercentage < LOW_STORAGE_THRESHOLD) {
- /**
- * TODO(b/114808204): Contextual Home Page - "Low Storage"
- * The behavior is under decision making, will update new behavior or remove TODO later.
- */
- Log.i(TAG, "Not show low storage slice, not match condition.");
- return null;
+ // Generate Low storage Slice.
+ final String percentageString = NumberFormat.getPercentInstance().format(usedPercentage);
+ final String freeSizeString = Formatter.formatFileSize(mContext, info.freeBytes);
+ final ListBuilder listBuilder = new ListBuilder(mContext,
+ CustomSliceRegistry.LOW_STORAGE_SLICE_URI, ListBuilder.INFINITY).setAccentColor(
+ Utils.getColorAccentDefaultColor(mContext));
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_storage);
+
+ if (usedPercentage < LOW_STORAGE_THRESHOLD) {
+ // For clients that ignore error checking, a generic storage slice will be given.
+ final CharSequence titleStorage = mContext.getText(R.string.storage_settings);
+ final String summaryStorage = mContext.getString(R.string.storage_summary,
+ percentageString, freeSizeString);
+
+ return listBuilder
+ .addRow(buildRowBuilder(titleStorage, summaryStorage, icon))
+ .setIsError(true)
+ .build();
}
- // Show Low storage Slice.
- final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_storage);
- final CharSequence title = mContext.getText(R.string.storage_menu_free);
- final SliceAction primarySliceAction = SliceAction.createDeeplink(
- PendingIntent.getActivity(mContext, 0, getIntent(), 0), icon,
- ListBuilder.ICON_IMAGE, title);
- final String lowStorageSummary = mContext.getString(R.string.low_storage_summary,
- NumberFormat.getPercentInstance().format(currentStoragePercentage),
- Formatter.formatFileSize(mContext, info.freeBytes));
+ final CharSequence titleLowStorage = mContext.getText(R.string.storage_menu_free);
+ final String summaryLowStorage = mContext.getString(R.string.low_storage_summary,
+ percentageString, freeSizeString);
- /**
- * TODO(b/114808204): Contextual Home Page - "Low Storage"
- * Slices doesn't support "Icon on the left" in header. Now we intend to start with Icon
- * right aligned. Will update the icon to left until Slices support it.
- */
- return new ListBuilder(mContext, CustomSliceRegistry.LOW_STORAGE_SLICE_URI,
- ListBuilder.INFINITY)
- .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
- .addRow(new RowBuilder()
- .setTitle(title)
- .setSubtitle(lowStorageSummary)
- .addEndItem(icon, ListBuilder.ICON_IMAGE)
- .setPrimaryAction(primarySliceAction))
+ return listBuilder
+ .addRow(buildRowBuilder(titleLowStorage, summaryLowStorage, icon))
.build();
}
@@ -121,6 +110,24 @@
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) {
+ final SliceAction primarySliceAction = SliceAction.createDeeplink(
+ PendingIntent.getActivity(mContext, 0, getIntent(), 0), icon,
+ ListBuilder.ICON_IMAGE, title);
+
+ /**
+ * TODO(b/114808204): Contextual Home Page - "Low Storage"
+ * Slices doesn't support "Icon on the left" in header. Now we intend to start with Icon
+ * right aligned. Will update the icon to left until Slices support it.
+ */
+ return new RowBuilder()
+ .setTitle(title)
+ .setSubtitle(summary)
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setPrimaryAction(primarySliceAction);
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index 4378be3..8720a3c 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -69,9 +69,9 @@
dbHelper.markContextualCardAsDismissed(mContext, card.getName());
});
showFeedbackDialog(card);
- final ContextualCardFeatureProvider contexualCardFeatureProvider =
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
- contexualCardFeatureProvider.logContextualCardDismiss(mContext, card);
+ contextualCardFeatureProvider.logContextualCardDismiss(mContext, card);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index a2d6e2b..be03c28 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -28,8 +28,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
@@ -38,6 +41,7 @@
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;
@@ -51,13 +55,15 @@
* Card renderer for {@link ContextualCard} built as slices.
*/
public class SliceContextualCardRenderer implements ContextualCardRenderer,
- SliceView.OnSliceActionListener {
+ SliceView.OnSliceActionListener, LifecycleObserver {
public static final int VIEW_TYPE = R.layout.homepage_slice_tile;
private static final String TAG = "SliceCardRenderer";
@VisibleForTesting
- final Map<String, LiveData<Slice>> mSliceLiveDataMap;
+ final Map<Uri, LiveData<Slice>> mSliceLiveDataMap;
+ @VisibleForTesting
+ final Set<SliceViewHolder> mFlippedCardSet;
private final Context mContext;
private final LifecycleOwner mLifecycleOwner;
@@ -71,6 +77,8 @@
mSliceLiveDataMap = new ArrayMap<>();
mControllerRendererPool = controllerRendererPool;
mCardSet = new ArraySet<>();
+ mFlippedCardSet = new ArraySet<>();
+ mLifecycleOwner.getLifecycle().addObserver(this);
}
@Override
@@ -87,9 +95,9 @@
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;
@@ -99,11 +107,11 @@
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);
@@ -111,6 +119,11 @@
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);
});
@@ -122,20 +135,24 @@
}
private void initDismissalActions(SliceViewHolder cardHolder, ContextualCard card) {
- final ViewFlipper viewFlipper = cardHolder.itemView.findViewById(R.id.viewFlipper);
cardHolder.sliceView.setOnLongClickListener(v -> {
- viewFlipper.showNext();
+ cardHolder.viewFlipper.showNext();
+ mFlippedCardSet.add(cardHolder);
return true;
});
final Button btnKeep = cardHolder.itemView.findViewById(R.id.keep);
btnKeep.setOnClickListener(v -> {
- viewFlipper.showPrevious();
+ cardHolder.resetCard();
+ mFlippedCardSet.remove(cardHolder);
});
final Button btnRemove = cardHolder.itemView.findViewById(R.id.remove);
btnRemove.setOnClickListener(v -> {
mControllerRendererPool.getController(mContext, card.getCardType()).onDismissed(card);
+ cardHolder.resetCard();
+ mFlippedCardSet.remove(cardHolder);
+ mSliceLiveDataMap.get(card.getSliceUri()).removeObservers(mLifecycleOwner);
});
}
@@ -158,12 +175,24 @@
}
}
+ @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+ public void onStop() {
+ mFlippedCardSet.stream().forEach(holder -> holder.resetCard());
+ mFlippedCardSet.clear();
+ }
+
public static class SliceViewHolder extends RecyclerView.ViewHolder {
public final SliceView sliceView;
+ public final ViewFlipper viewFlipper;
public SliceViewHolder(View view) {
super(view);
sliceView = view.findViewById(R.id.slice_view);
+ viewFlipper = view.findViewById(R.id.viewFlipper);
+ }
+
+ public void resetCard() {
+ viewFlipper.setDisplayedChild(0);
}
}
}
diff --git a/src/com/android/settings/location/LocationScanningPreferenceController.java b/src/com/android/settings/location/LocationScanningPreferenceController.java
index 9d1bdc0..2c05a39 100644
--- a/src/com/android/settings/location/LocationScanningPreferenceController.java
+++ b/src/com/android/settings/location/LocationScanningPreferenceController.java
@@ -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 @@
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
diff --git a/src/com/android/settings/location/LocationSliceBuilder.java b/src/com/android/settings/location/LocationSlice.java
similarity index 66%
rename from src/com/android/settings/location/LocationSliceBuilder.java
rename to src/com/android/settings/location/LocationSlice.java
index f70d09b..6dc4241 100644
--- a/src/com/android/settings/location/LocationSliceBuilder.java
+++ b/src/com/android/settings/location/LocationSlice.java
@@ -38,29 +38,31 @@
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 @@
.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 */);
}
}
diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java
index 633fc45..a16be66 100644
--- a/src/com/android/settings/network/ApnEditor.java
+++ b/src/com/android/settings/network/ApnEditor.java
@@ -167,7 +167,7 @@
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 @@
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();
diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java
index 4bd964e..261d889 100755
--- a/src/com/android/settings/network/ApnSettings.java
+++ b/src/com/android/settings/network/ApnSettings.java
@@ -82,7 +82,7 @@
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;
diff --git a/src/com/android/settings/network/MultiNetworkHeaderController.java b/src/com/android/settings/network/MultiNetworkHeaderController.java
new file mode 100644
index 0000000..1c0fc74
--- /dev/null
+++ b/src/com/android/settings/network/MultiNetworkHeaderController.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
new file mode 100644
index 0000000..cfe27db
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/network/SubscriptionsChangeListener.java b/src/com/android/settings/network/SubscriptionsChangeListener.java
new file mode 100644
index 0000000..c3bb22b
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionsChangeListener.java
@@ -0,0 +1,97 @@
+/*
+ * 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+
+import com.android.internal.telephony.TelephonyIntents;
+
+/** Helper class for listening to changes in availability of telephony subscriptions */
+public class SubscriptionsChangeListener extends ContentObserver {
+
+ public interface SubscriptionsChangeListenerClient {
+ void onAirplaneModeChanged(boolean airplaneModeEnabled);
+ void onSubscriptionsChanged();
+ }
+
+ private Context mContext;
+ private SubscriptionsChangeListenerClient mClient;
+ private SubscriptionManager mSubscriptionManager;
+ private OnSubscriptionsChangedListener mSubscriptionsChangedListener;
+ private Uri mAirplaneModeSettingUri;
+ private BroadcastReceiver mBroadcastReceiver;
+
+ public SubscriptionsChangeListener(Context context, SubscriptionsChangeListenerClient client) {
+ super(new Handler());
+ mContext = context;
+ mClient = client;
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mSubscriptionsChangedListener = new OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ subscriptionsChangedCallback();
+ }
+ };
+ mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ subscriptionsChangedCallback();
+ }
+ };
+ }
+
+ public void start() {
+ mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionsChangedListener);
+ mContext.getContentResolver()
+ .registerContentObserver(mAirplaneModeSettingUri, false, this);
+ final IntentFilter radioTechnologyChangedFilter = new IntentFilter(
+ TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
+ mContext.registerReceiver(mBroadcastReceiver, radioTechnologyChangedFilter);
+ }
+
+ public void stop() {
+ mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangedListener);
+ mContext.getContentResolver().unregisterContentObserver(this);
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ }
+
+ public boolean isAirplaneModeOn() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
+ private void subscriptionsChangedCallback() {
+ mClient.onSubscriptionsChanged();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri.equals(mAirplaneModeSettingUri)) {
+ mClient.onAirplaneModeChanged(isAirplaneModeOn());
+ }
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index b1124f8..9ebeda0 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -22,7 +22,6 @@
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 @@
@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;
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index dc184d3..27cc367 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -230,7 +230,8 @@
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);
}
diff --git a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
index 5b4c245..d0f1ee6 100644
--- a/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModeAutomaticRulePreferenceController.java
@@ -25,7 +25,6 @@
import android.content.pm.ServiceInfo;
import android.provider.Settings;
import android.service.notification.ConditionProviderService;
-import android.service.notification.ZenModeConfig;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -34,20 +33,15 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
abstract public class AbstractZenModeAutomaticRulePreferenceController extends
AbstractZenModePreferenceController implements PreferenceControllerMixin {
protected ZenModeBackend mBackend;
protected Fragment mParent;
- protected Set<Map.Entry<String, AutomaticZenRule>> mRules;
+ protected Map.Entry<String, AutomaticZenRule>[] mRules;
protected PackageManager mPm;
- private static List<String> mDefaultRuleIds;
public AbstractZenModeAutomaticRulePreferenceController(Context context, String key, Fragment
parent, Lifecycle lifecycle) {
@@ -60,20 +54,14 @@
@Override
public void updateState(Preference preference) {
super.updateState(preference);
- mRules = getZenModeRules();
+ mRules = mBackend.getAutomaticZenRules();
}
- private static List<String> getDefaultRuleIds() {
- if (mDefaultRuleIds == null) {
- mDefaultRuleIds = ZenModeConfig.DEFAULT_RULE_IDS;
+ protected Map.Entry<String, AutomaticZenRule>[] getRules() {
+ if (mRules == null) {
+ mRules = mBackend.getAutomaticZenRules();
}
- return mDefaultRuleIds;
- }
-
- private Set<Map.Entry<String, AutomaticZenRule>> getZenModeRules() {
- Map<String, AutomaticZenRule> ruleMap =
- NotificationManager.from(mContext).getAutomaticZenRules();
- return ruleMap.entrySet();
+ return mRules;
}
protected void showNameRuleDialog(final ZenRuleInfo ri, Fragment parent) {
@@ -81,16 +69,6 @@
RuleNameChangeListener(ri));
}
- protected Map.Entry<String, AutomaticZenRule>[] sortedRules() {
- if (mRules == null) {
- mRules = getZenModeRules();
- }
- final Map.Entry<String, AutomaticZenRule>[] rt =
- mRules.toArray(new Map.Entry[mRules.size()]);
- Arrays.sort(rt, RULE_COMPARATOR);
- return rt;
- }
-
protected static Intent getRuleIntent(String settingsAction,
ComponentName configurationActivity, String ruleId) {
final Intent intent = new Intent()
@@ -104,35 +82,6 @@
return intent;
}
- private static final Comparator<Map.Entry<String, AutomaticZenRule>> RULE_COMPARATOR =
- new Comparator<Map.Entry<String, AutomaticZenRule>>() {
- @Override
- public int compare(Map.Entry<String, AutomaticZenRule> lhs,
- Map.Entry<String, AutomaticZenRule> rhs) {
- // if it's a default rule, should be at the top of automatic rules
- boolean lhsIsDefaultRule = getDefaultRuleIds().contains(lhs.getKey());
- boolean rhsIsDefaultRule = getDefaultRuleIds().contains(rhs.getKey());
- if (lhsIsDefaultRule != rhsIsDefaultRule) {
- return lhsIsDefaultRule ? -1 : 1;
- }
-
- int byDate = Long.compare(lhs.getValue().getCreationTime(),
- rhs.getValue().getCreationTime());
- if (byDate != 0) {
- return byDate;
- } else {
- return key(lhs.getValue()).compareTo(key(rhs.getValue()));
- }
- }
-
- private String key(AutomaticZenRule rule) {
- final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId())
- ? 1 : ZenModeConfig.isValidEventConditionId(rule.getConditionId())
- ? 2 : 3;
- return type + rule.getName().toString();
- }
- };
-
public static ZenRuleInfo getRuleInfo(PackageManager pm, ServiceInfo si) {
if (si == null || si.metaData == null) {
return null;
diff --git a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
index 72bb0e3..c2db773 100644
--- a/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
+++ b/src/com/android/settings/notification/ZenAutomaticRuleHeaderPreferenceController.java
@@ -136,7 +136,7 @@
MetricsProto.MetricsEvent.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
mRule.setName(ruleName);
mRule.setModified(true);
- mBackend.setZenRule(mId, mRule);
+ mBackend.updateZenRule(mId, mRule);
}
}
}
diff --git a/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java b/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java
index f38deb3..e5ca754 100644
--- a/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java
+++ b/src/com/android/settings/notification/ZenAutomaticRuleSwitchPreferenceController.java
@@ -88,6 +88,6 @@
final boolean enabled = isChecked;
if (enabled == mRule.isEnabled()) return;
mRule.setEnabled(enabled);
- mBackend.setZenRule(mId, mRule);
+ mBackend.updateZenRule(mId, mRule);
}
}
diff --git a/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java b/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
index 67d9e93..b877668 100644
--- a/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAlarmsPreferenceController.java
@@ -21,12 +21,12 @@
import android.provider.Settings;
import android.util.Log;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
public class ZenModeAlarmsPreferenceController extends
AbstractZenModePreferenceController implements Preference.OnPreferenceChangeListener {
@@ -78,6 +78,7 @@
mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_ALARMS,
allowAlarms);
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_ALARMS, allowAlarms);
+
return true;
}
}
diff --git a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
index 7679b0b..7da90c8 100644
--- a/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceController.java
@@ -28,6 +28,7 @@
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Map;
+import java.util.Objects;
public class ZenModeAutomaticRulesPreferenceController extends
AbstractZenModeAutomaticRulePreferenceController {
@@ -62,16 +63,39 @@
@Override
public void updateState(Preference preference) {
super.updateState(preference);
+ Map.Entry<String, AutomaticZenRule>[] sortedRules = getRules();
+ final int currNumPreferences = mPreferenceCategory.getPreferenceCount();
+ if (currNumPreferences == sortedRules.length) {
+ for (int i = 0; i < sortedRules.length; i++) {
+ ZenRulePreference pref = (ZenRulePreference) mPreferenceCategory.getPreference(i);
+ // we are either:
+ // 1. updating the enabled state or name of the rule
+ // 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.updatePreference(rule);
+ } else {
+ reloadAllRules(sortedRules);
+ break;
+ }
+ }
+ } else {
+ reloadAllRules(sortedRules);
+ }
+ }
+ @VisibleForTesting
+ void reloadAllRules(Map.Entry<String, AutomaticZenRule>[] rules) {
mPreferenceCategory.removeAll();
- Map.Entry<String, AutomaticZenRule>[] sortedRules = sortedRules();
- for (Map.Entry<String, AutomaticZenRule> sortedRule : sortedRules) {
- ZenRulePreference pref = new ZenRulePreference(mPreferenceCategory.getContext(),
- sortedRule, mParent, mMetricsFeatureProvider);
+ for (Map.Entry<String, AutomaticZenRule> rule : rules) {
+ ZenRulePreference pref = createZenRulePreference(rule);
mPreferenceCategory.addPreference(pref);
}
}
+
+ @VisibleForTesting
+ ZenRulePreference createZenRulePreference(Map.Entry<String, AutomaticZenRule> rule) {
+ return new ZenRulePreference(mPreferenceCategory.getContext(),
+ rule, mParent, mMetricsFeatureProvider);
+ }
}
-
-
-
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
index 44bc5f1..c559a28 100644
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java
@@ -16,9 +16,15 @@
package com.android.settings.notification;
+import android.app.AlertDialog;
+import android.app.AutomaticZenRule;
import android.content.Context;
+import android.content.DialogInterface;
import android.provider.SearchIndexableResource;
import android.service.notification.ConditionProviderService;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import androidx.fragment.app.Fragment;
@@ -34,10 +40,14 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
@SearchIndexable
public class ZenModeAutomationSettings extends ZenModeSettingsBase {
protected final ManagedServiceSettings.Config CONFIG = getConditionProviderConfig();
+ private CharSequence[] mDeleteDialogRuleNames;
+ private String[] mDeleteDialogRuleIds;
+ private boolean[] mDeleteDialogChecked;
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
@@ -74,6 +84,52 @@
.setNoun("condition provider")
.build();
}
+ private final int DELETE_RULES = 1;
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(Menu.NONE, DELETE_RULES, Menu.NONE, R.string.zen_mode_delete_automatic_rules);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case DELETE_RULES:
+ Map.Entry<String, AutomaticZenRule>[] rules = mBackend.getAutomaticZenRules();
+ mDeleteDialogRuleNames = new CharSequence[rules.length];
+ mDeleteDialogRuleIds = new String[rules.length];
+ mDeleteDialogChecked = new boolean[rules.length];
+ for (int i = 0; i < rules.length; i++) {
+ mDeleteDialogRuleNames[i] = rules[i].getValue().getName();
+ mDeleteDialogRuleIds[i] = rules[i].getKey();
+ }
+ new AlertDialog.Builder(mContext)
+ .setTitle(R.string.zen_mode_delete_automatic_rules)
+ .setMultiChoiceItems(mDeleteDialogRuleNames, null,
+ new DialogInterface.OnMultiChoiceClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which,
+ boolean isChecked) {
+ mDeleteDialogChecked[which] = isChecked;
+ }
+ })
+ .setPositiveButton(R.string.zen_mode_schedule_delete,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ for (int i = 0; i < rules.length; i++) {
+ if (mDeleteDialogChecked[i]) {
+ mBackend.removeZenRule(mDeleteDialogRuleIds[i]);
+ }
+ }
+ }
+ }).show();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
/**
* For Search.
diff --git a/src/com/android/settings/notification/ZenModeBackend.java b/src/com/android/settings/notification/ZenModeBackend.java
index de30e5d..a75f51c 100644
--- a/src/com/android/settings/notification/ZenModeBackend.java
+++ b/src/com/android/settings/notification/ZenModeBackend.java
@@ -32,6 +32,11 @@
import com.android.settings.R;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
public class ZenModeBackend {
@VisibleForTesting
protected static final String ZEN_MODE_FROM_ANYONE = "zen_mode_from_anyone";
@@ -42,6 +47,7 @@
@VisibleForTesting
protected static final String ZEN_MODE_FROM_NONE = "zen_mode_from_none";
protected static final int SOURCE_NONE = -1;
+ private static List<String> mDefaultRuleIds;
private static ZenModeBackend sInstance;
@@ -79,7 +85,7 @@
Settings.Global.ZEN_MODE, mZenMode);
}
- protected boolean setZenRule(String id, AutomaticZenRule rule) {
+ protected boolean updateZenRule(String id, AutomaticZenRule rule) {
return NotificationManager.from(mContext).updateAutomaticZenRule(id, rule);
}
@@ -244,15 +250,17 @@
}
}
+ 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();
@@ -267,12 +275,16 @@
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;
+ }
}
}
@@ -294,13 +306,65 @@
return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId);
}
+ public NotificationManager.Policy getConsolidatedPolicy() {
+ return NotificationManager.from(mContext).getConsolidatedNotificationPolicy();
+ }
+
protected String addZenRule(AutomaticZenRule rule) {
try {
- String id = NotificationManager.from(mContext).addAutomaticZenRule(rule);
- NotificationManager.from(mContext).getAutomaticZenRule(id);
- return id;
+ return NotificationManager.from(mContext).addAutomaticZenRule(rule);
} catch (Exception e) {
return null;
}
}
+
+ protected Map.Entry<String, AutomaticZenRule>[] getAutomaticZenRules() {
+ Map<String, AutomaticZenRule> ruleMap =
+ NotificationManager.from(mContext).getAutomaticZenRules();
+ final Map.Entry<String, AutomaticZenRule>[] rt = ruleMap.entrySet().toArray(
+ new Map.Entry[ruleMap.size()]);
+ Arrays.sort(rt, RULE_COMPARATOR);
+ return rt;
+ }
+
+ protected AutomaticZenRule getAutomaticZenRule(String id) {
+ return NotificationManager.from(mContext).getAutomaticZenRule(id);
+ }
+
+ private static List<String> getDefaultRuleIds() {
+ if (mDefaultRuleIds == null) {
+ mDefaultRuleIds = ZenModeConfig.DEFAULT_RULE_IDS;
+ }
+ return mDefaultRuleIds;
+ }
+
+ @VisibleForTesting
+ public static final Comparator<Map.Entry<String, AutomaticZenRule>> RULE_COMPARATOR =
+ new Comparator<Map.Entry<String, AutomaticZenRule>>() {
+ @Override
+ public int compare(Map.Entry<String, AutomaticZenRule> lhs,
+ Map.Entry<String, AutomaticZenRule> rhs) {
+ // if it's a default rule, should be at the top of automatic rules
+ boolean lhsIsDefaultRule = getDefaultRuleIds().contains(lhs.getKey());
+ boolean rhsIsDefaultRule = getDefaultRuleIds().contains(rhs.getKey());
+ if (lhsIsDefaultRule != rhsIsDefaultRule) {
+ return lhsIsDefaultRule ? -1 : 1;
+ }
+
+ int byDate = Long.compare(lhs.getValue().getCreationTime(),
+ rhs.getValue().getCreationTime());
+ if (byDate != 0) {
+ return byDate;
+ } else {
+ return key(lhs.getValue()).compareTo(key(rhs.getValue()));
+ }
+ }
+
+ private String key(AutomaticZenRule rule) {
+ final int type = ZenModeConfig.isValidScheduleConditionId(rule.getConditionId())
+ ? 1 : ZenModeConfig.isValidEventConditionId(rule.getConditionId())
+ ? 2 : 3;
+ return type + rule.getName().toString();
+ }
+ };
}
diff --git a/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java b/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
index 19ee809..2e41f20 100644
--- a/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeMessagesPreferenceController.java
@@ -18,11 +18,11 @@
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 @@
@Override
public void updateState(Preference preference) {
super.updateState(preference);
- // TODO: (b/111475013 - beverlyt) set messages summary
+
+ preference.setSummary(mSummaryBuilder.getMessagesSettingSummary(getPolicy()));
}
}
diff --git a/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java b/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
index 44b6c24..9872188 100644
--- a/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModePriorityCallsPreferenceController.java
@@ -21,14 +21,14 @@
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 @@
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);
diff --git a/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java b/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
index 56829a7..cfda367 100644
--- a/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceController.java
@@ -21,14 +21,14 @@
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 @@
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);
diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
index 9e5dbc3..11b8084 100644
--- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
@@ -124,7 +124,7 @@
protected void updateRule(Uri newConditionId) {
mRule.setConditionId(newConditionId);
- mBackend.setZenRule(mId, mRule);
+ mBackend.updateZenRule(mId, mRule);
}
@Override
diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
index f65a8b0..0b2e1bc 100644
--- a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
@@ -64,7 +64,6 @@
private TimePickerPreference mEnd;
private SwitchPreference mExitAtAlarm;
private AlertDialog mDayDialog;
-
private ScheduleInfo mSchedule;
@Override
@@ -186,7 +185,6 @@
final int summaryFormat = nextDay ? R.string.zen_mode_end_time_next_day_summary_format : 0;
mEnd.setSummaryFormat(summaryFormat);
}
-
@Override
protected void updateControlsInternal() {
updateDays();
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 293c429..a3f59c6 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -145,7 +145,7 @@
|| 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 @@
}
}
- 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 @@
}
} 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) {
diff --git a/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java b/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
index 6d5aac9..f69eac7 100644
--- a/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceController.java
@@ -16,16 +16,23 @@
package com.android.settings.notification;
+import android.app.NotificationManager;
import android.content.Context;
+import android.icu.text.ListFormatter;
import android.net.Uri;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
+import android.util.Log;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
public class ZenModeSettingsFooterPreferenceController extends AbstractZenModePreferenceController {
protected static final String KEY = "footer_preference";
@@ -65,6 +72,31 @@
protected String getFooterText() {
ZenModeConfig config = getZenModeConfig();
+
+ NotificationManager.Policy appliedPolicy = mBackend.getConsolidatedPolicy();
+ NotificationManager.Policy defaultPolicy = config.toNotificationPolicy();
+ final boolean usingCustomPolicy = !Objects.equals(appliedPolicy, defaultPolicy);
+
+ if (usingCustomPolicy) {
+ final List<ZenModeConfig.ZenRule> activeRules = getActiveRules(config);
+ final List<String> rulesNames = new ArrayList<>();
+ for (ZenModeConfig.ZenRule rule : activeRules) {
+ if (rule.name != null) {
+ rulesNames.add(rule.name);
+ }
+ }
+ if (rulesNames.size() > 0) {
+ String rules = ListFormatter.getInstance().format(rulesNames);
+ if (!rules.isEmpty()) {
+ return mContext.getString(R.string.zen_mode_settings_dnd_custom_settings_footer,
+ rules);
+ }
+ }
+ }
+ return getFooterUsingDefaultPolicy(config);
+ }
+
+ private String getFooterUsingDefaultPolicy(ZenModeConfig config) {
String footerText = "";
long latestEndTime = -1;
@@ -116,4 +148,18 @@
}
return footerText;
}
+
+ private List<ZenModeConfig.ZenRule> getActiveRules(ZenModeConfig config) {
+ List<ZenModeConfig.ZenRule> zenRules = new ArrayList<>();
+ if (config.manualRule != null) {
+ zenRules.add(config.manualRule);
+ }
+
+ for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
+ if (automaticRule.isAutomaticActive()) {
+ zenRules.add(automaticRule);
+ }
+ }
+ return zenRules;
+ }
}
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index 8058e6c..10b49eb 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -19,17 +19,19 @@
import android.app.AutomaticZenRule;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.service.notification.ZenModeConfig;
import android.view.View;
+import android.widget.CheckBox;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
@@ -37,11 +39,11 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.Map;
+import java.util.Objects;
public class ZenRulePreference extends TwoTargetPreference {
private static final ManagedServiceSettings.Config CONFIG =
ZenModeAutomationSettings.getConditionProviderConfig();
- final CharSequence mName;
final String mId;
boolean appExists;
final Fragment mParent;
@@ -51,16 +53,23 @@
final ZenServiceListing mServiceListing;
final PackageManager mPm;
final MetricsFeatureProvider mMetricsFeatureProvider;
+ final AutomaticZenRule mRule;
+ CharSequence mName;
+
+ private boolean mIsSystemRule;
+ private Intent mIntent;
+ private boolean mChecked;
+ private CheckBox mCheckBox;
public ZenRulePreference(Context context,
final Map.Entry<String, AutomaticZenRule> ruleEntry,
Fragment parent, MetricsFeatureProvider metricsProvider) {
super(context);
-
+ setLayoutResource(R.layout.preference_checkable_two_target);
mBackend = ZenModeBackend.getInstance(context);
mContext = context;
- final AutomaticZenRule rule = ruleEntry.getValue();
- mName = rule.getName();
+ mRule = ruleEntry.getValue();
+ mName = mRule.getName();
mId = ruleEntry.getKey();
mParent = parent;
mPm = mContext.getPackageManager();
@@ -68,65 +77,104 @@
mServiceListing.reloadApprovedServices();
mPref = this;
mMetricsFeatureProvider = metricsProvider;
-
- setAttributes(rule);
+ mChecked = mRule.isEnabled();
+ setAttributes(mRule);
+ setWidgetLayoutResource(getSecondTargetResId());
}
- @Override
protected int getSecondTargetResId() {
- if (mId != null && ZenModeConfig.DEFAULT_RULE_IDS.contains(mId)) {
- return 0;
+ if (mIntent != null) {
+ return R.layout.zen_rule_widget;
}
-
- return R.layout.zen_rule_widget;
+ return 0;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
+ View settingsWidget = view.findViewById(android.R.id.widget_frame);
+ View divider = view.findViewById(R.id.two_target_divider);
+ if (mIntent != null) {
+ divider.setVisibility(View.VISIBLE);
+ settingsWidget.setVisibility(View.VISIBLE);
+ settingsWidget.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mContext.startActivity(mIntent);
+ }
+ });
+ } else {
+ divider.setVisibility(View.GONE);
+ settingsWidget.setVisibility(View.GONE);
+ settingsWidget.setOnClickListener(null);
+ }
- View v = view.findViewById(R.id.delete_zen_rule);
- if (v != null) {
- v.setOnClickListener(mDeleteListener);
+ View checkboxContainer = view.findViewById(R.id.checkbox_container);
+ if (checkboxContainer != null) {
+ checkboxContainer.setOnClickListener(mOnCheckBoxClickListener);
+ }
+ mCheckBox = (CheckBox) view.findViewById(com.android.internal.R.id.checkbox);
+ if (mCheckBox != null) {
+ mCheckBox.setChecked(mChecked);
}
}
- private final View.OnClickListener mDeleteListener = new View.OnClickListener() {
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ 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));
+ }
+ }
+
+ @Override
+ public void onClick() {
+ 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) {
- showDeleteRuleDialog(mParent, mId, mName.toString());
+ mRule.setEnabled(!mChecked);
+ mBackend.updateZenRule(mId, mRule);
+ setChecked(mRule.isEnabled());
+ setAttributes(mRule);
}
};
- private void showDeleteRuleDialog(final Fragment parent, final String ruleId,
- final String ruleName) {
- ZenDeleteRuleDialog.show(parent, ruleName, ruleId,
- new ZenDeleteRuleDialog.PositiveClickListener() {
- @Override
- public void onOk(String id) {
- mMetricsFeatureProvider.action(mContext,
- MetricsProto.MetricsEvent.ACTION_ZEN_DELETE_RULE_OK);
- mBackend.removeZenRule(id);
- }
- });
- }
-
protected void setAttributes(AutomaticZenRule rule) {
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(
rule.getConditionId(), true);
final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.getConditionId());
- final boolean isSystemRule = isSchedule || isEvent;
+ mIsSystemRule = isSchedule || isEvent;
try {
ApplicationInfo info = mPm.getApplicationInfo(rule.getOwner().getPackageName(), 0);
- setSummary(computeRuleSummary(rule, isSystemRule, info.loadLabel(mPm)));
+ setSummary(computeRuleSummary(rule));
} catch (PackageManager.NameNotFoundException e) {
appExists = false;
return;
}
appExists = true;
- setTitle(rule.getName());
+ setTitle(mName);
setPersistent(false);
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
@@ -134,14 +182,12 @@
ServiceInfo si = mServiceListing.findService(rule.getOwner());
ComponentName settingsActivity = AbstractZenModeAutomaticRulePreferenceController.
getSettingsActivity(si);
- setIntent(AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action,
- settingsActivity, mId));
- setSelectable(settingsActivity != null || isSystemRule);
+ mIntent = AbstractZenModeAutomaticRulePreferenceController.getRuleIntent(action,
+ settingsActivity, mId);
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);
diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java
index 5b7bc32..aae42f8 100644
--- a/src/com/android/settings/panel/InternetConnectivityPanel.java
+++ b/src/com/android/settings/panel/InternetConnectivityPanel.java
@@ -47,8 +47,8 @@
}
@Override
- public String getTitle() {
- return (String) mContext.getText(R.string.internet_connectivity_panel_title);
+ public CharSequence getTitle() {
+ return mContext.getText(R.string.internet_connectivity_panel_title);
}
@Override
diff --git a/src/com/android/settings/panel/PanelFeatureProviderImpl.java b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
index 2e84078..503a5c3 100644
--- a/src/com/android/settings/panel/PanelFeatureProviderImpl.java
+++ b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
@@ -25,6 +25,8 @@
switch (panelType) {
case SettingsPanelActivity.PANEL_TYPE_WIFI:
return InternetConnectivityPanel.create(context);
+ case SettingsPanelActivity.PANEL_TYPE_VOLUME:
+ return VolumePanel.create(context);
}
throw new IllegalStateException("No matching panel for: " + panelType);
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index db1f60d..09bead4 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -54,6 +54,9 @@
// TODO (b/117804442) move to framework
public static final String PANEL_TYPE_WIFI = "wifi_panel";
+ // TODO (b/117804442) move to framework
+ public static final String PANEL_TYPE_VOLUME = "volume_panel";
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java
new file mode 100644
index 0000000..c0118d7
--- /dev/null
+++ b/src/com/android/settings/panel/VolumePanel.java
@@ -0,0 +1,64 @@
+/*
+ * 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.panel;
+
+import static com.android.settings.slices.CustomSliceRegistry.VOLUME_ALARM_URI;
+import static com.android.settings.slices.CustomSliceRegistry.VOLUME_CALL_URI;
+import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI;
+import static com.android.settings.slices.CustomSliceRegistry.VOLUME_RINGER_URI;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Settings;
+
+import com.android.settings.R;
+import java.util.ArrayList;
+import java.util.List;
+
+public class VolumePanel implements PanelContent {
+
+ private final Context mContext;
+
+ public static VolumePanel create(Context context) {
+ return new VolumePanel(context);
+ }
+
+ private VolumePanel(Context context) {
+ mContext = context.getApplicationContext();
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ return mContext.getText(R.string.volume_connectivity_panel_title);
+ }
+
+ @Override
+ public List<Uri> getSlices() {
+ final List<Uri> uris = new ArrayList<>();
+ uris.add(VOLUME_MEDIA_URI);
+ uris.add(VOLUME_CALL_URI);
+ uris.add(VOLUME_RINGER_URI);
+ uris.add(VOLUME_ALARM_URI);
+ return uris;
+ }
+
+ @Override
+ public Intent getSeeMoreIntent() {
+ return new Intent(Settings.ACTION_SOUND_SETTINGS);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index bef72b7..4a9de15 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -22,13 +22,16 @@
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.BluetoothDevicesSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
+import com.android.settings.location.LocationSlice;
import com.android.settings.wifi.WifiSlice;
import java.util.Map;
@@ -103,9 +106,12 @@
private void addSlices() {
mUriMap.put(CustomSliceRegistry.BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
mUriMap.put(CustomSliceRegistry.BATTERY_INFO_SLICE_URI, BatterySlice.class);
- mUriMap.put(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI, ConnectedDeviceSlice.class);
+ mUriMap.put(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.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);
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index f2b3299..1b8cffe 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -72,13 +72,13 @@
.build();
/**
- * Backing Uri for Connected device Slice.
+ * Backing Uri for Bluetooth devices Slice.
*/
- public static final Uri CONNECTED_DEVICE_SLICE_URI = new Uri.Builder()
+ public static final Uri BLUETOOTH_DEVICES_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
- .appendPath("connected_device")
+ .appendPath("bluetooth_devices")
.build();
/**
* Backing Uri for the Data usage Slice.
@@ -86,6 +86,7 @@
public static final Uri DATA_USAGE_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath("data_usage_card")
.build();
/**
@@ -94,6 +95,7 @@
public static final Uri DEVICE_INFO_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
.appendPath("device_info_card")
.build();
/**
@@ -102,6 +104,7 @@
public static final Uri EMERGENCY_INFO_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
.appendPath("emergency_info_card")
.build();
/**
@@ -110,6 +113,7 @@
public static final Uri ENHANCED_4G_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath("enhanced_4g_lte")
.build();
/**
@@ -145,14 +149,53 @@
public static final Uri STORAGE_SLICE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
.appendPath("storage_card")
.build();
/**
+ * Full {@link Uri} for the Alarm volume Slice.
+ */
+ public static final Uri VOLUME_ALARM_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("alarm_volume")
+ .build();
+ /**
+ * Full {@link Uri} for the Call Volume Slice.
+ */
+ public static final Uri VOLUME_CALL_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("call_volume")
+ .build();
+ /**
+ * Full {@link Uri} for the Media Volume Slice.
+ */
+ public static final Uri VOLUME_MEDIA_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("media_volume")
+ .build();
+ /**
+ * Full {@link Uri} for the Ringer volume Slice.
+ */
+ public static final Uri VOLUME_RINGER_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("ring_volume")
+ .build();
+
+ /**
* Full {@link Uri} for the Wifi Calling Slice.
*/
public static final Uri WIFI_CALLING_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
.appendPath(WifiCallingSliceHelper.PATH_WIFI_CALLING)
.build();
/**
@@ -161,6 +204,7 @@
public static final Uri WIFI_CALLING_PREFERENCE_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(WifiCallingSliceHelper.PATH_WIFI_CALLING_PREFERENCE)
.build();
/**
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 109f02e..80b7133 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -41,9 +41,6 @@
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 @@
} 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 @@
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 @@
.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);
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 2860e9a..823c729 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -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.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 @@
.getNewWifiCallingSliceHelper(context)
.handleWifiCallingPreferenceChanged(intent);
break;
- case ACTION_FLASHLIGHT_SLICE_CHANGED:
- FlashlightSliceBuilder.handleUriChange(context, intent);
- break;
case ACTION_COPY:
handleCopyAction(context, key, isPlatformSlice);
break;
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index 76eefac..d75eaa2 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -168,10 +168,11 @@
* @return {@link PendingIntent} for a non-primary {@link SliceAction}.
*/
public static PendingIntent getActionIntent(Context context, String action, SliceData data) {
- final Intent intent = new Intent(action);
- intent.setClass(context, SliceBroadcastReceiver.class);
- intent.putExtra(EXTRA_SLICE_KEY, data.getKey());
- intent.putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
+ final Intent intent = new Intent(action)
+ .setData(data.getUri())
+ .setClass(context, SliceBroadcastReceiver.class)
+ .putExtra(EXTRA_SLICE_KEY, data.getKey())
+ .putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
@@ -193,8 +194,9 @@
CharSequence summaryText = controller.getSummary();
// Priority 1 : User prefers showing the dynamic summary in slice view rather than static
- // summary.
- if (isDynamicSummaryAllowed && isValidSummary(context, summaryText)) {
+ // summary. Note it doesn't require a valid summary - so we can force some slices to have
+ // empty summaries (ex: volume).
+ if (isDynamicSummaryAllowed) {
return summaryText;
}
@@ -447,6 +449,12 @@
if (iconResource == 0) {
iconResource = R.drawable.ic_settings;
}
- return IconCompat.createWithResource(context, iconResource);
+ try {
+ return IconCompat.createWithResource(context, iconResource);
+ } catch (Exception e) {
+ Log.w(TAG, "Falling back to settings icon because there is an error getting slice icon "
+ + data.getUri(), e);
+ return IconCompat.createWithResource(context, R.drawable.ic_settings);
+ }
}
}
diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
index 01708af..d633b7a 100644
--- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
+++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java
@@ -24,7 +24,6 @@
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 @@
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 */);
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index b1a1f8f..bd85ef3 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -44,15 +44,14 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
-import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.GearPreference;
import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.widget.ActionButtonsPreference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -113,7 +112,7 @@
private SeekBarPreference mDefaultPitchPref;
private SeekBarPreference mDefaultRatePref;
- private ActionButtonPreference mActionButtons;
+ private ActionButtonsPreference mActionButtons;
private int mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
private int mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
@@ -169,7 +168,7 @@
mDefaultPitchPref = (SeekBarPreference) findPreference(KEY_DEFAULT_PITCH);
mDefaultRatePref = (SeekBarPreference) findPreference(KEY_DEFAULT_RATE);
- mActionButtons = ((ActionButtonPreference) findPreference(KEY_ACTION_BUTTONS))
+ mActionButtons = ((ActionButtonsPreference) findPreference(KEY_ACTION_BUTTONS))
.setButton1Text(R.string.tts_play)
.setButton1OnClickListener(v -> speakSampleText())
.setButton1Enabled(false)
diff --git a/src/com/android/settings/widget/ActionButtonPreference.java b/src/com/android/settings/widget/ActionButtonPreference.java
deleted file mode 100644
index a34d735..0000000
--- a/src/com/android/settings/widget/ActionButtonPreference.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2017 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.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.annotation.DrawableRes;
-import androidx.annotation.StringRes;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-
-/**
- * This preference provides a four buttons layout with Settings style.
- * It looks like below
- *
- * --------------------------------------------------
- * button1 | button2 | button3 | button4 |
- * --------------------------------------------------
- *
- * User can set title / icon / click listener for each button.
- *
- * By default, four buttons are visible.
- * However, there are two cases which button should be invisible(View.GONE).
- *
- * 1. User sets invisible for button. ex: ActionButtonPreference.setButton1Visible(false)
- * 2. User doesn't set any title or icon for button.
- *
- */
-public class ActionButtonPreference extends Preference {
-
- private final String TAG = "ActionButtonPreference";
- private final ButtonInfo mButton1Info = new ButtonInfo();
- private final ButtonInfo mButton2Info = new ButtonInfo();
- private final ButtonInfo mButton3Info = new ButtonInfo();
- private final ButtonInfo mButton4Info = new ButtonInfo();
-
- public ActionButtonPreference(Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
- public ActionButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- public ActionButtonPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public ActionButtonPreference(Context context) {
- super(context);
- init();
- }
-
- private void init() {
- setLayoutResource(R.layout.settings_action_buttons);
- setSelectable(false);
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
- holder.setDividerAllowedAbove(true);
- holder.setDividerAllowedBelow(true);
-
- mButton1Info.mButton = (Button) holder.findViewById(R.id.button1);
- mButton2Info.mButton = (Button) holder.findViewById(R.id.button2);
- mButton3Info.mButton = (Button) holder.findViewById(R.id.button3);
- mButton4Info.mButton = (Button) holder.findViewById(R.id.button4);
-
- mButton1Info.setUpButton();
- mButton2Info.setUpButton();
- mButton3Info.setUpButton();
- mButton4Info.setUpButton();
- }
-
- public ActionButtonPreference setButton1Visible(boolean isVisible) {
- if (isVisible != mButton1Info.mIsVisible) {
- mButton1Info.mIsVisible = isVisible;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton1Text(@StringRes int textResId) {
- final String newText = getContext().getString(textResId);
- if (!TextUtils.equals(newText, mButton1Info.mText)) {
- mButton1Info.mText = newText;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton1Icon(@DrawableRes int iconResId) {
- if (iconResId == 0) {
- return this;
- }
-
- final Drawable icon;
- try {
- icon = getContext().getDrawable(iconResId);
- mButton1Info.mIcon = icon;
- notifyChanged();
- } catch (Resources.NotFoundException exception) {
- Log.e(TAG, "Resource does not exist: " + iconResId);
- }
- return this;
- }
-
- public ActionButtonPreference setButton1Enabled(boolean isEnabled) {
- if (isEnabled != mButton1Info.mIsEnabled) {
- mButton1Info.mIsEnabled = isEnabled;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton1OnClickListener(View.OnClickListener listener) {
- if (listener != mButton1Info.mListener) {
- mButton1Info.mListener = listener;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton2Visible(boolean isVisible) {
- if (isVisible != mButton2Info.mIsVisible) {
- mButton2Info.mIsVisible = isVisible;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton2Text(@StringRes int textResId) {
- final String newText = getContext().getString(textResId);
- if (!TextUtils.equals(newText, mButton2Info.mText)) {
- mButton2Info.mText = newText;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton2Icon(@DrawableRes int iconResId) {
- if (iconResId == 0) {
- return this;
- }
-
- final Drawable icon;
- try {
- icon = getContext().getDrawable(iconResId);
- mButton2Info.mIcon = icon;
- notifyChanged();
- } catch (Resources.NotFoundException exception) {
- Log.e(TAG, "Resource does not exist: " + iconResId);
- }
- return this;
- }
-
- public ActionButtonPreference setButton2Enabled(boolean isEnabled) {
- if (isEnabled != mButton2Info.mIsEnabled) {
- mButton2Info.mIsEnabled = isEnabled;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton2OnClickListener(View.OnClickListener listener) {
- if (listener != mButton2Info.mListener) {
- mButton2Info.mListener = listener;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton3Visible(boolean isVisible) {
- if (isVisible != mButton3Info.mIsVisible) {
- mButton3Info.mIsVisible = isVisible;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton3Text(@StringRes int textResId) {
- final String newText = getContext().getString(textResId);
- if (!TextUtils.equals(newText, mButton3Info.mText)) {
- mButton3Info.mText = newText;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton3Icon(@DrawableRes int iconResId) {
- if (iconResId == 0) {
- return this;
- }
-
- final Drawable icon;
- try {
- icon = getContext().getDrawable(iconResId);
- mButton3Info.mIcon = icon;
- notifyChanged();
- } catch (Resources.NotFoundException exception) {
- Log.e(TAG, "Resource does not exist: " + iconResId);
- }
- return this;
- }
-
- public ActionButtonPreference setButton3Enabled(boolean isEnabled) {
- if (isEnabled != mButton3Info.mIsEnabled) {
- mButton3Info.mIsEnabled = isEnabled;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton3OnClickListener(View.OnClickListener listener) {
- if (listener != mButton3Info.mListener) {
- mButton3Info.mListener = listener;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton4Visible(boolean isVisible) {
- if (isVisible != mButton4Info.mIsVisible) {
- mButton4Info.mIsVisible = isVisible;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton4Text(@StringRes int textResId) {
- final String newText = getContext().getString(textResId);
- if (!TextUtils.equals(newText, mButton4Info.mText)) {
- mButton4Info.mText = newText;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton4Icon(@DrawableRes int iconResId) {
- if (iconResId == 0) {
- return this;
- }
-
- final Drawable icon;
- try {
- icon = getContext().getDrawable(iconResId);
- mButton4Info.mIcon = icon;
- notifyChanged();
- } catch (Resources.NotFoundException exception) {
- Log.e(TAG, "Resource does not exist: " + iconResId);
- }
- return this;
- }
-
- public ActionButtonPreference setButton4Enabled(boolean isEnabled) {
- if (isEnabled != mButton4Info.mIsEnabled) {
- mButton4Info.mIsEnabled = isEnabled;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton4OnClickListener(View.OnClickListener listener) {
- if (listener != mButton4Info.mListener) {
- mButton4Info.mListener = listener;
- notifyChanged();
- }
- return this;
- }
-
- static class ButtonInfo {
- private Button mButton;
- private CharSequence mText;
- private Drawable mIcon;
- private View.OnClickListener mListener;
- private boolean mIsEnabled = true;
- private boolean mIsVisible = true;
-
- void setUpButton() {
- mButton.setText(mText);
- mButton.setOnClickListener(mListener);
- mButton.setEnabled(mIsEnabled);
- mButton.setCompoundDrawablesWithIntrinsicBounds(
- null /* left */, mIcon /* top */, null /* right */, null /* bottom */);
-
- if (shouldBeVisible()) {
- mButton.setVisibility(View.VISIBLE);
- } else {
- mButton.setVisibility(View.GONE);
- }
- }
-
- /**
- * By default, four buttons are visible.
- * However, there are two cases which button should be invisible.
- *
- * 1. User set invisible for this button. ex: mIsVisible = false.
- * 2. User didn't set any title or icon.
- *
- */
- private boolean shouldBeVisible() {
- return mIsVisible && (!TextUtils.isEmpty(mText) || mIcon != null);
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
new file mode 100644
index 0000000..23f6ccd
--- /dev/null
+++ b/src/com/android/settings/widget/FloatingAppBarScrollingViewBehavior.java
@@ -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;
+ }
+}
diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java
index 89df487..50c1b58 100644
--- a/src/com/android/settings/widget/RadioButtonPickerFragment.java
+++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java
@@ -22,10 +22,12 @@
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 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 @@
@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 @@
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 @@
}
}
mayCheckOnlyRadioButton();
+ if (mAppendStaticPreferences) {
+ addStaticPreferences(screen);
+ }
}
@VisibleForTesting
diff --git a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
index a883826..cbb8fb8 100644
--- a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
+++ b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
@@ -18,62 +18,34 @@
import android.content.Context;
import android.provider.Settings;
-import android.text.TextUtils;
-import androidx.preference.Preference;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.TogglePreferenceController;
/**
- * {@link AbstractPreferenceController} that controls whether we should fall back to celluar when
+ * CellularFallbackPreferenceController controls whether we should fall back to celluar when
* wifi is bad.
*/
-public class CellularFallbackPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
+public class CellularFallbackPreferenceController extends TogglePreferenceController {
- private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
-
-
- public CellularFallbackPreferenceController(Context context) {
- super(context);
+ public CellularFallbackPreferenceController(Context context, String key) {
+ super(context, key);
}
@Override
- public boolean isAvailable() {
- return !avoidBadWifiConfig();
+ public int getAvailabilityStatus() {
+ return !avoidBadWifiConfig() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
- public String getPreferenceKey() {
- return KEY_CELLULAR_FALLBACK;
+ public boolean isChecked() {
+ return avoidBadWifiCurrentSettings();
}
@Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (!TextUtils.equals(preference.getKey(), KEY_CELLULAR_FALLBACK)) {
- return false;
- }
- if (!(preference instanceof SwitchPreference)) {
- return false;
- }
+ public boolean setChecked(boolean isChecked) {
// On: avoid bad wifi. Off: prompt.
- String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
- Settings.Global.putString(mContext.getContentResolver(), settingName,
- ((SwitchPreference) preference).isChecked() ? "1" : null);
- return true;
- }
-
- @Override
- public void updateState(Preference preference) {
- final boolean currentSetting = avoidBadWifiCurrentSettings();
- // TODO: can this ever be null? The return value of avoidBadWifiConfig() can only
- // change if the resources change, but if that happens the activity will be recreated...
- if (preference != null) {
- SwitchPreference pref = (SwitchPreference) preference;
- pref.setChecked(currentSetting);
- }
+ return Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.NETWORK_AVOID_BAD_WIFI, isChecked ? "1" : null);
}
private boolean avoidBadWifiConfig() {
@@ -85,4 +57,4 @@
return "1".equals(Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.NETWORK_AVOID_BAD_WIFI));
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 1d1c30c..8df4a41 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -85,7 +85,6 @@
controllers.add(mUseOpenWifiPreferenceController);
controllers.add(new WifiInfoPreferenceController(context, getSettingsLifecycle(),
wifiManager));
- controllers.add(new CellularFallbackPreferenceController(context));
controllers.add(new WifiP2pPreferenceController(context, getSettingsLifecycle(),
wifiManager));
return controllers;
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index a1d8620..efb3f8c 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -44,12 +44,18 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.Utils;
import com.android.settingslib.wifi.AccessPoint;
import java.util.ArrayList;
import java.util.List;
+/**
+ * The Fragment sets up callback {@link NetworkRequestMatchCallback} with framework. To handle most
+ * behaviors of the callback when requesting wifi network, except for error message. When error
+ * happens, {@link NetworkRequestErrorDialogFragment} will be called to display error message.
+ */
public class NetworkRequestDialogFragment extends InstrumentedDialogFragment implements
DialogInterface.OnClickListener, NetworkRequestMatchCallback {
@@ -131,7 +137,7 @@
@Override
public void onCancel(@NonNull DialogInterface dialog) {
super.onCancel(dialog);
- // Finishes activity when user clicks back key or outside of dialog.
+ // Finishes the activity when user clicks back key or outside of the dialog.
getActivity().finish();
}
@@ -166,7 +172,7 @@
switch (msg.what) {
case MESSAGE_STOP_SCAN_WIFI_LIST:
removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
- stopScanningAndPopTimeoutDialog();
+ stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.TIME_OUT);
break;
default:
// Do nothing.
@@ -175,14 +181,18 @@
}
};
- protected void stopScanningAndPopTimeoutDialog() {
+ protected void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) {
// Dismisses current dialog.
dismiss();
// Throws new timeout dialog.
- final NetworkRequestTimeoutDialogFragment fragment = NetworkRequestTimeoutDialogFragment
+ final NetworkRequestErrorDialogFragment fragment = NetworkRequestErrorDialogFragment
.newInstance();
- fragment.show(getActivity().getSupportFragmentManager(), null);
+ final Bundle bundle = new Bundle();
+ bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE, type);
+ fragment.setArguments(bundle);
+ fragment.show(getActivity().getSupportFragmentManager(),
+ NetworkRequestDialogFragment.class.getSimpleName());
}
@Override
@@ -239,7 +249,7 @@
@Override
public void onAbort() {
- // TODO(b/117399926): We should have a UI notify user here.
+ stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
}
@Override
diff --git a/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java
new file mode 100644
index 0000000..762b467
--- /dev/null
+++ b/src/com/android/settings/wifi/NetworkRequestErrorDialogFragment.java
@@ -0,0 +1,86 @@
+/*
+ * 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.wifi;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+/**
+ * The dialog shows an error message when requesting network {@link NetworkRequestDialogFragment}.
+ * Contains multi-error types in {@code ERROR_DIALOG_TYPE}.
+ */
+public class NetworkRequestErrorDialogFragment extends InstrumentedDialogFragment {
+
+ public static final String DIALOG_TYPE = "DIALOG_ERROR_TYPE";
+
+ public enum ERROR_DIALOG_TYPE {TIME_OUT, ABORT}
+
+ public static NetworkRequestErrorDialogFragment newInstance() {
+ return new NetworkRequestErrorDialogFragment();
+ }
+
+ private NetworkRequestErrorDialogFragment() {
+ super();
+ }
+
+ @Override
+ public void onCancel(@NonNull DialogInterface dialog) {
+ super.onCancel(dialog);
+ // Wants to finish the activity when user clicks back key or outside of the dialog.
+ getActivity().finish();
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Gets error type to construct dialog. Default is TIME_OUT dialog.
+ ERROR_DIALOG_TYPE msgType = ERROR_DIALOG_TYPE.TIME_OUT;
+ if (getArguments() != null) {
+ msgType = (ERROR_DIALOG_TYPE) getArguments().getSerializable(DIALOG_TYPE);
+ }
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ if (msgType == ERROR_DIALOG_TYPE.TIME_OUT) {
+ builder.setMessage(R.string.network_connection_timeout_dialog_message)
+ .setPositiveButton(R.string.network_connection_timeout_dialog_ok,
+ (dialog, which) -> startScanningDialog())
+ .setNegativeButton(R.string.cancel, (dialog, which) -> getActivity().finish());
+ } else {
+ builder.setMessage(R.string.network_connection_errorstate_dialog_message)
+ .setPositiveButton(R.string.okay, (dialog, which) -> getActivity().finish());
+ }
+ return builder.create();
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.WIFI_SCANNING_NEEDED_DIALOG;
+ }
+
+ protected void startScanningDialog() {
+ final NetworkRequestDialogFragment fragment = NetworkRequestDialogFragment.newInstance();
+ fragment.show(getActivity().getSupportFragmentManager(),
+ NetworkRequestErrorDialogFragment.class.getSimpleName());
+ }
+}
diff --git a/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java
deleted file mode 100644
index 08f285b..0000000
--- a/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragment.java
+++ /dev/null
@@ -1,66 +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.wifi;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import androidx.appcompat.app.AlertDialog;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.R;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-
-public class NetworkRequestTimeoutDialogFragment extends InstrumentedDialogFragment implements
- DialogInterface.OnClickListener {
-
- public static NetworkRequestTimeoutDialogFragment newInstance() {
- NetworkRequestTimeoutDialogFragment fragment = new NetworkRequestTimeoutDialogFragment();
- return fragment;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
- .setMessage(R.string.network_connection_timeout_dialog_message)
- .setPositiveButton(R.string.network_connection_timeout_dialog_ok, this)
- .setNegativeButton(R.string.cancel, null);
- return builder.create();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsProto.MetricsEvent.WIFI_SCANNING_NEEDED_DIALOG;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- startScanningDialog();
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- default:
- // Do nothing.
- break;
- }
- }
-
- protected void startScanningDialog() {
- NetworkRequestDialogFragment fragment = NetworkRequestDialogFragment.newInstance();
- fragment.show(getActivity().getSupportFragmentManager(), null);
- }
-}
diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/WifiSlice.java
index 2382abb..64e3fc3 100644
--- a/src/com/android/settings/wifi/WifiSlice.java
+++ b/src/com/android/settings/wifi/WifiSlice.java
@@ -37,7 +37,6 @@
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
-import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -64,9 +63,11 @@
static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
private final Context mContext;
+ private final WifiManager mWifiManager;
public WifiSlice(Context context) {
mContext = context;
+ mWifiManager = mContext.getSystemService(WifiManager.class);
}
@Override
@@ -100,7 +101,7 @@
final ListBuilder listBuilder = new ListBuilder(mContext, WIFI_SLICE_URI,
ListBuilder.INFINITY)
.setAccentColor(color)
- .addRow(new RowBuilder()
+ .addRow(new ListBuilder.RowBuilder()
.setTitle(title)
.setSubtitle(summary)
.addEndItem(toggleSliceAction)
@@ -110,18 +111,25 @@
return listBuilder.build();
}
- List<AccessPoint> results = SliceBackgroundWorker.getInstance(mContext, this).getResults();
- if (results == null) {
- results = new ArrayList<>();
- }
- final int apCount = results.size();
+ final List<AccessPoint> results =
+ SliceBackgroundWorker.getInstance(mContext, this).getResults();
+
+ // Need a loading text when results are not ready.
+ boolean needLoadingRow = results == null;
+ final int apCount = needLoadingRow ? 0 : results.size();
+
// Add AP rows
final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) {
if (i < apCount) {
listBuilder.addRow(getAccessPointRow(results.get(i)));
+ } else if (needLoadingRow) {
+ listBuilder.addRow(new ListBuilder.RowBuilder()
+ .setTitle(mContext.getText(R.string.wifi_empty_list_wifi_on))
+ .setSubtitle(placeholder));
+ needLoadingRow = false;
} else {
- listBuilder.addRow(new RowBuilder()
+ listBuilder.addRow(new ListBuilder.RowBuilder()
.setTitle(placeholder)
.setSubtitle(placeholder));
}
@@ -129,12 +137,12 @@
return listBuilder.build();
}
- private RowBuilder getAccessPointRow(AccessPoint accessPoint) {
+ private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) {
final String title = accessPoint.getConfigName();
final IconCompat levelIcon = IconCompat.createWithResource(mContext,
com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel()));
final CharSequence apSummary = accessPoint.getSettingsSummary();
- final RowBuilder rowBuilder = new RowBuilder()
+ final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
.setTitle(title)
.setSubtitle(!TextUtils.isEmpty(apSummary)
@@ -188,10 +196,9 @@
*/
@Override
public void onNotifyChange(Intent intent) {
- final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
final boolean newState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
- wifiManager.isWifiEnabled());
- wifiManager.setWifiEnabled(newState);
+ mWifiManager.isWifiEnabled());
+ mWifiManager.setWifiEnabled(newState);
// Do not notifyChange on Uri. The service takes longer to update the current value than it
// does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
// handle it.
@@ -211,26 +218,19 @@
}
private boolean isWifiEnabled() {
- final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
-
- switch (wifiManager.getWifiState()) {
+ switch (mWifiManager.getWifiState()) {
case WifiManager.WIFI_STATE_ENABLED:
case WifiManager.WIFI_STATE_ENABLING:
return true;
- case WifiManager.WIFI_STATE_DISABLED:
- case WifiManager.WIFI_STATE_DISABLING:
- case WifiManager.WIFI_STATE_UNKNOWN:
default:
return false;
}
}
private CharSequence getSummary() {
- final WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
-
- switch (wifiManager.getWifiState()) {
+ switch (mWifiManager.getWifiState()) {
case WifiManager.WIFI_STATE_ENABLED:
- final String ssid = WifiInfo.removeDoubleQuotes(wifiManager.getConnectionInfo()
+ final String ssid = WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo()
.getSSID());
if (TextUtils.equals(ssid, WifiSsid.NONE)) {
return mContext.getText(R.string.disconnected);
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index ba8241a..e1179f8 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -20,6 +20,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +41,7 @@
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
@@ -54,9 +56,11 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.Utils;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.wifi.dpp.WifiDppConfiguratorActivity;
+import com.android.settings.wifi.dpp.WifiDppUtils;
import com.android.settings.wifi.WifiDialog;
import com.android.settings.wifi.WifiDialog.WifiDialogListener;
import com.android.settings.wifi.WifiUtils;
@@ -66,6 +70,7 @@
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.widget.ActionButtonsPreference;
import com.android.settingslib.widget.LayoutPreference;
import com.android.settingslib.wifi.AccessPoint;
@@ -130,7 +135,7 @@
private final MetricsFeatureProvider mMetricsFeatureProvider;
// UI elements - in order of appearance
- private ActionButtonPreference mButtonsPref;
+ private ActionButtonsPreference mButtonsPref;
private EntityHeaderController mEntityHeaderController;
private Preference mSignalStrengthPref;
private Preference mLinkSpeedPref;
@@ -275,12 +280,15 @@
setupEntityHeader(screen);
- mButtonsPref = ((ActionButtonPreference) screen.findPreference(KEY_BUTTONS_PREF))
+ mButtonsPref = ((ActionButtonsPreference) screen.findPreference(KEY_BUTTONS_PREF))
.setButton1Text(R.string.forget)
.setButton1Icon(R.drawable.ic_settings_delete)
.setButton1OnClickListener(view -> forgetNetwork())
.setButton2Text(R.string.wifi_sign_in_button_text)
- .setButton2OnClickListener(view -> signIntoNetwork());
+ .setButton2OnClickListener(view -> signIntoNetwork())
+ .setButton3Text(R.string.share)
+ .setButton3Icon(R.drawable.ic_qrcode_24dp)
+ .setButton3OnClickListener(view -> shareNetwork());
mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mLinkSpeedPref = screen.findPreference(KEY_LINK_SPEED);
@@ -296,7 +304,7 @@
mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY);
mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF);
- mSecurityPref.setSummary(mAccessPoint.getSecurityString(false /* concise */));
+ mSecurityPref.setSummary(mAccessPoint.getSecurityString(/* concise */ false));
}
private void setupEntityHeader(PreferenceScreen screen) {
@@ -425,7 +433,9 @@
private void updateIpLayerInfo() {
mButtonsPref.setButton2Visible(canSignIntoNetwork());
- mButtonsPref.setVisible(canSignIntoNetwork() || canForgetNetwork());
+ mButtonsPref.setButton3Visible(isSharingNetworkEnabled());
+ mButtonsPref.setVisible(
+ canSignIntoNetwork() || canForgetNetwork() || isSharingNetworkEnabled());
if (mNetwork == null || mLinkProperties == null) {
mIpAddressPref.setVisible(false);
@@ -511,6 +521,13 @@
}
/**
+ * Returns whether the user can share the network represented by this preference with QR code.
+ */
+ private boolean isSharingNetworkEnabled() {
+ return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.WIFI_SHARING);
+ }
+
+ /**
* Forgets the wifi network associated with this preference.
*/
private void forgetNetwork() {
@@ -529,6 +546,42 @@
}
/**
+ * Show QR code to share the network represented by this preference.
+ */
+ public void launchQRCodeGenerator() {
+ final Intent intent = new Intent(
+ WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY,
+ mAccessPoint.getSecurityString(/* concise */ false));
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, mAccessPoint.getSsidStr());
+ mContext.startActivity(intent);
+ }
+
+ /**
+ * Share the wifi network with QR code.
+ */
+ private void shareNetwork() {
+ final KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(
+ Context.KEYGUARD_SERVICE);
+ if (keyguardManager.isKeyguardSecure()) {
+ // Show authentication screen to confirm credentials (pin, pattern or password) for
+ // the current user of the device.
+ final String description = String.format(
+ mContext.getString(R.string.wifi_sharing_message),
+ mAccessPoint.getSsidStr());
+ final Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(
+ mContext.getString(R.string.lockpassword_confirm_your_pattern_header),
+ description);
+ if (intent != null) {
+ mFragment.startActivityForResult(intent,
+ WifiNetworkDetailsFragment.REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
+ }
+ } else {
+ launchQRCodeGenerator();
+ }
+ }
+
+ /**
* Sign in to the captive portal found on this wifi network associated with this preference.
*/
private void signIntoNetwork() {
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 7f0e8ee..9814486 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -17,8 +17,10 @@
import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID;
+import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Bundle;
@@ -52,6 +54,8 @@
private static final String TAG = "WifiNetworkDetailsFrg";
+ public static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1;
+
private AccessPoint mAccessPoint;
private WifiDetailPreferenceController mWifiDetailPreferenceController;
@@ -142,4 +146,14 @@
return controllers;
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
+ && resultCode == Activity.RESULT_OK) {
+ mWifiDetailPreferenceController.launchQRCodeGenerator();
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 72fa7fe..d81c19b 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -18,6 +18,7 @@
import android.app.ActionBar;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -30,32 +31,22 @@
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.R;
-public class WifiDppConfiguratorActivity extends InstrumentedActivity {
+public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
+ WifiNetworkConfig.Retriever {
private static final String TAG = "WifiDppConfiguratorActivity";
+ public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
+ "android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER";
+ public static final String ACTION_CONFIGURATOR_QR_CODE_GENERATOR =
+ "android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR";
+ public static final String ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK =
+ "android.settings.WIFI_DPP_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK";
+
private FragmentManager mFragmentManager;
private FragmentTransaction mFragmentTransaction;
- public static final String EXTRA_LAUNCH_MODE =
- "com.android.settings.wifi.dpp.EXTRA_LAUNCH_MODE";
- public static final String EXTRA_SSID = "com.android.settings.wifi.dpp.EXTRA_SSID";
-
- public enum LaunchMode {
- LAUNCH_MODE_QR_CODE_SCANNER(1),
- LAUNCH_MODE_QR_CODE_GENERATOR(2),
- LAUNCH_MODE_CHOOSE_SAVED_WIFI_NETWORK(3),
- LAUNCH_MODE_NOT_DEFINED(-1);
-
- private int mMode;
-
- LaunchMode(int mode) {
- this.mMode = mode;
- }
-
- public int getMode() {
- return mMode;
- }
- }
+ /** The Wi-Fi network which will be configured */
+ private WifiNetworkConfig mWifiNetworkConfig;
@Override
public int getMetricsCategory() {
@@ -71,37 +62,59 @@
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
- final int launchMode = getIntent().getIntExtra(EXTRA_LAUNCH_MODE,
- LaunchMode.LAUNCH_MODE_NOT_DEFINED.getMode());
- if (launchMode == LaunchMode.LAUNCH_MODE_QR_CODE_SCANNER.getMode()) {
- addQrCodeScannerFragment();
- } else if (launchMode == LaunchMode.LAUNCH_MODE_QR_CODE_GENERATOR.getMode()) {
- addQrCodeGeneratorFragment();
- } else if (launchMode == LaunchMode.LAUNCH_MODE_CHOOSE_SAVED_WIFI_NETWORK.getMode()) {
- addChooseSavedWifiNetworkFragment();
- } else {
- Log.e(TAG, "Launch with an invalid mode extra");
+ Intent intent = getIntent();
+ boolean cancelActivity = false;
+ WifiNetworkConfig config;
+ switch (intent.getAction()) {
+ case ACTION_CONFIGURATOR_QR_CODE_SCANNER:
+ config = WifiNetworkConfig.getValidConfigOrNull(intent);
+ if (config == null) {
+ cancelActivity = true;
+ } else {
+ mWifiNetworkConfig = config;
+ addQrCodeScannerFragment(/* addToBackStack= */ false);
+ }
+ break;
+ case ACTION_CONFIGURATOR_QR_CODE_GENERATOR:
+ config = WifiNetworkConfig.getValidConfigOrNull(intent);
+ if (config == null) {
+ cancelActivity = true;
+ } else {
+ mWifiNetworkConfig = config;
+ addQrCodeGeneratorFragment();
+ }
+ break;
+ case ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK:
+ addChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
+ break;
+ default:
+ cancelActivity = true;
+ Log.e(TAG, "Launch with an invalid action");
+ }
+
+ if (cancelActivity) {
setResult(Activity.RESULT_CANCELED);
finish();
}
}
- private void addQrCodeScannerFragment() {
- final WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
+ private void addQrCodeScannerFragment(boolean addToBackStack) {
+ WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
- mFragmentTransaction.addToBackStack(/* name */ null);
+ if (addToBackStack) {
+ mFragmentTransaction.addToBackStack(/* name */ null);
+ }
mFragmentTransaction.commit();
}
private void addQrCodeGeneratorFragment() {
- final WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
+ WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
- mFragmentTransaction.addToBackStack(/* name */ null);
mFragmentTransaction.commit();
}
- private void addChooseSavedWifiNetworkFragment() {
- final ActionBar action = getActionBar();
+ private void addChooseSavedWifiNetworkFragment(boolean addToBackStack) {
+ ActionBar action = getActionBar();
if (action != null) {
action.hide();
}
@@ -109,13 +122,15 @@
WifiDppChooseSavedWifiNetworkFragment fragment =
new WifiDppChooseSavedWifiNetworkFragment();
mFragmentTransaction.add(R.id.fragment_container, fragment);
- mFragmentTransaction.addToBackStack(/* name */ null);
+ if (addToBackStack) {
+ mFragmentTransaction.addToBackStack(/* name */ null);
+ }
mFragmentTransaction.commit();
}
@Override
protected void onStop() {
- final Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
+ Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
if (fragment != null) {
// Remove it to prevent stacking multiple fragments after screen rotated.
mFragmentManager.beginTransaction().remove(fragment).commit();
@@ -123,4 +138,19 @@
super.onStop();
}
+
+ @Override
+ public WifiNetworkConfig getWifiNetworkConfig() {
+ return mWifiNetworkConfig;
+ }
+
+ @Override
+ public boolean setWifiNetworkConfig(WifiNetworkConfig config) {
+ if(!WifiNetworkConfig.isValidConfig(config)) {
+ return false;
+ } else {
+ mWifiNetworkConfig = new WifiNetworkConfig(config);
+ return true;
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
index 0d30a79..c86fc98 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
@@ -30,6 +30,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.wifi.qrcode.QrDecorateView;
import com.android.settings.R;
/**
@@ -46,7 +47,7 @@
private TextView mDescription;
private SurfaceView mPreviewView; //optional, for WifiDppQrCodeScannerFragment
- private ImageView mDecorateViiew; //optional, for WifiDppQrCodeScannerFragment
+ private QrDecorateView mDecorateViiew; //optional, for WifiDppQrCodeScannerFragment
private TextView mErrorMessage; //optional, for WifiDppQrCodeScannerFragment
private ImageView mBarcodeView; //optional, for WifiDppQrCodeGeneratorFragment
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index 3e4ac61..70dade5 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -49,15 +49,12 @@
setTitle(getString(R.string.wifi_dpp_add_device_to_network));
- String ssid = null;
- final Intent intent = getActivity().getIntent();
- if (intent != null) {
- ssid = intent.getStringExtra(WifiDppConfiguratorActivity.EXTRA_SSID);
+ WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
+ .getWifiNetworkConfig();
+ if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
+ throw new IllegalArgumentException("Invalid Wi-Fi network for configuring");
}
- if (TextUtils.isEmpty(ssid)) {
- throw new IllegalArgumentException("Invalid SSID");
- }
- setDescription(getString(R.string.wifi_dpp_center_qr_code, ssid));
+ setDescription(getString(R.string.wifi_dpp_center_qr_code, wifiNetworkConfig.getSsid()));
hideRightButton();
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
new file mode 100644
index 0000000..70ef3a8
--- /dev/null
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -0,0 +1,57 @@
+/*
+ * 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.wifi.dpp;
+
+import android.content.Intent;
+
+/**
+ * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
+ */
+public class WifiDppUtils {
+ /** The data is from {@code com.android.settingslib.wifi.AccessPoint.securityToString} */
+ public static final String EXTRA_WIFI_SECURITY = "security";
+
+ /** The data corresponding to {@code WifiConfiguration} SSID */
+ public static final String EXTRA_WIFI_SSID = "ssid";
+
+ /** The data corresponding to {@code WifiConfiguration} preSharedKey */
+ public static final String EXTRA_WIFI_PRE_SHARED_KEY = "preSharedKey";
+
+ /** The data corresponding to {@code WifiConfiguration} hiddenSSID */
+ public static final String EXTRA_WIFI_HIDDEN_SSID = "hiddenSsid";
+
+ /**
+ * Acceptable QR code string may be a standard W-Fi DPP bootstrapping information or the Wi-Fi
+ * Network config format described in
+ * https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
+ *
+ * Wi-Fi Network config format example:
+ *
+ * WIFI:T:WPA;S:mynetwork;P:mypass;;
+ *
+ * parameter Example Description
+ * T WPA Authentication type; can be WEP or WPA, or 'nopass' for no password. Or,
+ * omit for no password.
+ * S mynetwork Network SSID. Required. Enclose in double quotes if it is an ASCII name,
+ * but could be interpreted as hex (i.e. "ABCD")
+ * P mypass Password, ignored if T is "nopass" (in which case it may be omitted).
+ * Enclose in double quotes if it is an ASCII name, but could be interpreted as
+ * hex (i.e. "ABCD")
+ * H true Optional. True if the network SSID is hidden.
+ */
+ public static final String EXTRA_QR_CODE = "qrCode";
+}
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
new file mode 100644
index 0000000..439de98
--- /dev/null
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -0,0 +1,118 @@
+/*
+ * 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.wifi.dpp;
+
+import android.content.Intent;
+import android.text.TextUtils;
+
+/**
+ * Contains the Wi-Fi Network config parameters described in
+ * https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
+ *
+ * Checks below members of {@code WifiDppUtils} for more information.
+ * EXTRA_WIFI_SECURITY / EXTRA_WIFI_SSID / EXTRA_WIFI_PRE_SHARED_KEY / EXTRA_WIFI_HIDDEN_SSID /
+ * EXTRA_QR_CODE
+ */
+public class WifiNetworkConfig {
+ private String mSecurity;
+ private String mSsid;
+ private String mPreSharedKey;
+ private boolean mHiddenSsid;
+
+ private WifiNetworkConfig(String security, String ssid, String preSharedKey,
+ boolean hiddenSsid) {
+ mSecurity = security;
+ mSsid = ssid;
+ mPreSharedKey = preSharedKey;
+ mHiddenSsid = hiddenSsid;
+ }
+
+ public WifiNetworkConfig(WifiNetworkConfig config) {
+ mSecurity = new String(config.mSecurity);
+ mSsid = new String(config.mSsid);
+ mPreSharedKey = new String(config.mPreSharedKey);
+ mHiddenSsid = config.mHiddenSsid;
+ }
+
+ /**
+ * Wi-Fi DPP activities should implement this interface for fragments to retrieve the
+ * WifiNetworkConfig for configuration
+ */
+ public interface Retriever {
+ public WifiNetworkConfig getWifiNetworkConfig();
+ public boolean setWifiNetworkConfig(WifiNetworkConfig config);
+ }
+
+ /**
+ * Retrieve WifiNetworkConfig from below 2 intents
+ *
+ * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR
+ * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER
+ */
+ public static WifiNetworkConfig getValidConfigOrNull(Intent intent) {
+ String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
+ String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
+ String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
+ boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID, false);
+
+ if (!isValidConfig(security, ssid, hiddenSsid)) {
+ return null;
+ }
+
+ if (ssid == null) {
+ ssid = "";
+ }
+
+ return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid);
+ }
+
+ public static boolean isValidConfig(WifiNetworkConfig config) {
+ if (config == null) {
+ return false;
+ } else {
+ return isValidConfig(config.mSecurity, config.mSsid, config.mHiddenSsid);
+ }
+ }
+
+ public static boolean isValidConfig(String security, String ssid, boolean hiddenSsid) {
+ if (TextUtils.isEmpty(security)) {
+ return false;
+ }
+
+ if (!hiddenSsid && TextUtils.isEmpty(ssid)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public String getSecurity() {
+ return new String(mSecurity);
+ }
+
+ public String getSsid() {
+ return new String(mSsid);
+ }
+
+ public String getPreSharedKey() {
+ return new String(mPreSharedKey);
+ }
+
+ public boolean getHiddenSsid() {
+ return mHiddenSsid;
+ }
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 479ffee..ab06f75 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -7,7 +7,6 @@
com.android.settings.accessibility.ToggleSelectToSpeakPreferenceFragmentForSetupWizard
com.android.settings.accounts.AccountDetailDashboardFragment
com.android.settings.accounts.AccountSyncSettings
-com.android.settings.accounts.ManagedProfileSettings
com.android.settings.applications.appinfo.AppInfoDashboardFragment
com.android.settings.applications.appinfo.DrawOverlayDetails
com.android.settings.applications.appinfo.ExternalSourcesDetails
@@ -27,9 +26,7 @@
com.android.settings.bluetooth.BluetoothPairingDetail
com.android.settings.bluetooth.DevicePickerFragment
com.android.settings.datausage.AppDataUsage
-com.android.settings.datausage.AppDataUsageV2
com.android.settings.datausage.DataUsageList
-com.android.settings.datausage.DataUsageListV2
com.android.settings.datetime.timezone.TimeZoneSettings
com.android.settings.deviceinfo.PrivateVolumeSettings
com.android.settings.deviceinfo.PublicVolumeSettings
diff --git a/tests/robotests/res/values/themes.xml b/tests/robotests/res/values/themes.xml
index 7bfbe10..41ace18 100644
--- a/tests/robotests/res/values/themes.xml
+++ b/tests/robotests/res/values/themes.xml
@@ -15,6 +15,8 @@
<item name="colorAccent">#ffffff</item>
<item name="preferenceTheme">@style/PreferenceTheme</item>
<item name="android:windowLightStatusBar">true</item>
+ <!-- Define this color for material design -->
+ <item name="colorPrimaryVariant">@android:color/white</item>
</style>
<style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.ActionBar">
diff --git a/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml b/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml
new file mode 100644
index 0000000..f91e4ca
--- /dev/null
+++ b/tests/robotests/res/xml-mcc999/battery_saver_schedule_settings.xml
@@ -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 >
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index cb2aa8b..00980ad 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -18,10 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import android.content.ContentResolver;
import android.content.Context;
import android.os.Vibrator;
import android.provider.Settings;
@@ -32,6 +32,7 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.XmlTestUtils;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@@ -42,31 +43,43 @@
@RunWith(SettingsRobolectricTestRunner.class)
public class AccessibilitySettingsTest {
+ private static final String VIBRATION_PREFERENCE_SCREEN = "vibration_preference_screen";
+ private static final String ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE =
+ "accessibility_content_timeout_preference_fragment";
+ private static final String ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE =
+ "accessibility_control_timeout_preference_fragment";
+
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ private AccessibilitySettings mSettings;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = mContext.getContentResolver();
+ mSettings = spy(new AccessibilitySettings());
+ doReturn(mContext).when(mSettings).getContext();
+ }
@Test
public void testNonIndexableKeys_existInXmlLayout() {
- final Context context = RuntimeEnvironment.application;
final List<String> niks = AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER
- .getNonIndexableKeys(context);
+ .getNonIndexableKeys(mContext);
final List<String> keys = new ArrayList<>();
- keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, R.xml.accessibility_settings));
+ keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(mContext, R.xml.accessibility_settings));
assertThat(keys).containsAllIn(niks);
}
@Test
public void testUpdateVibrationSummary_shouldUpdateSummary() {
- MockitoAnnotations.initMocks(this);
- final Context mContext = RuntimeEnvironment.application;
- final AccessibilitySettings mSettings = spy(new AccessibilitySettings());
-
final Preference mVibrationPreferenceScreen = new Preference(mContext);
- doReturn(mVibrationPreferenceScreen).when(mSettings).findPreference(anyString());
+ doReturn(mVibrationPreferenceScreen).when(mSettings).findPreference(
+ VIBRATION_PREFERENCE_SCREEN);
- doReturn(mContext).when(mSettings).getContext();
-
- mVibrationPreferenceScreen.setKey("vibration_preference_screen");
+ mVibrationPreferenceScreen.setKey(VIBRATION_PREFERENCE_SCREEN);
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
@@ -81,4 +94,58 @@
VibrationIntensityPreferenceController.getIntensityString(mContext,
Vibrator.VIBRATION_INTENSITY_OFF));
}
+
+ @Test
+ public void testUpdateAccessibilityTimeoutSummary_shouldUpdateSummary() {
+ String[] testingValues = {null, "0", "10000", "30000", "60000", "120000"};
+ int[] exceptedResIds = {R.string.accessibility_timeout_default,
+ R.string.accessibility_timeout_default,
+ R.string.accessibility_timeout_10secs,
+ R.string.accessibility_timeout_30secs,
+ R.string.accessibility_timeout_1min,
+ R.string.accessibility_timeout_2mins
+ };
+
+ for (int i = 0; i < testingValues.length; i++) {
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, testingValues[i]);
+
+ verifyAccessibilityTimeoutSummary(ACCESSIBILITY_CONTENT_TIMEOUT_PREFERENCE,
+ exceptedResIds[i]);
+
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, testingValues[i]);
+
+ verifyAccessibilityTimeoutSummary(ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE,
+ exceptedResIds[i]);
+ }
+ }
+
+ @Test
+ public void testUpdateAccessibilityControlTimeoutSummary_invalidData_shouldUpdateSummary() {
+ String[] testingValues = {"-9009", "98277466643738977979666555536362343", "Hello,a prank"};
+
+ for (String value : testingValues) {
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, value);
+
+ verifyAccessibilityTimeoutSummary(ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE,
+ R.string.accessibility_timeout_default);
+
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, value);
+
+ verifyAccessibilityTimeoutSummary(ACCESSIBILITY_CONTROL_TIMEOUT_PREFERENCE,
+ R.string.accessibility_timeout_default);
+ }
+ }
+
+ private void verifyAccessibilityTimeoutSummary(String preferenceKey, int resId) {
+ final Preference preference = new Preference(mContext);
+ doReturn(preference).when(mSettings).findPreference(preferenceKey);
+ preference.setKey(preferenceKey);
+ mSettings.updateAccessibilityTimeoutSummary(mContentResolver, preference);
+
+ assertThat(preference.getSummary()).isEqualTo(mContext.getResources().getString(resId));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
new file mode 100644
index 0000000..4469282
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.accounts;
+
+import static android.provider.Settings.Secure.CROSS_PROFILE_CALENDAR_ENABLED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+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 static org.robolectric.RuntimeEnvironment.application;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+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.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowDevicePolicyManager;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class CrossProfileCalendarPreferenceControllerTest {
+
+ private static final String PREF_KEY = "cross_profile_calendar";
+ private static final int MANAGED_USER_ID = 10;
+ private static final String TEST_PACKAGE_NAME = "com.test";
+ private static final ComponentName TEST_COMPONENT_NAME = new ComponentName("test", "test");
+
+ @Mock
+ private UserHandle mManagedUser;
+
+ private RestrictedSwitchPreference mPreference;
+ private Context mContext;
+ private CrossProfileCalendarPreferenceController mController;
+ private ShadowDevicePolicyManager dpm;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mController = new CrossProfileCalendarPreferenceController(mContext, PREF_KEY);
+ mController.setManagedUser(mManagedUser);
+ mPreference = spy(new RestrictedSwitchPreference(mContext));
+ dpm = Shadows.shadowOf(application.getSystemService(DevicePolicyManager.class));
+
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+ doReturn(mContext).when(mContext).createPackageContextAsUser(
+ any(String.class), anyInt(), any(UserHandle.class));
+ }
+
+ @Test
+ public void getAvailabilityStatus_noManagedUser_DISABLED() {
+ mController.setManagedUser(null);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isNotEqualTo(CrossProfileCalendarPreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
+ mController.setManagedUser(mManagedUser);
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(CrossProfileCalendarPreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void updateStateToDisabled_isNotChecked() {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier());
+
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void updateStateToEnabled_isChecked() throws Exception {
+ // Put 0 first so we know the value is not originally 1.
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier());
+ mController.updateState(mPreference);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, 1, mManagedUser.getIdentifier());
+
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void updateState_noPackageAllowed_preferenceShouldBeDisabled() throws Exception {
+ dpm.setProfileOwner(TEST_COMPONENT_NAME);
+
+ mController.updateState(mPreference);
+ verify(mPreference).setDisabledByAdmin(any());
+ }
+
+ @Test
+ public void updateState_somePackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
+ dpm.setProfileOwner(TEST_COMPONENT_NAME);
+ dpm.addCrossProfileCalendarPackage(TEST_COMPONENT_NAME, TEST_PACKAGE_NAME);
+
+ mController.updateState(mPreference);
+ verify(mPreference).setDisabledByAdmin(null);
+ }
+
+ @Test
+ public void onPreferenceChangeToFalse_shouldUpdateProviderValue() {
+ mController.onPreferenceChange(mPreference, false);
+ assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, 1, mManagedUser.getIdentifier()))
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void onPreferenceChangeToTrue_shouldUpdateProviderValue() {
+ // Change to false first so we know the value is not originally 1.
+ mController.onPreferenceChange(mPreference, false);
+
+ mController.onPreferenceChange(mPreference, true);
+ assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ CROSS_PROFILE_CALENDAR_ENABLED, 0, mManagedUser.getIdentifier()))
+ .isEqualTo(1);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java b/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java
index 87eb6a6..114000c 100644
--- a/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppStorageSettingsTest.java
@@ -16,6 +16,8 @@
package com.android.settings.applications;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
@@ -30,9 +32,8 @@
import android.widget.Button;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.widget.ActionButtonPreference;
-import com.android.settings.widget.ActionButtonPreferenceTest;
import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
+import com.android.settingslib.widget.ActionButtonsPreference;
import org.junit.Before;
import org.junit.Test;
@@ -46,7 +47,7 @@
@Mock
private AppStorageSizesController mSizesController;
- private ActionButtonPreference mButtonsPref;
+ private ActionButtonsPreference mButtonsPref;
private AppStorageSettings mSettings;
private Button mLeftButton;
private Button mRightButton;
@@ -58,7 +59,7 @@
mRightButton = new Button(RuntimeEnvironment.application);
mSettings = spy(new AppStorageSettings());
mSettings.mSizeController = mSizesController;
- mButtonsPref = ActionButtonPreferenceTest.createMock();
+ mButtonsPref = createMock();
mSettings.mButtonsPref = mButtonsPref;
when(mButtonsPref.setButton1OnClickListener(any(View.OnClickListener.class)))
@@ -103,5 +104,22 @@
verify(mSettings).handleClearDataClick();
verify(mSettings).handleClearCacheClick();
}
+
+ private ActionButtonsPreference createMock() {
+ final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
+ when(pref.setButton1Text(anyInt())).thenReturn(pref);
+ when(pref.setButton1Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ when(pref.setButton2Text(anyInt())).thenReturn(pref);
+ when(pref.setButton2Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ return pref;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
index 815c76b..f8dd11b 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
@@ -42,18 +43,18 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.UserManager;
+import android.view.View;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.widget.ActionButtonPreference;
-import com.android.settings.widget.ActionButtonPreferenceTest;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.ActionButtonsPreference;
import org.junit.Before;
import org.junit.Test;
@@ -99,9 +100,8 @@
@Mock
private PackageInfo mPackageInfo;
- private ActionButtonPreference mButtonPrefs;
-
private Intent mUninstallIntent;
+ private ActionButtonsPreference mButtonPrefs;
private AppButtonsPreferenceController mController;
@Before
@@ -127,7 +127,7 @@
mPackageInfo.packageName = PACKAGE_NAME;
mPackageInfo.applicationInfo = mAppInfo;
- mButtonPrefs = ActionButtonPreferenceTest.createMock();
+ mButtonPrefs = createMock();
mController.mButtonsPref = mButtonPrefs;
mController.mPackageInfo = mPackageInfo;
@@ -175,6 +175,22 @@
}
@Test
+ public void updateOpenButton_noLaunchIntent_buttonShouldBeDisable() {
+ mController.updateOpenButton();
+
+ verify(mButtonPrefs).setButton1Visible(false);
+ }
+
+ @Test
+ public void updateOpenButton_haveLaunchIntent_buttonShouldBeEnable() {
+ doReturn(new Intent()).when(mPackageManger).getLaunchIntentForPackage(anyString());
+
+ mController.updateOpenButton();
+
+ verify(mButtonPrefs).setButton1Visible(true);
+ }
+
+ @Test
public void updateUninstallButton_isSystemApp_handleAsDisableableButton() {
doReturn(false).when(mController).handleDisableable();
mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
@@ -182,7 +198,7 @@
mController.updateUninstallButton();
verify(mController).handleDisableable();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -220,7 +236,7 @@
mController.updateUninstallButton();
verify(mController).handleDisableable();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -229,7 +245,7 @@
mController.updateUninstallButton();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -239,7 +255,7 @@
mController.updateUninstallButton();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -248,7 +264,7 @@
mController.updateUninstallButton();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -258,7 +274,7 @@
mController.updateUninstallButton();
- verify(mButtonPrefs).setButton1Enabled(false);
+ verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@@ -308,7 +324,7 @@
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.uninstall_text);
+ verify(mButtonPrefs).setButton2Text(R.string.uninstall_text);
assertThat(controllable).isFalse();
}
@@ -320,7 +336,7 @@
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.uninstall_text);
+ verify(mButtonPrefs).setButton2Text(R.string.uninstall_text);
assertThat(controllable).isTrue();
}
@@ -332,7 +348,7 @@
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.install_text);
+ verify(mButtonPrefs).setButton2Text(R.string.install_text);
assertThat(controllable).isTrue();
}
@@ -390,4 +406,15 @@
return SettingsEnums.PAGE_UNKNOWN;
}
}
+
+ private ActionButtonsPreference createMock() {
+ final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
+ when(pref.setButton2Text(anyInt())).thenReturn(pref);
+ when(pref.setButton2Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ return pref;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
index 1adc678..fe70c7e 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -16,13 +16,12 @@
package com.android.settings.applications.appinfo;
-import static com.android.settings.core.FeatureFlags.DATA_USAGE_V2;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -33,12 +32,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.ConnectivityManager;
-import android.net.INetworkStatsSession;
import android.os.Bundle;
-import android.util.FeatureFlagUtils;
-
-import androidx.loader.app.LoaderManager;
-import androidx.preference.Preference;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.datausage.AppDataUsage;
@@ -49,9 +43,12 @@
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;
+
+import androidx.loader.app.LoaderManager;
+import androidx.preference.Preference;
@RunWith(SettingsRobolectricTestRunner.class)
public class AppDataUsagePreferenceControllerTest {
@@ -68,7 +65,6 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application.getApplicationContext());
- FeatureFlagUtils.setEnabled(mContext, DATA_USAGE_V2, false);
mController = spy(new AppDataUsagePreferenceController(mContext, "test_key"));
mController.setParentFragment(mFragment);
}
@@ -90,8 +86,9 @@
}
@Test
- public void onResume_noSession_shouldNotRestartDataLoader() {
+ public void onResume_notAvailable_shouldNotRestartDataLoader() {
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+ doReturn(BasePreferenceController.CONDITIONALLY_UNAVAILABLE).when(mController).getAvailabilityStatus();
mController.onResume();
@@ -100,26 +97,26 @@
}
@Test
- public void onResume_hasSession_shouldRestartDataLoader() {
+ public void onResume_isAvailable_shouldRestartDataLoader() {
final ConnectivityManager connectivityManager = mock(ConnectivityManager.class);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(connectivityManager);
when(connectivityManager.isNetworkSupported(anyInt())).thenReturn(true);
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
- ReflectionHelpers.setField(mController, "mStatsSession", mock(INetworkStatsSession.class));
+ doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
final AppEntry appEntry = mock(AppEntry.class);
appEntry.info = new ApplicationInfo();
when(mFragment.getAppEntry()).thenReturn(appEntry);
mController.onResume();
- verify(mLoaderManager).restartLoader(
- eq(AppInfoDashboardFragment.LOADER_CHART_DATA), any(Bundle.class), eq(mController));
+ verify(mLoaderManager).restartLoader(eq(AppInfoDashboardFragment.LOADER_CHART_DATA),
+ nullable(Bundle.class), eq(mController));
}
@Test
public void onPause_shouldDestroyDataLoader() {
- ReflectionHelpers.setField(mController, "mStatsSession", mock(INetworkStatsSession.class));
+ doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
mController.onPause();
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java
deleted file mode 100644
index 708222e..0000000
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java
+++ /dev/null
@@ -1,143 +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.applications.appinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.net.ConnectivityManager;
-import android.os.Bundle;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settings.core.FeatureFlags;
-import com.android.settings.datausage.AppDataUsageV2;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import android.util.FeatureFlagUtils;
-
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-
-import androidx.loader.app.LoaderManager;
-import androidx.preference.Preference;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class AppDataUsagePreferenceControllerV2Test {
-
- @Mock
- private LoaderManager mLoaderManager;
- @Mock
- private AppInfoDashboardFragment mFragment;
-
- private Context mContext;
- private AppDataUsagePreferenceControllerV2 mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application.getApplicationContext());
- mController = spy(new AppDataUsagePreferenceControllerV2(mContext, "test_key"));
- mController.setParentFragment(mFragment);
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_V2, true);
- }
-
- @Test
- public void getAvailabilityStatus_bandwidthControlEnabled_shouldReturnAvailable() {
- doReturn(true).when(mController).isBandwidthControlEnabled();
-
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.AVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_bandwidthControlDisabled_shouldReturnDisabled() {
- doReturn(false).when(mController).isBandwidthControlEnabled();
-
- assertThat(mController.getAvailabilityStatus())
- .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void onResume_notAvailable_shouldNotRestartDataLoader() {
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_V2, false);
- doReturn(mLoaderManager).when(mFragment).getLoaderManager();
-
- mController.onResume();
-
- verify(mLoaderManager, never()).restartLoader(
- AppInfoDashboardFragment.LOADER_CHART_DATA, Bundle.EMPTY, mController);
- }
-
- @Test
- public void onResume_isAvailable_shouldRestartDataLoader() {
- final ConnectivityManager connectivityManager = mock(ConnectivityManager.class);
- when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
- .thenReturn(connectivityManager);
- when(connectivityManager.isNetworkSupported(anyInt())).thenReturn(true);
- doReturn(mLoaderManager).when(mFragment).getLoaderManager();
- doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = new ApplicationInfo();
- when(mFragment.getAppEntry()).thenReturn(appEntry);
-
- mController.onResume();
-
- verify(mLoaderManager).restartLoader(eq(AppInfoDashboardFragment.LOADER_CHART_DATA),
- nullable(Bundle.class), eq(mController));
- }
-
- @Test
- public void onPause_shouldDestroyDataLoader() {
- doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus();
- doReturn(mLoaderManager).when(mFragment).getLoaderManager();
-
- mController.onPause();
-
- verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_CHART_DATA);
- }
-
- @Test
- public void getDetailFragmentClass_shouldReturnAppDataUsage() {
- assertThat(mController.getDetailFragmentClass()).isEqualTo(AppDataUsageV2.class);
- }
-
- @Test
- public void updateState_shouldUpdatePreferenceSummary() {
- final Preference preference = mock(Preference.class);
-
- mController.updateState(preference);
-
- verify(preference).setSummary(any());
- }
-}
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index b3f5b5e..4c9cacb 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -28,11 +28,12 @@
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.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;
@@ -159,6 +162,35 @@
}
@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));
ReflectionHelpers.setField(mFragment, "mListContainer", mock(View.class));
@@ -250,6 +282,34 @@
}
@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);
final ManageApplications.ApplicationsAdapter adapter =
@@ -344,6 +404,48 @@
}
@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[]{});
ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
@@ -375,4 +477,14 @@
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;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
index 094ec80..d8be01f 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -34,8 +36,7 @@
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowBluetoothDevice;
-import com.android.settings.widget.ActionButtonPreference;
-import com.android.settings.widget.ActionButtonPreferenceTest;
+import com.android.settingslib.widget.ActionButtonsPreference;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,7 +48,7 @@
@Config(shadows = SettingsShadowBluetoothDevice.class)
public class BluetoothDetailsButtonsControllerTest extends BluetoothDetailsControllerTestBase {
private BluetoothDetailsButtonsController mController;
- private ActionButtonPreference mButtonsPref;
+ private ActionButtonsPreference mButtonsPref;
private Button mConnectButton;
private Button mForgetButton;
@@ -60,8 +61,9 @@
mConnectButton = buttons.findViewById(R.id.button2);
mForgetButton = buttons.findViewById(R.id.button1);
mController =
- new BluetoothDetailsButtonsController(mContext, mFragment, mCachedDevice, mLifecycle);
- mButtonsPref = ActionButtonPreferenceTest.createMock();
+ new BluetoothDetailsButtonsController(mContext, mFragment, mCachedDevice,
+ mLifecycle);
+ mButtonsPref = createMock();
when(mButtonsPref.getKey()).thenReturn(mController.getPreferenceKey());
when(mButtonsPref.setButton2OnClickListener(any(View.OnClickListener.class)))
.thenAnswer(invocation -> {
@@ -186,4 +188,21 @@
verify(mButtonsPref).setButton2Enabled(false);
}
+
+ private ActionButtonsPreference createMock() {
+ final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
+ when(pref.setButton1Text(anyInt())).thenReturn(pref);
+ when(pref.setButton1Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ when(pref.setButton2Text(anyInt())).thenReturn(pref);
+ when(pref.setButton2Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ return pref;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
index 3b1b5af..ebf3252 100644
--- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
@@ -18,6 +18,7 @@
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 @@
}
}
+ @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
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 01fa32f..333c706 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -19,6 +19,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
@@ -28,12 +29,14 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.net.NetworkPolicyManager;
import android.os.Bundle;
import android.util.ArraySet;
import android.view.View;
+import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -45,6 +48,7 @@
import com.android.settingslib.AppItem;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.net.NetworkCycleDataForUid;
import org.junit.After;
import org.junit.Before;
@@ -57,6 +61,9 @@
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
public class AppDataUsageTest {
@@ -172,4 +179,49 @@
verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class));
verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class));
}
+
+ @Test
+ public void bindData_noAppUsageData_shouldHideCycleSpinner() {
+ mFragment = spy(new AppDataUsage());
+ final SpinnerPreference cycle = mock(SpinnerPreference.class);
+ ReflectionHelpers.setField(mFragment, "mCycle", cycle);
+ final Preference preference = mock(Preference.class);
+ ReflectionHelpers.setField(mFragment, "mBackgroundUsage", preference);
+ ReflectionHelpers.setField(mFragment, "mForegroundUsage", preference);
+ ReflectionHelpers.setField(mFragment, "mTotalUsage", preference);
+ doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
+
+ mFragment.bindData(0 /* position */);
+
+ verify(cycle).setVisible(false);
+ }
+
+ @Test
+ public void bindData_hasAppUsageData_shouldShowCycleSpinnerAndUpdateUsageSummary() {
+ mFragment = spy(new AppDataUsage());
+ final Context context = RuntimeEnvironment.application;
+ doReturn(context).when(mFragment).getContext();
+ final long backgroundBytes = 1234L;
+ final long foregroundBytes = 5678L;
+ final List<NetworkCycleDataForUid> appUsage = new ArrayList<>();
+ appUsage.add(new NetworkCycleDataForUid.Builder()
+ .setBackgroundUsage(backgroundBytes).setForegroundUsage(foregroundBytes).build());
+ ReflectionHelpers.setField(mFragment, "mUsageData", appUsage);
+ final Preference backgroundPref = mock(Preference.class);
+ ReflectionHelpers.setField(mFragment, "mBackgroundUsage", backgroundPref);
+ final Preference foregroundPref = mock(Preference.class);
+ ReflectionHelpers.setField(mFragment, "mForegroundUsage", foregroundPref);
+ final Preference totalPref = mock(Preference.class);
+ ReflectionHelpers.setField(mFragment, "mTotalUsage", totalPref);
+ final SpinnerPreference cycle = mock(SpinnerPreference.class);
+ ReflectionHelpers.setField(mFragment, "mCycle", cycle);
+
+ mFragment.bindData(0 /* position */);
+
+ verify(cycle).setVisible(true);
+ verify(totalPref).setSummary(
+ DataUsageUtils.formatDataUsage(context, backgroundBytes + foregroundBytes));
+ verify(backgroundPref).setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
+ verify(foregroundPref).setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java
deleted file mode 100644
index 8796a39..0000000
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageV2Test.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2017 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.datausage;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.NetworkPolicyManager;
-import android.os.Bundle;
-import android.util.ArraySet;
-import android.view.View;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
-import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
-import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.AppItem;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.net.NetworkCycleDataForUid;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = {ShadowEntityHeaderController.class, ShadowRestrictedLockUtilsInternal.class})
-public class AppDataUsageV2Test {
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private EntityHeaderController mHeaderController;
- @Mock
- private PackageManager mPackageManager;
-
- private AppDataUsageV2 mFragment;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- FakeFeatureFactory.setupForTest();
- }
-
- @After
- public void tearDown() {
- ShadowEntityHeaderController.reset();
- }
-
- @Test
- public void bindAppHeader_allWorkApps_shouldNotShowAppInfoLink() {
- ShadowEntityHeaderController.setUseMock(mHeaderController);
- when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
- when(mHeaderController.setUid(anyInt())).thenReturn(mHeaderController);
-
- mFragment = spy(new AppDataUsageV2());
-
- when(mFragment.getPreferenceManager())
- .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
- doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
- ReflectionHelpers.setField(mFragment, "mAppItem", mock(AppItem.class));
-
- mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
-
- verify(mHeaderController).setHasAppInfoLink(false);
- }
-
- @Test
- public void bindAppHeader_workApp_shouldSetWorkAppUid() throws
- PackageManager.NameNotFoundException {
- final int fakeUserId = 100;
-
- mFragment = spy(new AppDataUsageV2());
- final ArraySet<String> packages = new ArraySet<>();
- packages.add("pkg");
- final AppItem appItem = new AppItem(123456789);
-
- ReflectionHelpers.setField(mFragment, "mPackageManager", mPackageManager);
- ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
- ReflectionHelpers.setField(mFragment, "mPackages", packages);
-
- when(mPackageManager.getPackageUidAsUser(anyString(), anyInt()))
- .thenReturn(fakeUserId);
-
- ShadowEntityHeaderController.setUseMock(mHeaderController);
- when(mHeaderController.setRecyclerView(any(), any())).thenReturn(mHeaderController);
- when(mHeaderController.setUid(fakeUserId)).thenReturn(mHeaderController);
- when(mHeaderController.setHasAppInfoLink(anyBoolean())).thenReturn(mHeaderController);
-
- when(mFragment.getPreferenceManager())
- .thenReturn(mock(PreferenceManager.class, RETURNS_DEEP_STUBS));
- doReturn(mock(PreferenceScreen.class)).when(mFragment).getPreferenceScreen();
-
- mFragment.onViewCreated(new View(RuntimeEnvironment.application), new Bundle());
-
- verify(mHeaderController).setHasAppInfoLink(true);
- verify(mHeaderController).setUid(fakeUserId);
- }
-
- @Test
- public void changePreference_backgroundData_shouldUpdateUI() {
- mFragment = spy(new AppDataUsageV2());
- final AppItem appItem = new AppItem(123456789);
- final RestrictedSwitchPreference pref = mock(RestrictedSwitchPreference.class);
- final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
- ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
- ReflectionHelpers.setField(mFragment, "mRestrictBackground", pref);
- ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
-
- doNothing().when(mFragment).updatePrefs();
-
- mFragment.onPreferenceChange(pref, true /* value */);
-
- verify(mFragment).updatePrefs();
- }
-
- @Test
- public void updatePrefs_restrictedByAdmin_shouldDisablePreference() {
- mFragment = spy(new AppDataUsageV2());
- final int testUid = 123123;
- final AppItem appItem = new AppItem(testUid);
- final RestrictedSwitchPreference restrictBackgroundPref
- = mock(RestrictedSwitchPreference.class);
- final RestrictedSwitchPreference unrestrictedDataPref
- = mock(RestrictedSwitchPreference.class);
- final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
- final NetworkPolicyManager networkPolicyManager = mock(NetworkPolicyManager.class);
- ReflectionHelpers.setField(mFragment, "mAppItem", appItem);
- ReflectionHelpers.setField(mFragment, "mRestrictBackground", restrictBackgroundPref);
- ReflectionHelpers.setField(mFragment, "mUnrestrictedData", unrestrictedDataPref);
- ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
- ReflectionHelpers.setField(mFragment.services, "mPolicyManager", networkPolicyManager);
-
- ShadowRestrictedLockUtilsInternal.setRestricted(true);
- doReturn(NetworkPolicyManager.POLICY_NONE).when(networkPolicyManager)
- .getUidPolicy(testUid);
-
- mFragment.updatePrefs();
-
- verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class));
- verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class));
- }
-
- @Test
- public void bindData_noAppUsageData_shouldHideCycleSpinner() {
- mFragment = spy(new AppDataUsageV2());
- final SpinnerPreference cycle = mock(SpinnerPreference.class);
- ReflectionHelpers.setField(mFragment, "mCycle", cycle);
- final Preference preference = mock(Preference.class);
- ReflectionHelpers.setField(mFragment, "mBackgroundUsage", preference);
- ReflectionHelpers.setField(mFragment, "mForegroundUsage", preference);
- ReflectionHelpers.setField(mFragment, "mTotalUsage", preference);
- doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
-
- mFragment.bindData(0 /* position */);
-
- verify(cycle).setVisible(false);
- }
-
- @Test
- public void bindData_hasAppUsageData_shouldShowCycleSpinnerAndUpdateUsageSummary() {
- mFragment = spy(new AppDataUsageV2());
- final Context context = RuntimeEnvironment.application;
- doReturn(context).when(mFragment).getContext();
- final long backgroundBytes = 1234L;
- final long foregroundBytes = 5678L;
- final List<NetworkCycleDataForUid> appUsage = new ArrayList<>();
- appUsage.add(new NetworkCycleDataForUid.Builder()
- .setBackgroundUsage(backgroundBytes).setForegroundUsage(foregroundBytes).build());
- ReflectionHelpers.setField(mFragment, "mUsageData", appUsage);
- final Preference backgroundPref = mock(Preference.class);
- ReflectionHelpers.setField(mFragment, "mBackgroundUsage", backgroundPref);
- final Preference foregroundPref = mock(Preference.class);
- ReflectionHelpers.setField(mFragment, "mForegroundUsage", foregroundPref);
- final Preference totalPref = mock(Preference.class);
- ReflectionHelpers.setField(mFragment, "mTotalUsage", totalPref);
- final SpinnerPreference cycle = mock(SpinnerPreference.class);
- ReflectionHelpers.setField(mFragment, "mCycle", cycle);
-
- mFragment.bindData(0 /* position */);
-
- verify(cycle).setVisible(true);
- verify(totalPref).setSummary(
- DataUsageUtils.formatDataUsage(context, backgroundBytes + foregroundBytes));
- verify(backgroundPref).setSummary(DataUsageUtils.formatDataUsage(context, backgroundBytes));
- verify(foregroundPref).setSummary(DataUsageUtils.formatDataUsage(context, foregroundBytes));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
index ce58ae2..0f9aed1 100644
--- a/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/ChartDataUsagePreferenceTest.java
@@ -18,17 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.content.Context;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkStatsHistory.Entry;
import android.util.SparseIntArray;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.UsageView;
+import com.android.settingslib.net.NetworkCycleChartData;
+import com.android.settingslib.net.NetworkCycleData;
import org.junit.Before;
import org.junit.Test;
@@ -37,14 +35,20 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class ChartDataUsagePreferenceTest {
- private static final long MILLIS_IN_ONE_HOUR = 60 * 60 * 1000;
- private static final long MILLIS_IN_ONE_DAY = 24 * MILLIS_IN_ONE_HOUR;
- private static final long TIMESTAMP_NOW = Integer.MAX_VALUE;
+ // 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 NetworkStatsHistory mNetworkStatsHistory;
+ private List<NetworkCycleData> mNetworkCycleData;
+ private NetworkCycleChartData mNetworkCycleChartData;
private Context mContext;
private ChartDataUsagePreference mPreference;
@@ -54,79 +58,119 @@
mContext = RuntimeEnvironment.application;
mPreference = new ChartDataUsagePreference(mContext, null);
- mNetworkStatsHistory = spy(new NetworkStatsHistory(MILLIS_IN_ONE_HOUR, 10));
- addTestNetworkEntries();
- mPreference.setNetworkStats(mNetworkStatsHistory);
}
@Test
- public void calcPoints_notStartOfData_shouldAddDataPointsOnly() {
- final long start = TIMESTAMP_NOW - 20 * MILLIS_IN_ONE_DAY;
- final long end = TIMESTAMP_NOW - 5 * MILLIS_IN_ONE_DAY;
- mPreference.setVisibleRange(start, end);
- when(mNetworkStatsHistory.getIndexAfter(start)).thenReturn(2);
- when(mNetworkStatsHistory.getIndexAfter(end)).thenReturn(7);
+ public void calcPoints_dataAvailableFromCycleStart_shouldAddDataPointsOnly() {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor<SparseIntArray> pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
+ createTestNetworkData();
+ mPreference.setNetworkCycleData(mNetworkCycleChartData);
- mPreference.calcPoints(usageView);
+ 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);
}
@Test
- public void calcPoints_startOfData_shouldIndicateStartOfData() {
- final long start = TIMESTAMP_NOW - 20 * MILLIS_IN_ONE_DAY;
- final long end = TIMESTAMP_NOW - 5 * MILLIS_IN_ONE_DAY;
- mPreference.setVisibleRange(start, end);
- when(mNetworkStatsHistory.getIndexAfter(start)).thenReturn(0);
- when(mNetworkStatsHistory.getIndexAfter(end)).thenReturn(5);
+ public void calcPoints_dataNotAvailableAtCycleStart_shouldIndicateStartOfData() {
final UsageView usageView = mock(UsageView.class);
final ArgumentCaptor<SparseIntArray> pointsCaptor =
ArgumentCaptor.forClass(SparseIntArray.class);
+ createTestNetworkData();
+ mPreference.setNetworkCycleData(mNetworkCycleChartData);
- mPreference.calcPoints(usageView);
+ 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);
}
- private void addTestNetworkEntries() {
- // create 10 arbitary network data
- mNetworkStatsHistory.setValues(0, createEntry(1521583200000L, 743823454L, 16574289L));
- mNetworkStatsHistory.setValues(1, createEntry(1521586800000L, 64396L, 160364L));
- mNetworkStatsHistory.setValues(2, createEntry(1521590400000L, 2832L, 5299L));
- mNetworkStatsHistory.setValues(3, createEntry(1521655200000L, 83849690L, 3558238L));
- mNetworkStatsHistory.setValues(4, createEntry(1521658800000L, 1883657L, 353330L));
- mNetworkStatsHistory.setValues(5, createEntry(1521662400000L, 705259L, 279065L));
- mNetworkStatsHistory.setValues(6, createEntry(1521666000000L, 216169L, 155302L));
- mNetworkStatsHistory.setValues(7, createEntry(1521669600000L, 6069175L, 427581L));
- mNetworkStatsHistory.setValues(8, createEntry(1521673200000L, 120389L, 110807L));
- mNetworkStatsHistory.setValues(9, createEntry(1521676800000L, 29947L, 73257L));
+ @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));
}
- /**
- * Create a network entry to be used to calculate the usage chart. In the calculation, we only
- * need bucketStart, total bytes (rx + tx), and bucketDuration (which is set when we create
- * the NetworkStatsHistory object). Other fields are ignored, so we don't initialize here.
- *
- * @param start the timestamp when this entry begins
- * @param rx the total number of received bytes
- * @param tx the total number of transmitted bytes
- * @return the network entry with the corresponding start time and data usage
- */
- private Entry createEntry(long start, long rx, long tx) {
- Entry entry = new Entry();
- entry.bucketStart = start;
- entry.rxBytes = rx;
- entry.txBytes = tx;
- return entry;
+ private void createTestNetworkData() {
+ mNetworkCycleData = new ArrayList<>();
+ // create 10 arbitrary network data
+ mNetworkCycleData.add(createNetworkCycleData(1521583200000L, 1521586800000L, 743823454L));
+ mNetworkCycleData.add(createNetworkCycleData(1521586800000L, 1521590400000L, 64396L));
+ mNetworkCycleData.add(createNetworkCycleData(1521590400000L, 1521655200000L, 2832L));
+ mNetworkCycleData.add(createNetworkCycleData(1521655200000L, 1521658800000L, 83849690L));
+ mNetworkCycleData.add(createNetworkCycleData(1521658800000L, 1521662400000L, 1883657L));
+ mNetworkCycleData.add(createNetworkCycleData(1521662400000L, 1521666000000L, 705259L));
+ mNetworkCycleData.add(createNetworkCycleData(1521666000000L, 1521669600000L, 216169L));
+ mNetworkCycleData.add(createNetworkCycleData(1521669600000L, 1521673200000L, 6069175L));
+ mNetworkCycleData.add(createNetworkCycleData(1521673200000L, 1521676800000L, 120389L));
+ mNetworkCycleData.add(createNetworkCycleData(1521676800000L, 1521678800000L, 29947L));
+
+ final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
+ builder.setUsageBuckets(mNetworkCycleData)
+ .setStartTime(TIMESTAMP_START)
+ .setEndTime(TIMESTAMP_END);
+ mNetworkCycleChartData = builder.build();
+ }
+
+ private NetworkCycleData createNetworkCycleData(long start, long end, long usage) {
+ return new NetworkCycleData.Builder()
+ .setStartTime(start).setEndTime(end).setTotalUsage(usage).build();
}
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index acd00fd..7a10d70 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -26,13 +26,11 @@
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.provider.Settings;
-import androidx.fragment.app.FragmentActivity;
-import androidx.preference.PreferenceManager;
-
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.NetworkPolicyEditor;
@@ -45,6 +43,9 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.util.ReflectionHelpers;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceManager;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class DataUsageListTest {
@@ -98,6 +99,18 @@
}
@Test
+ public void processArgument_shouldGetNetworkTypeFromArgument() {
+ final Bundle args = new Bundle();
+ args.putInt(DataUsageList.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_WIFI);
+ args.putInt(DataUsageList.EXTRA_SUB_ID, 3);
+ mDataUsageList.setArguments(args);
+
+ mDataUsageList.processArgument();
+
+ assertThat(mDataUsageList.mNetworkType).isEqualTo(ConnectivityManager.TYPE_WIFI);
+ }
+
+ @Test
public void processArgument_fromIntent_shouldGetTemplateFromIntent() {
final FragmentActivity activity = mock(FragmentActivity.class);
final Intent intent = new Intent();
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListV2Test.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListV2Test.java
deleted file mode 100644
index f561a05..0000000
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListV2Test.java
+++ /dev/null
@@ -1,127 +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.datausage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.provider.Settings;
-
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.NetworkPolicyEditor;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.util.ReflectionHelpers;
-
-import androidx.fragment.app.FragmentActivity;
-import androidx.preference.PreferenceManager;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class DataUsageListV2Test {
-
- @Mock
- private CellDataPreference.DataStateListener mListener;
- @Mock
- private TemplatePreference.NetworkServices mNetworkServices;
- @Mock
- private Context mContext;
- private DataUsageListV2 mDataUsageList;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- FakeFeatureFactory.setupForTest();
- mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class);
- mDataUsageList = spy(DataUsageListV2.class);
-
- doReturn(mContext).when(mDataUsageList).getContext();
- ReflectionHelpers.setField(mDataUsageList, "mDataStateListener", mListener);
- ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
- }
-
- @Test
- public void resumePause_shouldListenUnlistenDataStateChange() {
- ReflectionHelpers.setField(
- mDataUsageList, "mVisibilityLoggerMixin", mock(VisibilityLoggerMixin.class));
- ReflectionHelpers.setField(
- mDataUsageList, "mPreferenceManager", mock(PreferenceManager.class));
-
- mDataUsageList.onResume();
-
- verify(mListener).setListener(true, mDataUsageList.mSubId, mContext);
-
- mDataUsageList.onPause();
-
- verify(mListener).setListener(false, mDataUsageList.mSubId, mContext);
- }
-
- @Test
- public void processArgument_shouldGetTemplateFromArgument() {
- final Bundle args = new Bundle();
- args.putParcelable(DataUsageListV2.EXTRA_NETWORK_TEMPLATE, mock(NetworkTemplate.class));
- args.putInt(DataUsageListV2.EXTRA_SUB_ID, 3);
- mDataUsageList.setArguments(args);
-
- mDataUsageList.processArgument();
-
- assertThat(mDataUsageList.mTemplate).isNotNull();
- assertThat(mDataUsageList.mSubId).isEqualTo(3);
- }
-
- @Test
- public void processArgument_shouldGetNetworkTypeFromArgument() {
- final Bundle args = new Bundle();
- args.putInt(DataUsageListV2.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_WIFI);
- args.putInt(DataUsageListV2.EXTRA_SUB_ID, 3);
- mDataUsageList.setArguments(args);
-
- mDataUsageList.processArgument();
-
- assertThat(mDataUsageList.mNetworkType).isEqualTo(ConnectivityManager.TYPE_WIFI);
- }
-
- @Test
- public void processArgument_fromIntent_shouldGetTemplateFromIntent() {
- final FragmentActivity activity = mock(FragmentActivity.class);
- final Intent intent = new Intent();
- intent.putExtra(Settings.EXTRA_NETWORK_TEMPLATE, mock(NetworkTemplate.class));
- intent.putExtra(Settings.EXTRA_SUB_ID, 3);
- when(activity.getIntent()).thenReturn(intent);
- doReturn(activity).when(mDataUsageList).getActivity();
-
- mDataUsageList.processArgument();
-
- assertThat(mDataUsageList.mTemplate).isNotNull();
- assertThat(mDataUsageList.mSubId).isEqualTo(3);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
index 9a67df8..4bd584e 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java
@@ -29,9 +29,7 @@
import android.net.ConnectivityManager;
import android.telephony.TelephonyManager;
import android.util.DataUnit;
-import android.util.FeatureFlagUtils;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -102,7 +100,6 @@
@Test
public void hasEthernet_shouldQueryEthernetSummaryForUser() throws Exception {
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_V2, true);
when(mManager.isNetworkSupported(anyInt())).thenReturn(true);
final String subscriber = "TestSub";
when(mTelephonyManager.getSubscriberId()).thenReturn(subscriber);
diff --git a/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java
deleted file mode 100644
index 03837c2..0000000
--- a/tests/robotests/src/com/android/settings/development/AngleEnabledAppPreferenceControllerTest.java
+++ /dev/null
@@ -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));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index d2c9b65..5eb21bd 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -28,10 +28,15 @@
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.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;
@@ -179,6 +186,29 @@
}
@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);
doReturn(controller).when(mDashboard)
@@ -264,6 +294,18 @@
}
}
+ @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
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java
index 983621c..a966417 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/PrivateVolumeOptionMenuControllerTest.java
@@ -64,6 +64,7 @@
MockitoAnnotations.initMocks(this);
when(mVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
+ when(mVolumeInfo.isMountedWritable()).thenReturn(true);
when(mPrimaryInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mMenu.findItem(anyInt())).thenReturn(mMigrateMenuItem);
when(mMigrateMenuItem.getItemId()).thenReturn(100);
@@ -82,6 +83,7 @@
@Test
public void testMigrateDataIsNotVisibleNormally() {
when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mPrimaryInfo);
+ when(mPrimaryInfo.isMountedWritable()).thenReturn(true);
mController.onCreateOptionsMenu(mMenu, mMenuInflater);
mController.onPrepareOptionsMenu(mMenu);
@@ -100,6 +102,17 @@
}
@Test
+ public void testMigrateDataIsNotVisibleWhenExternalVolumeIsNotMounted() {
+ when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);
+ when(mVolumeInfo.isMountedWritable()).thenReturn(false);
+
+ mController.onCreateOptionsMenu(mMenu, mMenuInflater);
+ mController.onPrepareOptionsMenu(mMenu);
+
+ verify(mMigrateMenuItem).setVisible(false);
+ }
+
+ @Test
public void testMigrateDataGoesToMigrateWizard() {
when(mPm.getPrimaryStorageCurrentVolume()).thenReturn(mVolumeInfo);
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
index 859912a..57f0ebb 100644
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
@@ -209,6 +209,7 @@
@Test
public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() {
+ when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
doNothing().when(mFragment).addPreferencesFromResource(anyInt());
doNothing().when(mFragment).updateCandidates();
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
index f1d03c7..f7a61c8 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
@@ -28,6 +28,7 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.drawer.CategoryKey;
import org.junit.Before;
import org.junit.Test;
@@ -59,7 +60,7 @@
assertThat(mSettings.getMetricsCategory())
.isEqualTo(MetricsEvent.ENTERPRISE_PRIVACY_SETTINGS);
assertThat(mSettings.getLogTag()).isEqualTo("EnterprisePrivacySettings");
- assertThat(mSettings.getCategoryKey()).isNull();
+ assertThat(mSettings.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ENTERPRISE_PRIVACY);
assertThat(mSettings.getPreferenceScreenResId())
.isEqualTo(R.xml.enterprise_privacy_settings);
}
diff --git a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
similarity index 94%
rename from tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
index 56a84bb..4af5754 100644
--- a/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/flashlight/FlashlightSliceTest.java
@@ -42,7 +42,7 @@
@RunWith(SettingsRobolectricTestRunner.class)
-public class FlashlightSliceBuilderTest {
+public class FlashlightSliceTest {
private Context mContext;
@@ -58,7 +58,7 @@
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();
diff --git a/tests/robotests/src/com/android/settings/gestures/GesturesSettingsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/GesturesSettingsPreferenceControllerTest.java
index d8f800d..e892eb2 100644
--- a/tests/robotests/src/com/android/settings/gestures/GesturesSettingsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/GesturesSettingsPreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.gestures;
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
@@ -81,7 +83,7 @@
});
ReflectionHelpers.setField(mController, "mGestureControllers", mControllers);
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
index 08631f7..b3f9411 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -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.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 @@
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 @@
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());
+ }
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 4f50197..98943a0 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -162,7 +162,7 @@
cards.add(new ContextualCard.Builder()
.setName("test_connected")
.setCardType(ContextualCard.CardType.SLICE)
- .setSliceUri(CustomSliceRegistry.CONNECTED_DEVICE_SLICE_URI)
+ .setSliceUri(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI)
.build());
cards.add(new ContextualCard.Builder()
.setName("test_gesture")
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
index bb61c7d..25689e6 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionContextualCardRendererTest.java
@@ -58,7 +58,7 @@
final ActivityController<Activity> activityController = Robolectric.buildActivity(
Activity.class);
mActivity = activityController.get();
- mActivity.setTheme(R.style.Theme_AppCompat);
+ mActivity.setTheme(R.style.Theme_Settings_Home);
activityController.create();
mRenderer = new ConditionContextualCardRenderer(mActivity, mControllerRendererPool);
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionHeaderContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionHeaderContextualCardRendererTest.java
index d0b5a24..ee8a582 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionHeaderContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/ConditionHeaderContextualCardRendererTest.java
@@ -60,7 +60,7 @@
final ActivityController<Activity> activityController = Robolectric.buildActivity(
Activity.class);
mActivity = activityController.get();
- mActivity.setTheme(R.style.Theme_AppCompat);
+ mActivity.setTheme(R.style.Theme_Settings_Home);
activityController.create();
mRenderer = new ConditionHeaderContextualCardRenderer(mActivity, mControllerRendererPool);
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java
index 2618e1b..c337df1 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/legacysuggestion/LegacySuggestionContextualCardRendererTest.java
@@ -59,7 +59,7 @@
final ActivityController<Activity> activityController = Robolectric.buildActivity(
Activity.class);
mActivity = activityController.get();
- mActivity.setTheme(R.style.Theme_AppCompat);
+ mActivity.setTheme(R.style.Theme_Settings_Home);
activityController.create();
mRenderer = new LegacySuggestionContextualCardRenderer(mActivity, mControllerRendererPool);
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
new file mode 100644
index 0000000..ac6557e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.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;
+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;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import org.junit.After;
+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 java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class BluetoothDevicesSliceTest {
+
+ private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
+ private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
+
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+
+ private List<CachedBluetoothDevice> mBluetoothDeviceList;
+ private BluetoothDevicesSlice mBluetoothDevicesSlice;
+ private Context mContext;
+ private IconCompat mIcon;
+ private PendingIntent mDetailIntent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+
+ mBluetoothDevicesSlice = spy(new BluetoothDevicesSlice(mContext));
+
+ // Mock the icon and detail intent of Bluetooth.
+ mIcon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
+ mDetailIntent = PendingIntent.getActivity(mContext, 0, new Intent("test action"), 0);
+ doReturn(mIcon).when(mBluetoothDevicesSlice).getBluetoothDeviceIcon(any());
+ doReturn(mDetailIntent).when(mBluetoothDevicesSlice).getBluetoothDetailIntent(any());
+
+ // Initial Bluetooth device list.
+ mBluetoothDeviceList = new ArrayList<>();
+ }
+
+ @After
+ public void tearDown() {
+ if (!mBluetoothDeviceList.isEmpty()) {
+ mBluetoothDeviceList.clear();
+ }
+ }
+
+ @Test
+ public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
+ mockBluetoothDeviceList();
+ doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+ final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+ final List<SliceItem> sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.bluetooth_devices));
+ }
+
+ @Test
+ public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
+ mockBluetoothDeviceList();
+ doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+ final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+ final List<SliceItem> sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems, BLUETOOTH_MOCK_TITLE);
+ }
+
+ @Test
+ public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
+ mockBluetoothDeviceList();
+ doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+ final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+ final List<SliceItem> sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems,
+ mContext.getString(R.string.bluetooth_pairing_pref_title));
+ }
+
+ @Test
+ public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
+ doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+ final Slice slice = mBluetoothDevicesSlice.getSlice();
+
+ final List<SliceItem> sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_bluetooth_devices));
+ }
+
+ @Test
+ public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
+ doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+
+ final Slice slice = mBluetoothDevicesSlice.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_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
+ doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
+ mBluetoothDeviceList.add(mCachedBluetoothDevice);
+ }
+
+ private boolean hasTitle(SliceMetadata metadata, String title) {
+ final CharSequence sliceTitle = metadata.getTitle();
+ return TextUtils.equals(sliceTitle, title);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
deleted file mode 100644
index 23da127..0000000
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ConnectedDeviceSliceTest.java
+++ /dev/null
@@ -1,99 +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.homepage.contextualcards.slices;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-
-import androidx.core.graphics.drawable.IconCompat;
-import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-import androidx.slice.SliceProvider;
-import androidx.slice.widget.SliceLiveData;
-
-import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.SliceTester;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-
-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 java.util.ArrayList;
-import java.util.List;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class ConnectedDeviceSliceTest {
-
- @Mock
- private CachedBluetoothDevice mCachedBluetoothDevice;
-
- private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
- private Context mContext;
- private ConnectedDeviceSlice mConnectedDeviceSlice;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
-
- // Set-up specs for SliceMetadata.
- SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
-
- mConnectedDeviceSlice = spy(new ConnectedDeviceSlice(mContext));
- }
-
- @Test
- public void getSlice_hasConnectedDevices_shouldBeCorrectSliceContent() {
- final String title = "BluetoothTitle";
- final String summary = "BluetoothSummary";
- final IconCompat icon = IconCompat.createWithResource(mContext,
- R.drawable.ic_homepage_connected_device);
- final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
- new Intent("test action"), 0);
- doReturn(title).when(mCachedBluetoothDevice).getName();
- doReturn(summary).when(mCachedBluetoothDevice).getConnectionSummary();
- mCachedDevices.add(mCachedBluetoothDevice);
- doReturn(mCachedDevices).when(mConnectedDeviceSlice).getBluetoothConnectedDevices();
- doReturn(icon).when(mConnectedDeviceSlice).getConnectedDeviceIcon(any());
- doReturn(pendingIntent).when(mConnectedDeviceSlice).getBluetoothDetailIntent(any());
- final Slice slice = mConnectedDeviceSlice.getSlice();
-
- final List<SliceItem> sliceItems = slice.getItems();
- SliceTester.assertTitle(sliceItems, title);
- }
-
- @Test
- public void getSlice_hasNoConnectedDevices_shouldReturnCorrectHeader() {
- final List<CachedBluetoothDevice> connectedBluetoothList = new ArrayList<>();
- doReturn(connectedBluetoothList).when(mConnectedDeviceSlice).getBluetoothConnectedDevices();
- final Slice slice = mConnectedDeviceSlice.getSlice();
-
- final List<SliceItem> sliceItems = slice.getItems();
- SliceTester.assertTitle(sliceItems, mContext.getString(R.string.no_connected_devices));
- }
-}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
index 0be55d9..9787aee 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
@@ -16,6 +16,8 @@
package com.android.settings.homepage.contextualcards.slices;
+import static android.app.slice.Slice.HINT_ERROR;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -66,7 +68,7 @@
@Test
@Config(shadows = ShadowPrivateStorageInfo.class)
- public void getSlice_hasLowStorage_shouldBeCorrectSliceContent() {
+ public void getSlice_lowStorage_shouldHaveStorageFreeTitle() {
ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(10L, 100L));
final Slice slice = mLowStorageSlice.getSlice();
@@ -77,12 +79,33 @@
@Test
@Config(shadows = ShadowPrivateStorageInfo.class)
- public void getSlice_hasNoLowStorage_shouldBeNull() {
+ public void getSlice_lowStorage_shouldNotHaveErrorHint() {
+ ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(10L, 100L));
+
+ final Slice slice = mLowStorageSlice.getSlice();
+
+ assertThat(slice.hasHint(HINT_ERROR)).isFalse();
+ }
+
+ @Test
+ @Config(shadows = ShadowPrivateStorageInfo.class)
+ public void getSlice_storageFree_shouldHaveStorageSettingsTitle() {
ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(100L, 100L));
final Slice slice = mLowStorageSlice.getSlice();
- assertThat(slice).isNull();
+ final List<SliceItem> sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_settings));
+ }
+
+ @Test
+ @Config(shadows = ShadowPrivateStorageInfo.class)
+ public void getSlice_storageFree_shouldHaveErrorHint() {
+ ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(100L, 100L));
+
+ final Slice slice = mLowStorageSlice.getSlice();
+
+ assertThat(slice.hasHint(HINT_ERROR)).isTrue();
}
@Implements(PrivateStorageInfo.class)
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
index abfddbb..7d71302 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.app.Activity;
@@ -51,10 +52,14 @@
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceContextualCardRendererTest {
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
@Mock
private LiveData<Slice> mSliceLiveData;
@Mock
private ControllerRendererPool mControllerRendererPool;
+ @Mock
+ private SliceContextualCardController mController;
private Activity mActivity;
private SliceContextualCardRenderer mRenderer;
@@ -66,7 +71,7 @@
final ActivityController<Activity> activityController = Robolectric.buildActivity(
Activity.class);
mActivity = activityController.get();
- mActivity.setTheme(R.style.Theme_AppCompat);
+ mActivity.setTheme(R.style.Theme_Settings_Home);
activityController.create();
mLifecycleOwner = new ContextualCardsFragment();
mRenderer = new SliceContextualCardRenderer(mActivity, mLifecycleOwner,
@@ -75,10 +80,9 @@
@Test
public void bindView_shouldSetScrollableToFalse() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
assertThat(
((SliceContextualCardRenderer.SliceViewHolder) viewHolder).sliceView.isScrollable
@@ -87,7 +91,7 @@
@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));
@@ -99,64 +103,124 @@
@Test
public void bindView_newSliceLiveData_shouldAddDataToMap() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
-
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
assertThat(mRenderer.mSliceLiveDataMap.size()).isEqualTo(1);
}
@Test
public void bindView_sliceLiveDataShouldObserveSliceView() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
-
- assertThat(mRenderer.mSliceLiveDataMap.get(sliceUri).hasObservers()).isTrue();
+ assertThat(mRenderer.mSliceLiveDataMap.get(TEST_SLICE_URI).hasObservers()).isTrue();
}
@Test
public void bindView_sliceLiveDataShouldRemoveObservers() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
- mRenderer.mSliceLiveDataMap.put(sliceUri, mSliceLiveData);
+ mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData);
- mRenderer.bindView(getSliceViewHolder(), buildContextualCard(sliceUri));
+ mRenderer.bindView(getSliceViewHolder(), buildContextualCard(TEST_SLICE_URI));
verify(mSliceLiveData).removeObservers(mLifecycleOwner);
}
@Test
public void longClick_shouldFlipCard() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
final View dismissalView = viewHolder.itemView.findViewById(R.id.dismissal_view);
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
- assertThat(card).isNotNull();
card.performLongClick();
assertThat(viewFlipper.getCurrentView()).isEqualTo(dismissalView);
}
@Test
+ public void longClick_shouldAddViewHolderToSet() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+
+ assertThat(mRenderer.mFlippedCardSet).contains(viewHolder);
+ }
+
+ @Test
public void viewClick_keepCard_shouldFlipBackToSlice() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
final View card = viewHolder.itemView.findViewById(R.id.slice_view);
final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
- mRenderer.bindView(viewHolder, buildContextualCard(sliceUri));
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
- assertThat(card).isNotNull();
card.performLongClick();
- assertThat(btnKeep).isNotNull();
btnKeep.performClick();
assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
}
+ @Test
+ public void viewClick_keepCard_shouldRemoveViewHolderFromSet() {
+ final RecyclerView.ViewHolder viewHolder = getSliceViewHolder();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final Button btnKeep = viewHolder.itemView.findViewById(R.id.keep);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+ btnKeep.performClick();
+
+ assertThat(mRenderer.mFlippedCardSet).doesNotContain(viewHolder);
+ }
+
+ @Test
+ public void viewClick_removeCard_shouldRemoveViewHolderFromSet() {
+ 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.bindView(viewHolder, contextualCard);
+ doReturn(mController).when(mControllerRendererPool).getController(mActivity,
+ ContextualCard.CardType.SLICE);
+
+ card.performLongClick();
+ btnRemove.performClick();
+
+ 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();
+ final View card = viewHolder.itemView.findViewById(R.id.slice_view);
+ final ViewFlipper viewFlipper = viewHolder.itemView.findViewById(R.id.viewFlipper);
+ mRenderer.bindView(viewHolder, buildContextualCard(TEST_SLICE_URI));
+
+ card.performLongClick();
+ mRenderer.onStop();
+
+ assertThat(viewFlipper.getCurrentView()).isInstanceOf(SliceView.class);
+ }
+
private RecyclerView.ViewHolder getSliceViewHolder() {
final int viewType = mRenderer.getViewType(false /* isHalfWidth */);
final RecyclerView recyclerView = new RecyclerView(mActivity);
@@ -166,10 +230,11 @@
return mRenderer.createViewHolder(view);
}
- private ContextualCard buildContextualCard(String sliceUri) {
+ private ContextualCard buildContextualCard(Uri sliceUri) {
return new ContextualCard.Builder()
.setName("test_name")
- .setSliceUri(Uri.parse(sliceUri))
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(sliceUri)
.build();
}
}
diff --git a/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
index e25b226..994a8fd 100644
--- a/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationScanningPreferenceControllerTest.java
@@ -18,7 +18,11 @@
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 @@
@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();
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
similarity index 93%
rename from tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
rename to tests/robotests/src/com/android/settings/location/LocationSliceTest.java
index ecbf858..8f1045a 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
@@ -24,7 +24,7 @@
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
-public class LocationSliceBuilderTest {
+public class LocationSliceTest {
private Context mContext;
@@ -38,7 +38,7 @@
@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();
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
new file mode 100644
index 0000000..02e4024
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -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);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
new file mode 100644
index 0000000..88ea2ea
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionsChangeListenerTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.AdditionalMatchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.network.SubscriptionsChangeListener.SubscriptionsChangeListenerClient;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class SubscriptionsChangeListenerTest {
+
+ @Mock
+ private SubscriptionsChangeListenerClient mClient;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+
+ private Context mContext;
+ private SubscriptionsChangeListener mListener;
+ private Uri mAirplaneModeUri;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+
+ mAirplaneModeUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
+ }
+
+ private void initListener(boolean alsoStart) {
+ mListener = new SubscriptionsChangeListener(mContext, mClient);
+ if (alsoStart) {
+ mListener.start();
+ }
+ }
+
+ @Test
+ public void whenStartNotCalled_noListeningWasSetup() {
+ final ContentResolver contentResolver = mock(ContentResolver.class);
+ when(mContext.getContentResolver()).thenReturn(contentResolver);
+ initListener(false);
+ verify(contentResolver, never()).registerContentObserver(any(Uri.class), anyBoolean(),
+ any(ContentObserver.class));
+ verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener(any());
+ verify(mContext, never()).registerReceiver(any(), any());
+ }
+
+ @Test
+ public void onSubscriptionsChangedEvent_subscriptionManagerFires_eventDeliveredToUs() {
+ initListener(true);
+ final ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> captor =
+ ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
+ verify(mSubscriptionManager).addOnSubscriptionsChangedListener(captor.capture());
+ captor.getValue().onSubscriptionsChanged();
+ verify(mClient).onSubscriptionsChanged();
+ }
+
+ @Test
+ public void onSubscriptionsChangedEvent_radioTechnologyChangedBroadcast_eventDeliveredToUs() {
+ initListener(true);
+ final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(), any());
+ broadcastReceiverCaptor.getValue().onReceive(mContext, null);
+ verify(mClient).onSubscriptionsChanged();
+ }
+
+ @Test
+ public void onAirplaneModeChangedEvent_becameTrue_eventFires() {
+ initListener(true);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ mListener.onChange(false, mAirplaneModeUri);
+ verify(mClient).onAirplaneModeChanged(true);
+ assertThat(mListener.isAirplaneModeOn()).isTrue();
+ }
+
+ @Test
+ public void onAirplaneModeChangedEvent_becameFalse_eventFires() {
+ initListener(true);
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ mListener.onChange(false, mAirplaneModeUri);
+ verify(mClient).onAirplaneModeChanged(false);
+ assertThat(mListener.isAirplaneModeOn()).isFalse();
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
index 2fc3d98..e1ad93b 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataPreferenceControllerTest.java
@@ -20,6 +20,7 @@
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 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(
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
index ec50e2b..b431c0a 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeAutomaticRulesPreferenceControllerTest.java
@@ -16,13 +16,17 @@
package com.android.settings.notification;
-import static junit.framework.Assert.assertEquals;
-
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AutomaticZenRule;
-import android.app.NotificationManager;
import android.content.Context;
import android.provider.Settings;
@@ -31,161 +35,122 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class)
public class ZenModeAutomaticRulesPreferenceControllerTest {
- private static final String GENERIC_RULE_NAME = "test";
- private static final String DEFAULT_ID_1 = "DEFAULT_1";
- private static final String DEFAULT_ID_2 = "DEFAULT_2";
-
private ZenModeAutomaticRulesPreferenceController mController;
- private final List<String> mDefaultIds = Arrays.asList(DEFAULT_ID_1, DEFAULT_ID_2);
-
@Mock
private ZenModeBackend mBackend;
@Mock
- private NotificationManager mNotificationManager;
- @Mock
private PreferenceCategory mockPref;
@Mock
- private NotificationManager.Policy mPolicy;
- @Mock
private PreferenceScreen mPreferenceScreen;
-
+ @Mock
+ private ZenRulePreference mZenRulePreference;
private Context mContext;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- ShadowApplication shadowApplication = ShadowApplication.getInstance();
- shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
-
mContext = RuntimeEnvironment.application;
- when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
- mController = new ZenModeAutomaticRulesPreferenceController(mContext, mock(Fragment.class),
- mock(Lifecycle.class));
-
+ mController = spy(new ZenModeAutomaticRulesPreferenceController(mContext, mock(Fragment.class),
+ null));
ReflectionHelpers.setField(mController, "mBackend", mBackend);
- ReflectionHelpers.setField(mController, "mDefaultRuleIds", mDefaultIds);
-
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
mockPref);
mController.displayPreference(mPreferenceScreen);
+ doReturn(mZenRulePreference).when(mController).createZenRulePreference(any());
}
@Test
- public void updateState_checkRuleOrderingDescending() {
- final int NUM_RULES = 4;
- when(mNotificationManager.getAutomaticZenRules()).thenReturn(
- mockAutoZenRulesDecreasingCreationTime(NUM_RULES));
+ public void testUpdateState_clearsPreferencesWhenAddingNewPreferences() {
+ final int NUM_RULES = 3;
+ Map<String, AutomaticZenRule> rMap = new HashMap<>();
- Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
- assertEquals(NUM_RULES, rules.length);
+ String ruleId1 = "test1_id";
+ String ruleId2 = "test2_id";
+ String ruleId3 = "test3_id";
- // check ordering, most recent should be at the bottom/end (ie higher creation time)
- for (int i = 0; i < NUM_RULES; i++) {
- assertEquals(GENERIC_RULE_NAME + (NUM_RULES - 1 - i), rules[i].getKey());
- }
+ AutomaticZenRule autoRule1 = new AutomaticZenRule("test_rule_1", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10);
+ AutomaticZenRule autoRule2 = new AutomaticZenRule("test_rule_2", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 20);
+ AutomaticZenRule autoRule3 = new AutomaticZenRule("test_rule_3", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 30);
+
+ rMap.put(ruleId1, autoRule1);
+ rMap.put(ruleId2, autoRule2);
+ rMap.put(ruleId3, autoRule3);
+
+ // should add 3 new preferences to mockPref
+ mockGetAutomaticZenRules(NUM_RULES, rMap);
+ mController.updateState(mockPref);
+ verify(mockPref, times(1)).removeAll();
+ verify(mockPref, times(NUM_RULES)).addPreference(any());
}
@Test
- public void updateState_checkRuleOrderingAscending() {
- final int NUM_RULES = 4;
- when(mNotificationManager.getAutomaticZenRules()).thenReturn(
- mockAutoZenRulesAscendingCreationTime(NUM_RULES));
+ public void testUpdateState_clearsPreferencesWhenRemovingPreferences(){
+ final int NUM_RULES = 2;
+ Map<String, AutomaticZenRule> rMap = new HashMap<>();
- Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
- assertEquals(NUM_RULES, rules.length);
+ String ruleId1 = "test1_id";
+ String ruleId2 = "test2_id";
- // check ordering, most recent should be at the bottom/end (ie higher creation time)
- for (int i = 0; i < NUM_RULES; i++) {
- assertEquals(GENERIC_RULE_NAME + i, rules[i].getKey());
- }
+ AutomaticZenRule autoRule1 = new AutomaticZenRule("test_rule_1", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10);
+ AutomaticZenRule autoRule2 = new AutomaticZenRule("test_rule_2", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 20);
+
+ rMap.put(ruleId1, autoRule1);
+ rMap.put(ruleId2, autoRule2);
+
+ // update state should re-add all preferences since a preference was deleted
+ when(mockPref.getPreferenceCount()).thenReturn(NUM_RULES + 2);
+ mockGetAutomaticZenRules(NUM_RULES, rMap);
+ mController.updateState(mockPref);
+ verify(mockPref, times(1)).removeAll();
+ verify(mockPref, times(NUM_RULES)).addPreference(any());
}
@Test
- public void updateState_checkRuleOrderingDescending_withDefaultRules() {
- final int NUM_RULES = 4;
+ public void testUpdateState_updateEnableState() throws NoSuchFieldException {
+ final int NUM_RULES = 1;
+ Map<String, AutomaticZenRule> rMap = new HashMap<>();
+ String testId = "test1_id";
+ AutomaticZenRule rule = new AutomaticZenRule("rule_name", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10);
+ rMap.put(testId, rule);
- Map<String, AutomaticZenRule> ruleMap = mockAutoZenRulesDecreasingCreationTime(NUM_RULES);
- ruleMap.put(DEFAULT_ID_2, new AutomaticZenRule("DEFAULT_1_NAME", null,
- null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 20));
- ruleMap.put(DEFAULT_ID_1, new AutomaticZenRule("DEFAULT_1_NAME", null,
- null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10));
- when(mNotificationManager.getAutomaticZenRules()).thenReturn(ruleMap);
+ when(mockPref.getPreferenceCount()).thenReturn(NUM_RULES);
+ when(mockPref.getPreference(anyInt())).thenReturn(mZenRulePreference);
- Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
- assertEquals(NUM_RULES + 2, rules.length);
-
- assertEquals(rules[0].getKey(), DEFAULT_ID_1);
- assertEquals(rules[1].getKey(), DEFAULT_ID_2);
- // NON-DEFAULT RULES check ordering, most recent at the bottom/end
- for (int i = 0; i < NUM_RULES; i++) {
- assertEquals(GENERIC_RULE_NAME + (NUM_RULES - 1 - i), rules[i + 2].getKey());
- }
+ // update state should NOT re-add all the preferences, should only update enable state
+ rule.setEnabled(false);
+ rMap.put(testId, rule);
+ mockGetAutomaticZenRules(NUM_RULES, rMap);
+ FieldSetter.setField(mZenRulePreference, ZenRulePreference.class.getDeclaredField("mId"), testId);
+ mController.updateState(mockPref);
+ verify(mZenRulePreference, times(1)).updatePreference(any());
+ verify(mController, never()).reloadAllRules(any());
}
- @Test
- public void updateState_checkRuleOrderingMix() {
- final int NUM_RULES = 4;
- // map with creation times: 0, 2, 4, 6
- Map<String,AutomaticZenRule> rMap = mockAutoZenRulesAscendingCreationTime(NUM_RULES);
-
- final String insertedRule1 = "insertedRule1";
- rMap.put(insertedRule1, new AutomaticZenRule(insertedRule1, null, null,
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 5));
-
- final String insertedRule2 = "insertedRule2";
- rMap.put(insertedRule2, new AutomaticZenRule(insertedRule2, null, null,
- Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 3));
-
- // rule map with rule creation times, 0, 2, 4, 6, 5, 3
- // sort should create ordering based on creation times: 0, 2, 3, 4, 5, 6
- when(mNotificationManager.getAutomaticZenRules()).thenReturn(rMap);
-
- Map.Entry<String, AutomaticZenRule>[] rules = mController.sortedRules();
- assertEquals(NUM_RULES + 2, rules.length); // inserted 2 rules
-
- // check ordering of inserted rules
- assertEquals(insertedRule1, rules[4].getKey());
- assertEquals(insertedRule2, rules[2].getKey());
- }
-
- private Map<String, AutomaticZenRule> mockAutoZenRulesAscendingCreationTime(int numRules) {
- Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
-
- for (int i = 0; i < numRules; i++) {
- ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
- null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, i * 2));
- }
-
- return ruleMap;
- }
-
- private Map<String, AutomaticZenRule> mockAutoZenRulesDecreasingCreationTime(int numRules) {
- Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
-
- for (int i = 0; i < numRules; i++) {
- ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
- null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, numRules - i));
- }
-
- return ruleMap;
+ private void mockGetAutomaticZenRules(int numRules, Map<String, AutomaticZenRule> rules) {
+ Map.Entry<String, AutomaticZenRule>[] arr = new Map.Entry[numRules];
+ rules.entrySet().toArray(arr);
+ when(mBackend.getAutomaticZenRules()).thenReturn(arr);
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java
new file mode 100644
index 0000000..94a3c01
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeBackendTest.java
@@ -0,0 +1,108 @@
+package com.android.settings.notification;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.app.AutomaticZenRule;
+import android.provider.Settings;
+import android.service.notification.ZenModeConfig;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeBackendTest {
+
+ private static final String GENERIC_RULE_NAME = "test";
+ private static final String DEFAULT_ID_1 = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
+ private static final String DEFAULT_ID_2 = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
+
+ @Test
+ public void updateState_checkRuleOrderingDescending() {
+ final int NUM_RULES = 4;
+ Map.Entry<String, AutomaticZenRule>[] rules = populateAutoZenRulesDescendingCreationTime(
+ NUM_RULES, false);
+ Arrays.sort(rules, ZenModeBackend.RULE_COMPARATOR);
+
+ // check ordering, most recent should be at the end
+ for (int i = 0; i < NUM_RULES; i++) {
+ assertEquals(GENERIC_RULE_NAME + (NUM_RULES - 1 - i), rules[i].getKey());
+ }
+ }
+
+ @Test
+ public void updateState_checkRuleOrderingAscending() {
+ final int NUM_RULES = 4;
+ Map.Entry<String, AutomaticZenRule>[] rules = populateAutoZenRulesAscendingCreationTime(
+ NUM_RULES, false);
+ Arrays.sort(rules, ZenModeBackend.RULE_COMPARATOR);
+
+ // check ordering, most recent should be at the end
+ for (int i = 0; i < NUM_RULES; i++) {
+ assertEquals(GENERIC_RULE_NAME + i, rules[i].getKey());
+ }
+ }
+
+ @Test
+ public void updateState_checkRuleOrderingDescending_withDefaultRules() {
+ final int NUM_RULES = 4;
+
+ Map.Entry<String, AutomaticZenRule>[] rules = populateAutoZenRulesDescendingCreationTime(NUM_RULES,
+ true);
+ Arrays.sort(rules, ZenModeBackend.RULE_COMPARATOR);
+
+ assertEquals(rules[0].getKey(), DEFAULT_ID_1);
+ assertEquals(rules[1].getKey(), DEFAULT_ID_2);
+ // NON-DEFAULT RULES check ordering, most recent at the bottom/end
+ for (int i = 0; i < NUM_RULES; i++) {
+ assertEquals(GENERIC_RULE_NAME + (NUM_RULES - 1 - i), rules[i + 2].getKey());
+ }
+ }
+
+ private Map.Entry<String, AutomaticZenRule>[] populateAutoZenRulesAscendingCreationTime(
+ int numRules, boolean addDefaultRules) {
+ Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+
+ for (int i = 0; i < numRules; i++) {
+ ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, i * 2));
+ }
+
+ if (addDefaultRules) {
+ ruleMap.put(DEFAULT_ID_1, new AutomaticZenRule("DEFAULT_1_NAME", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 20));
+ ruleMap.put(DEFAULT_ID_2, new AutomaticZenRule("DEFAULT_2_NAME", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10));
+ }
+
+ Map.Entry<String, AutomaticZenRule>[] toReturn = new Map.Entry[ruleMap.size()];
+ ruleMap.entrySet().toArray(toReturn);
+ return toReturn;
+ }
+
+ private Map.Entry<String, AutomaticZenRule>[] populateAutoZenRulesDescendingCreationTime(
+ int numRules, boolean addDefaultRules) {
+ Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+
+ for (int i = 0; i < numRules; i++) {
+ ruleMap.put(GENERIC_RULE_NAME + i, new AutomaticZenRule(GENERIC_RULE_NAME + i, null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, numRules - i));
+ }
+
+ if (addDefaultRules) {
+ ruleMap.put(DEFAULT_ID_1, new AutomaticZenRule("DEFAULT_1_NAME", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 10));
+ ruleMap.put(DEFAULT_ID_2, new AutomaticZenRule("DEFAULT_2_NAME", null,
+ null, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, true, 20));
+ }
+
+ Map.Entry<String, AutomaticZenRule>[] toReturn = new Map.Entry[ruleMap.size()];
+ ruleMap.entrySet().toArray(toReturn);
+ return toReturn;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
index 36a1382..7131250 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModePriorityCallsPreferenceControllerTest.java
@@ -30,6 +30,9 @@
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.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 @@
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 @@
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 @@
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
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
index 75605a4..7b6698d 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModePriorityMessagesPreferenceControllerTest.java
@@ -30,6 +30,9 @@
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.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 @@
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 @@
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 @@
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
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
index c1634fb..ca9f942 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsFooterPreferenceControllerTest.java
@@ -126,7 +126,7 @@
}
@Test
- public void app_manualRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_app_manualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
injectManualRuleFromApp();
mController.updateState(mockPref);
@@ -137,7 +137,7 @@
}
@Test
- public void time_manualRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_time_manualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
String placeholder = "placeholder";
injectManualRuleWithTimeCountdown(1000, placeholder);
@@ -148,7 +148,7 @@
}
@Test
- public void forever_manualRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_forever_manualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
injectManualRuleWithIndefiniteEnd();
mController.updateState(mockPref);
@@ -158,7 +158,7 @@
}
@Test
- public void automaticRule_noManualRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_automaticRule_noManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
// no manual rule
ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, null);
@@ -174,7 +174,7 @@
}
@Test
- public void manualRuleEndsLast_hasAutomaticRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_manualRuleEndsLast_hasAutomaticRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
// manual rule that ends after automatic rule ends
injectManualRuleWithIndefiniteEnd();
@@ -190,7 +190,7 @@
}
@Test
- public void automaticRuleEndsLast_hasManualRule_setFooterTitle() {
+ public void testDefaultNotifPolicy_automaticRuleEndsLast_hasManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
// manual rule that ends before automatic rule ends
injectManualRuleWithTimeCountdown(1000, "");
@@ -208,14 +208,15 @@
}
@Test
- public void multipleAutomaticRules_appAutoRuleautomaticRuleApp_setFooterTitle() {
+ public void testDefaultNotifPolicy_multipleAutomaticRules_autoRuleApp_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
// automatic rule that ends after manual rule ends
ZenRule rule1 = injectNewAutomaticRule(TEST_RULE_NAME + "1", false, false);
when(mConfigWrapper.parseAutomaticRuleEndTime(rule1.conditionId)).thenReturn(10000L);
- ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true, true);
+ // automatic rule that is an app
+ injectNewAutomaticRule(TEST_RULE_NAME + "2", true, true);
ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", true, false);
when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(9000L);
@@ -229,7 +230,7 @@
}
@Test
- public void multipleAutomaticRules_setFooterTitle() {
+ public void testDefaultNotifPolicy_multipleAutomaticRules_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
// automatic rule that ends after manual rule ends
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
index 4fc7d57..53032ac 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java
@@ -71,20 +71,20 @@
@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 @@
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
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
index 9b29d48..cf344d2 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
@@ -61,7 +61,6 @@
mFakePanelContent = new FakePanelContent();
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
-
ActivityController<FakeSettingsPanelActivity> activityController =
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
activityController.setup();
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
index bfd7863..02a7d0a 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
@@ -54,7 +54,13 @@
public void setUp() {
mContext = RuntimeEnvironment.application;
- final ActivityController<FakeSettingsPanelActivity> activityController =
+ mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
+ mFakePanelContent = new FakePanelContent();
+ doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
+
+ ActivityController<FakeSettingsPanelActivity> activityController =
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
activityController.setup();
@@ -65,12 +71,6 @@
.getSupportFragmentManager()
.findFragmentById(R.id.main_content));
- mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
- mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
- mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
- mFakePanelContent = new FakePanelContent();
- doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
-
mAdapter = new PanelSlicesAdapter(mPanelFragment, mFakePanelContent.getSlices());
}
diff --git a/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java
new file mode 100644
index 0000000..21019d3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.panel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class VolumePanelTest {
+
+ private VolumePanel mPanel;
+
+ @Before
+ public void setUp() {
+ mPanel = VolumePanel.create(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getSlices_containsNecessarySlices() {
+ final List<Uri> uris = mPanel.getSlices();
+
+ assertThat(uris).containsExactly(
+ CustomSliceRegistry.VOLUME_CALL_URI,
+ CustomSliceRegistry.VOLUME_MEDIA_URI,
+ CustomSliceRegistry.VOLUME_RINGER_URI,
+ CustomSliceRegistry.VOLUME_ALARM_URI);
+ }
+
+ @Test
+ public void getSeeMoreIntent_notNull() {
+ assertThat(mPanel.getSeeMoreIntent()).isNotNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 2e2104b..821d383 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -218,6 +218,19 @@
}
@Test
+ public void getDynamicSummary_allowDynamicSummary_nullSummary_returnsNull() {
+ final SliceData data = getDummyData(true /*isDynamicSummaryAllowed*/);
+ final FakePreferenceController controller = spy(
+ new FakePreferenceController(mContext, KEY));
+ final String controllerSummary = null;
+ doReturn(controllerSummary).when(controller).getSummary();
+
+ final CharSequence summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);
+
+ assertThat(summary).isNull();
+ }
+
+ @Test
public void getDynamicSummary_returnsScreenTitle() {
final SliceData data = getDummyData();
final FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
@@ -492,6 +505,19 @@
assertThat(actualIconResource).isEqualTo(settingsIcon);
}
+ @Test
+ public void getSafeIcon_invalidResource_shouldFallbackToSettingsIcon() {
+ final int settingsIcon = R.drawable.ic_settings;
+ final int badIcon = 0x12345678;
+ final SliceData data = getDummyData(TOGGLE_CONTROLLER, SliceData.SliceType.SWITCH,
+ badIcon);
+
+ final IconCompat actualIcon = SliceBuilderUtils.getSafeIcon(mContext, data);
+
+ final int actualIconResource = actualIcon.toIcon().getResId();
+ assertThat(actualIconResource).isEqualTo(settingsIcon);
+ }
+
private SliceData getDummyData() {
return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
ICON, IS_DYNAMIC_SUMMARY_ALLOWED);
diff --git a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java b/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
index 9417e9c..74914f4 100644
--- a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
+++ b/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
@@ -84,6 +84,8 @@
paths.add(new ResourcePath(null,
Fs.fromURL(new URL("file:frameworks/base/packages/SettingsLib/SearchWidget/res/")), null));
paths.add(new ResourcePath(null,
+ Fs.fromURL(new URL("file:frameworks/base/packages/SettingsLib/ActionButtonsPreference/res")), null));
+ paths.add(new ResourcePath(null,
Fs.fromURL(new URL("file:frameworks/base/packages/SettingsLib/SettingsLayoutPreference/res")), null));
paths.add(new ResourcePath(null,
Fs.fromURL(new URL("file:frameworks/base/core/res/res")), null));
diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
index be4199d..c0ffdcd 100644
--- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java
+++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java
@@ -110,8 +110,6 @@
final SliceAction mainToggleAction = toggles.get(0);
- final IconCompat expectedToggleIcon = IconCompat.createWithResource(context,
- sliceData.getIconResource());
assertThat(mainToggleAction.getIcon()).isNull();
// Check intent in Toggle Action
@@ -238,6 +236,7 @@
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) {
@@ -257,6 +256,7 @@
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(","))
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
index f11d9e8..e0576b2 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRuntimePermissionPresenter.java
@@ -17,7 +17,7 @@
package com.android.settings.testutils.shadow;
import android.content.Context;
-import android.content.pm.permission.RuntimePermissionPresenter;
+import android.permission.RuntimePermissionPresenter;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
diff --git a/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java
deleted file mode 100644
index 34a9872..0000000
--- a/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2017 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 static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.preference.PreferenceViewHolder;
-
-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.robolectric.RuntimeEnvironment;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public class ActionButtonPreferenceTest {
-
- private Context mContext;
- private View mRootView;
- private ActionButtonPreference mPref;
- private PreferenceViewHolder mHolder;
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mRootView = View.inflate(mContext, R.layout.settings_action_buttons, null /* parent */);
- mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
- mPref = new ActionButtonPreference(mContext);
- }
-
- @Test
- public void onBindViewHolder_setTitle_shouldShowButtonByDefault() {
- mPref.setButton1Text(R.string.settings_label);
- mPref.setButton2Text(R.string.settings_label);
- mPref.setButton3Text(R.string.settings_label);
- mPref.setButton4Text(R.string.settings_label);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setIcon_shouldShowButtonByDefault() {
- mPref.setButton1Icon(R.drawable.ic_settings);
- mPref.setButton2Icon(R.drawable.ic_settings);
- mPref.setButton3Icon(R.drawable.ic_settings);
- mPref.setButton4Icon(R.drawable.ic_settings);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_notSetTitleOrIcon_shouldNotShowButtonByDefault() {
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.GONE);
- }
-
- @Test
- public void onBindViewHolder_setVisibleIsGoneAndSetTitle_shouldNotShowButton() {
- mPref.setButton1Text(R.string.settings_label).setButton1Visible(false);
- mPref.setButton2Text(R.string.settings_label).setButton2Visible(false);
- mPref.setButton3Text(R.string.settings_label).setButton3Visible(false);
- mPref.setButton4Text(R.string.settings_label).setButton4Visible(false);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.GONE);
- }
-
- @Test
- public void onBindViewHolder_setVisibleIsGoneAndSetIcon_shouldNotShowButton() {
- mPref.setButton1Icon(R.drawable.ic_settings).setButton1Visible(false);
- mPref.setButton2Icon(R.drawable.ic_settings).setButton2Visible(false);
- mPref.setButton3Icon(R.drawable.ic_settings).setButton3Visible(false);
- mPref.setButton4Icon(R.drawable.ic_settings).setButton4Visible(false);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.GONE);
- }
-
- @Test
- public void onBindViewHolder_setVisibility_shouldUpdateButtonVisibility() {
- mPref.setButton1Text(R.string.settings_label).setButton1Visible(false);
- mPref.setButton2Text(R.string.settings_label).setButton2Visible(false);
- mPref.setButton3Text(R.string.settings_label).setButton3Visible(false);
- mPref.setButton4Text(R.string.settings_label).setButton4Visible(false);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.GONE);
-
- mPref.setButton1Visible(true);
- mPref.setButton2Visible(true);
- mPref.setButton3Visible(true);
- mPref.setButton4Visible(true);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button2).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button3).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button4).getVisibility())
- .isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setEnabled_shouldEnableButton() {
- mPref.setButton1Enabled(true);
- mPref.setButton2Enabled(false);
- mPref.setButton3Enabled(true);
- mPref.setButton4Enabled(false);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1).isEnabled()).isTrue();
- assertThat(mRootView.findViewById(R.id.button2).isEnabled()).isFalse();
- assertThat(mRootView.findViewById(R.id.button3).isEnabled()).isTrue();
- assertThat(mRootView.findViewById(R.id.button4).isEnabled()).isFalse();
- }
-
- @Test
- public void onBindViewHolder_setText_shouldShowSameText() {
- mPref.setButton1Text(R.string.settings_label);
- mPref.setButton2Text(R.string.settings_label);
- mPref.setButton3Text(R.string.settings_label);
- mPref.setButton4Text(R.string.settings_label);
-
- mPref.onBindViewHolder(mHolder);
-
- assertThat(((Button) mRootView.findViewById(R.id.button1)).getText())
- .isEqualTo(mContext.getText(R.string.settings_label));
- assertThat(((Button) mRootView.findViewById(R.id.button2)).getText())
- .isEqualTo(mContext.getText(R.string.settings_label));
- assertThat(((Button) mRootView.findViewById(R.id.button3)).getText())
- .isEqualTo(mContext.getText(R.string.settings_label));
- assertThat(((Button) mRootView.findViewById(R.id.button4)).getText())
- .isEqualTo(mContext.getText(R.string.settings_label));
- }
-
- @Test
- public void onBindViewHolder_setButtonIcon_iconMustDisplayAboveText() {
- mPref.setButton1Text(R.string.settings_label);
- mPref.setButton1Icon(R.drawable.ic_settings);
-
- mPref.onBindViewHolder(mHolder);
- final Drawable[] drawablesAroundText =
- ((Button) mRootView.findViewById(R.id.button1))
- .getCompoundDrawables();
-
- assertThat(drawablesAroundText[1 /* top */]).isNotNull();
- }
-
- @Test
- public void setButtonIcon_iconResourceIdIsZero_shouldNotDisplayIcon() {
- mPref.setButton1Text(R.string.settings_label);
- mPref.setButton1Icon(0);
-
- mPref.onBindViewHolder(mHolder);
- final Drawable[] drawablesAroundText =
- ((Button) mRootView.findViewById(R.id.button1))
- .getCompoundDrawables();
-
- assertThat(drawablesAroundText[1 /* top */]).isNull();
- }
-
- @Test
- public void setButtonIcon_iconResourceIdNotExisting_shouldNotDisplayIconAndCrash() {
- mPref.setButton1Text(R.string.settings_label);
- mPref.setButton1Icon(999999999 /* not existing id */);
- // Should not crash here
- mPref.onBindViewHolder(mHolder);
- final Drawable[] drawablesAroundText =
- ((Button) mRootView.findViewById(R.id.button1))
- .getCompoundDrawables();
-
- assertThat(drawablesAroundText[1 /* top */]).isNull();
- }
-
- public static ActionButtonPreference createMock() {
- final ActionButtonPreference pref = mock(ActionButtonPreference.class);
- when(pref.setButton1Text(anyInt())).thenReturn(pref);
- when(pref.setButton1Icon(anyInt())).thenReturn(pref);
- when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
- when(pref.setButton1Visible(anyBoolean())).thenReturn(pref);
- when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
-
- when(pref.setButton2Text(anyInt())).thenReturn(pref);
- when(pref.setButton2Icon(anyInt())).thenReturn(pref);
- when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
- when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
- when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
-
- when(pref.setButton3Text(anyInt())).thenReturn(pref);
- when(pref.setButton3Icon(anyInt())).thenReturn(pref);
- when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref);
- when(pref.setButton3Visible(anyBoolean())).thenReturn(pref);
- when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
-
- when(pref.setButton4Text(anyInt())).thenReturn(pref);
- when(pref.setButton4Icon(anyInt())).thenReturn(pref);
- when(pref.setButton4Enabled(anyBoolean())).thenReturn(pref);
- when(pref.setButton4Visible(anyBoolean())).thenReturn(pref);
- when(pref.setButton4OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
- return pref;
- }
-}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
new file mode 100644
index 0000000..6acc4d9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/FloatingAppBarScrollingViewBehaviorTest.java
@@ -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);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
index 64352d9..55d212f 100644
--- a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java
@@ -18,6 +18,7 @@
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.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;
@@ -99,6 +102,26 @@
}
@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);
}
diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
index e12053c..91598c0 100644
--- a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
@@ -33,6 +33,7 @@
@RunWith(SettingsRobolectricTestRunner.class)
public class CellularFallbackPreferenceControllerTest {
+ private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@@ -42,7 +43,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new CellularFallbackPreferenceController(mContext);
+ mController = new CellularFallbackPreferenceController(mContext, KEY_CELLULAR_FALLBACK);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index 2e806dd..8cf02b8 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -17,6 +17,7 @@
package com.android.settings.wifi;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -32,213 +33,220 @@
import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.os.Bundle;
import android.widget.Button;
+
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
+
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.wifi.AccessPoint;
+
import java.util.ArrayList;
import java.util.List;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
import org.robolectric.shadows.ShadowLooper;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class})
public class NetworkRequestDialogFragmentTest {
- final String KEY_SSID = "key_ssid";
+ final String KEY_SSID = "key_ssid";
- private FragmentActivity mActivity;
- private NetworkRequestDialogFragment networkRequestDialogFragment;
- private Context mContext;
+ private FragmentActivity mActivity;
+ private NetworkRequestDialogFragment networkRequestDialogFragment;
+ private Context mContext;
- @Before
- public void setUp() {
- mActivity = Robolectric.setupActivity(FragmentActivity.class);
- networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
- mContext = spy(RuntimeEnvironment.application);
- }
-
- @Test
- public void display_shouldShowTheDialog() {
- networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
- AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(alertDialog).isNotNull();
- assertThat(alertDialog.isShowing()).isTrue();
- }
-
- @Test
- public void clickPositiveButton_shouldCloseTheDialog() {
- networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
- AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(alertDialog.isShowing()).isTrue();
-
- Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- assertThat(positiveButton).isNotNull();
-
- positiveButton.performClick();
- assertThat(alertDialog.isShowing()).isFalse();
- }
-
- @Test
- public void onResumeAndWaitTimeout_shouldCallTimeoutDialog() {
- FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
- FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
- spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
-
- assertThat(fakeFragment.bCalledStopAndPop).isFalse();
-
- ShadowLooper.getShadowMainLooper().runToEndOfTasks();
-
- assertThat(fakeFragment.bCalledStopAndPop).isTrue();
- }
-
- class FakeNetworkRequestDialogFragment extends NetworkRequestDialogFragment {
- boolean bCalledStopAndPop = false;
-
- @Override
- public void stopScanningAndPopTimeoutDialog() {
- bCalledStopAndPop = true;
+ @Before
+ public void setUp() {
+ mActivity = Robolectric.setupActivity(FragmentActivity.class);
+ networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
+ mContext = spy(RuntimeEnvironment.application);
}
- }
- @Test
- public void onResume_shouldRegisterCallback() {
- when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
- Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
- when(mContext.getApplicationContext()).thenReturn(applicationContext);
- WifiManager wifiManager = mock(WifiManager.class);
- when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
+ @Test
+ public void display_shouldShowTheDialog() {
+ networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog).isNotNull();
+ assertThat(alertDialog.isShowing()).isTrue();
+ }
- networkRequestDialogFragment.onResume();
+ @Test
+ public void clickPositiveButton_shouldCloseTheDialog() {
+ networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog.isShowing()).isTrue();
- verify(wifiManager).registerNetworkRequestMatchCallback(any(), any());
- }
+ Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ assertThat(positiveButton).isNotNull();
- @Test
- public void onPause_shouldUnRegisterCallback() {
- when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
- Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
- when(mContext.getApplicationContext()).thenReturn(applicationContext);
- WifiManager wifiManager = mock(WifiManager.class);
- when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
+ positiveButton.performClick();
+ assertThat(alertDialog.isShowing()).isFalse();
+ }
- networkRequestDialogFragment.onPause();
+ @Test
+ public void onResumeAndWaitTimeout_shouldCallTimeoutDialog() {
+ FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
+ FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
+ spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
- verify(wifiManager).unregisterNetworkRequestMatchCallback(networkRequestDialogFragment);
- }
+ assertThat(fakeFragment.bCalledStopAndPop).isFalse();
- @Test
- public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 3");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
+ ShadowLooper.getShadowMainLooper().runToEndOfTasks();
- when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
- networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ assertThat(fakeFragment.bCalledStopAndPop).isTrue();
+ }
- // Test if config would update list.
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "Test AP 3";
- networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
+ class FakeNetworkRequestDialogFragment extends NetworkRequestDialogFragment {
+ boolean bCalledStopAndPop = false;
- AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
- verify(accessPointList, times(1)).set(2, verifyAccessPoint);
- }
+ @Override
+ public void stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE type) {
+ bCalledStopAndPop = true;
+ }
+ }
- @Test
- public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 3");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
+ @Test
+ public void onResume_shouldRegisterCallback() {
+ when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
+ Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
+ when(mContext.getApplicationContext()).thenReturn(applicationContext);
+ WifiManager wifiManager = mock(WifiManager.class);
+ when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
- when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
- networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ networkRequestDialogFragment.onResume();
- // Test if config would update list.
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "Test AP 3";
- networkRequestDialogFragment.onUserSelectionConnectFailure(config);
+ verify(wifiManager).registerNetworkRequestMatchCallback(any(), any());
+ }
- AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
- verify(accessPointList, times(1)).set(2, verifyAccessPoint);
- }
+ @Test
+ public void onPause_shouldUnRegisterCallback() {
+ when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
+ Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
+ when(mContext.getApplicationContext()).thenReturn(applicationContext);
+ WifiManager wifiManager = mock(WifiManager.class);
+ when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
- @Test
- public void onUserSelectionCallbackRegistration_shouldCallSelect() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 3");
- AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
- accessPointList.add(clickedAccessPoint);
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
- when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
+ networkRequestDialogFragment.onPause();
- NetworkRequestUserSelectionCallback selectionCallback = mock(
- NetworkRequestUserSelectionCallback.class);
- AlertDialog dialog = mock(AlertDialog.class);
- networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);
+ verify(wifiManager).unregisterNetworkRequestMatchCallback(networkRequestDialogFragment);
+ }
- networkRequestDialogFragment.onClick(dialog, 2);
+ @Test
+ public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() {
+ List<AccessPoint> accessPointList = spy(new ArrayList<>());
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_SSID, "Test AP 1");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 2");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 3");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 4");
+ accessPointList.add(new AccessPoint(mContext, bundle));
- verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
- }
+ when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
+ networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
- @Test
- public void onMatch_shouldUpdatedList() {
- // Prepares WifiManager.
- when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
- Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
- when(mContext.getApplicationContext()).thenReturn(applicationContext);
- WifiManager wifiManager = mock(WifiManager.class);
- when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
+ // Test if config would update list.
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "Test AP 3";
+ networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
- List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
- WifiConfiguration config = new WifiConfiguration();
- final String SSID_AP1 = "Test AP 1";
- config.SSID = SSID_AP1;
- wifiConfigurationList.add(config);
- config = new WifiConfiguration();
- final String SSID_AP2 = "Test AP 2";
- config.SSID = SSID_AP2;
- wifiConfigurationList.add(config);
+ AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
+ verify(accessPointList, times(1)).set(2, verifyAccessPoint);
+ }
- // Prepares callback converted data.
- List<ScanResult> scanResults = new ArrayList<>();
- when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList);
+ @Test
+ public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() {
+ List<AccessPoint> accessPointList = spy(new ArrayList<>());
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_SSID, "Test AP 1");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 2");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 3");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 4");
+ accessPointList.add(new AccessPoint(mContext, bundle));
- networkRequestDialogFragment.onMatch(scanResults);
+ when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
+ networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
- List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList();
- assertThat(accessPointList).isNotEmpty();
- assertThat(accessPointList.size()).isEqualTo(2);
- assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1);
- assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2);
- }
+ // Test if config would update list.
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "Test AP 3";
+ networkRequestDialogFragment.onUserSelectionConnectFailure(config);
+
+ AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
+ verify(accessPointList, times(1)).set(2, verifyAccessPoint);
+ }
+
+ @Test
+ public void onUserSelectionCallbackRegistration_shouldCallSelect() {
+ List<AccessPoint> accessPointList = spy(new ArrayList<>());
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_SSID, "Test AP 1");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 2");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 3");
+ AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
+ accessPointList.add(clickedAccessPoint);
+ bundle.putString(KEY_SSID, "Test AP 4");
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
+
+ NetworkRequestUserSelectionCallback selectionCallback = mock(
+ NetworkRequestUserSelectionCallback.class);
+ AlertDialog dialog = mock(AlertDialog.class);
+ networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);
+
+ networkRequestDialogFragment.onClick(dialog, 2);
+
+ verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
+ }
+
+ @Test
+ public void onMatch_shouldUpdatedList() {
+ // Prepares WifiManager.
+ when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
+ Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
+ when(mContext.getApplicationContext()).thenReturn(applicationContext);
+ WifiManager wifiManager = mock(WifiManager.class);
+ when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
+
+ List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
+ WifiConfiguration config = new WifiConfiguration();
+ final String SSID_AP1 = "Test AP 1";
+ config.SSID = SSID_AP1;
+ wifiConfigurationList.add(config);
+ config = new WifiConfiguration();
+ final String SSID_AP2 = "Test AP 2";
+ config.SSID = SSID_AP2;
+ wifiConfigurationList.add(config);
+
+ // Prepares callback converted data.
+ List<ScanResult> scanResults = new ArrayList<>();
+ when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList);
+
+ networkRequestDialogFragment.onMatch(scanResults);
+
+ List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList();
+ assertThat(accessPointList).isNotEmpty();
+ assertThat(accessPointList.size()).isEqualTo(2);
+ assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1);
+ assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java
new file mode 100644
index 0000000..c6659a5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestErrorDialogFragmentTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.widget.Button;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class})
+public class NetworkRequestErrorDialogFragmentTest {
+
+ private FragmentActivity mActivity;
+ private NetworkRequestErrorDialogFragment mFragment;
+
+ @Before
+ public void setUp() {
+ mActivity = Robolectric.setupActivity(FragmentActivity.class);
+ mFragment = spy(NetworkRequestErrorDialogFragment.newInstance());
+ mFragment.show(mActivity.getSupportFragmentManager(), null);
+ }
+
+ @Test
+ public void display_shouldShowTimeoutDialog() {
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+
+ assertThat(alertDialog).isNotNull();
+ assertThat(alertDialog.isShowing()).isTrue();
+
+ ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
+ assertThat(RuntimeEnvironment.application
+ .getString(R.string.network_connection_timeout_dialog_message))
+ .isEqualTo(shadowAlertDialog.getMessage());
+ }
+
+ @Test
+ public void display_shouldShowAbortDialog() {
+ mFragment = spy(NetworkRequestErrorDialogFragment.newInstance());
+ Bundle bundle = new Bundle();
+ bundle.putSerializable(NetworkRequestErrorDialogFragment.DIALOG_TYPE,
+ ERROR_DIALOG_TYPE.ABORT);
+ mFragment.setArguments(bundle);
+ mFragment.show(mActivity.getSupportFragmentManager(), null);
+
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+
+ assertThat(alertDialog).isNotNull();
+ assertThat(alertDialog.isShowing()).isTrue();
+
+ ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
+ assertThat(RuntimeEnvironment.application
+ .getString(R.string.network_connection_errorstate_dialog_message))
+ .isEqualTo(shadowAlertDialog.getMessage());
+ }
+
+ @Test
+ public void clickPositiveButton_shouldCallStartScanningDialog() {
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog.isShowing()).isTrue();
+
+ Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ assertThat(positiveButton).isNotNull();
+
+ positiveButton.performClick();
+ verify(mFragment, times(1)).startScanningDialog();
+ }
+
+ @Test
+ public void clickNegativeButton_shouldCloseTheDialog() {
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog.isShowing()).isTrue();
+
+ Button negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
+ assertThat(negativeButton).isNotNull();
+
+ negativeButton.performClick();
+ assertThat(alertDialog.isShowing()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java
deleted file mode 100644
index ed28e60..0000000
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestTimeoutDialogFragmentTest.java
+++ /dev/null
@@ -1,90 +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.wifi;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.internal.verification.VerificationModeFactory.times;
-
-import android.content.DialogInterface;
-import android.widget.Button;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
-import com.android.settings.R;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class})
-public class NetworkRequestTimeoutDialogFragmentTest {
-
- private FragmentActivity mActivity;
- private NetworkRequestTimeoutDialogFragment mFragment;
-
- @Before
- public void setUp() {
- mActivity = Robolectric.setupActivity(FragmentActivity.class);
- mFragment = spy(NetworkRequestTimeoutDialogFragment.newInstance());
- mFragment.show(mActivity.getSupportFragmentManager(), null);
- }
-
- @Test
- public void display_shouldShowTheDialog() {
- AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-
- assertThat(alertDialog).isNotNull();
- assertThat(alertDialog.isShowing()).isTrue();
-
- ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
- assertThat(RuntimeEnvironment.application
- .getString(R.string.network_connection_timeout_dialog_message))
- .isEqualTo(shadowAlertDialog.getMessage());
- }
-
- @Test
- public void clickPositiveButton_shouldCallStartScanningDialog() {
- AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(alertDialog.isShowing()).isTrue();
-
- Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- assertThat(positiveButton).isNotNull();
-
- positiveButton.performClick();
- verify(mFragment, times(1)).startScanningDialog();
- }
-
- @Test
- public void clickNegativeButton_shouldCloseTheDialog() {
- AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(alertDialog.isShowing()).isTrue();
-
- Button negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
- assertThat(negativeButton).isNotNull();
-
- negativeButton.performClick();
- assertThat(alertDialog.isShowing()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
index 5ac25ed..cdd1664 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
@@ -53,14 +53,17 @@
private Context mContext;
+ private WifiManager mWifiManager;
private WifiSlice mWifiSlice;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
+ mWifiManager = mContext.getSystemService(WifiManager.class);
// Set-up specs for SliceMetadata.
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mWifiManager.setWifiEnabled(true);
mWifiSlice = new WifiSlice(mContext);
}
@@ -83,13 +86,30 @@
}
@Test
- public void getWifiSlice_noAp_shouldReturnPlaceholder() {
+ public void getWifiSlice_wifiOff_shouldReturnSingleRow() {
+ mWifiManager.setWifiEnabled(false);
+
final Slice wifiSlice = mWifiSlice.getSlice();
- int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+ final int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
null /* nonHints */).size();
+
+ // Title row
+ assertThat(rows).isEqualTo(1);
+ }
+
+ @Test
+ public void getWifiSlice_noAp_shouldReturnLoadingRow() {
+ final Slice wifiSlice = mWifiSlice.getSlice();
+
+ final int rows = SliceQuery.findAll(wifiSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+ null /* nonHints */).size();
+ final List<SliceItem> sliceItems = wifiSlice.getItems();
+
// All AP rows + title row
assertThat(rows).isEqualTo(DEFAULT_EXPANDED_ROW_COUNT + 1);
+ // Has scanning text
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_empty_list_wifi_on));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index d39b55f..eab9e51 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -17,12 +17,14 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
@@ -67,11 +69,10 @@
import com.android.settings.testutils.shadow.ShadowBidiFormatter;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
-import com.android.settings.widget.ActionButtonPreference;
-import com.android.settings.widget.ActionButtonPreferenceTest;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.widget.ActionButtonsPreference;
import com.android.settingslib.widget.LayoutPreference;
import com.android.settingslib.wifi.AccessPoint;
@@ -142,7 +143,7 @@
private ImageView mockHeaderIcon;
@Mock
- private ActionButtonPreference mockButtonsPref;
+ private ActionButtonsPreference mockButtonsPref;
@Mock
private Preference mockSignalStrengthPref;
@Mock
@@ -247,7 +248,7 @@
.thenReturn(mockNetworkInfo);
doNothing().when(mockConnectivityManager).registerNetworkCallback(
nullable(NetworkRequest.class), mCallbackCaptor.capture(), nullable(Handler.class));
- mockButtonsPref = ActionButtonPreferenceTest.createMock();
+ mockButtonsPref = createMock();
when(mockButtonsPref.setButton1OnClickListener(mForgetClickListener.capture()))
.thenReturn(mockButtonsPref);
@@ -849,4 +850,27 @@
verify(mockAccessPoint, times(2)).getLevel();
verify(mockIconInjector, times(2)).getIcon(anyInt());
}
+
+ private ActionButtonsPreference createMock() {
+ final ActionButtonsPreference pref = mock(ActionButtonsPreference.class);
+ when(pref.setButton1Text(anyInt())).thenReturn(pref);
+ when(pref.setButton1Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ when(pref.setButton2Text(anyInt())).thenReturn(pref);
+ when(pref.setButton2Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ when(pref.setButton3Text(anyInt())).thenReturn(pref);
+ when(pref.setButton3Icon(anyInt())).thenReturn(pref);
+ when(pref.setButton3Enabled(anyBoolean())).thenReturn(pref);
+ when(pref.setButton3Visible(anyBoolean())).thenReturn(pref);
+ when(pref.setButton3OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
+
+ return pref;
+ }
}
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 208c344..70e9587 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -35,43 +35,42 @@
new ActivityTestRule<>(WifiDppConfiguratorActivity.class);
@Test
- public void launchActivity_modeQrCodeScanner_shouldNotAutoFinish() {
- Intent intent = new Intent();
- intent.putExtra(WifiDppConfiguratorActivity.EXTRA_LAUNCH_MODE,
- WifiDppConfiguratorActivity.LaunchMode.LAUNCH_MODE_QR_CODE_SCANNER.getMode());
+ public void launchActivity_qrCodeScanner_shouldNotAutoFinish() {
+ Intent intent = new Intent(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WEP");
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
+
mActivityRule.launchActivity(intent);
assertThat(mActivityRule.getActivity().isFinishing()).isEqualTo(false);
}
@Test
- public void launchActivity_modeQrCodeGenerator_shouldNotAutoFinish() {
- Intent intent = new Intent();
- intent.putExtra(WifiDppConfiguratorActivity.EXTRA_LAUNCH_MODE,
- WifiDppConfiguratorActivity.LaunchMode.LAUNCH_MODE_QR_CODE_GENERATOR.getMode());
+ public void launchActivity_qrCodeGenerator_shouldNotAutoFinish() {
+ Intent intent = new Intent(
+ WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WEP");
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
+
mActivityRule.launchActivity(intent);
assertThat(mActivityRule.getActivity().isFinishing()).isEqualTo(false);
}
@Test
- public void launchActivity_modeChooseSavedWifiNetwork_shouldNotAutoFinish() {
- Intent intent = new Intent();
- intent.putExtra(WifiDppConfiguratorActivity.EXTRA_LAUNCH_MODE,
- WifiDppConfiguratorActivity.LaunchMode
- .LAUNCH_MODE_CHOOSE_SAVED_WIFI_NETWORK.getMode());
+ public void launchActivity_chooseSavedWifiNetwork_shouldNotAutoFinish() {
+ Intent intent = new Intent(
+ WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_CHOOSE_SAVED_WIFI_NETWORK);
+
mActivityRule.launchActivity(intent);
assertThat(mActivityRule.getActivity().isFinishing()).isEqualTo(false);
}
@Test
- public void launchActivity_noLaunchMode_shouldFinishActivityWithResultCodeCanceled() {
- // If we do not specify launch mode, the activity will finish itself right away
- Intent intent = new Intent();
- mActivityRule.launchActivity(intent);
+ public void testActivity_shouldImplementsWifiNetworkConfigRetriever() {
+ WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
- assertThat(mActivityRule.getActivityResult().getResultCode()).
- isEqualTo(Activity.RESULT_CANCELED);
+ assertThat(activity instanceof WifiNetworkConfig.Retriever).isEqualTo(true);
}
}
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragmentTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragmentTest.java
index c46db2c..98742ed 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragmentTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragmentTest.java
@@ -28,6 +28,8 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import com.android.settings.R;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -41,21 +43,13 @@
@Before
public void setUp() {
- Intent intent = new Intent();
- intent.putExtra(WifiDppConfiguratorActivity.EXTRA_LAUNCH_MODE,
- WifiDppConfiguratorActivity.LaunchMode.LAUNCH_MODE_QR_CODE_SCANNER.getMode());
+ Intent intent = new Intent(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SECURITY, "WEP");
+ intent.putExtra(WifiDppUtils.EXTRA_WIFI_SSID, "GoogleGuest");
mActivityRule.launchActivity(intent);
}
@Test
- public void leftButton_shouldFinishActivityWithResultCodeCanceled() {
- onView(withText("Cancel")).perform(click());
-
- assertThat(mActivityRule.getActivityResult().getResultCode()).
- isEqualTo(Activity.RESULT_CANCELED);
- }
-
- @Test
public void rotateScreen_shouldNotCrash() {
mActivityRule.getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);