Merge "Fix restricted fragment dialogs" into pi-dev
diff --git a/res/drawable/empty_search_results.xml b/res/drawable/empty_search_results.xml
deleted file mode 100644
index 9162107..0000000
--- a/res/drawable/empty_search_results.xml
+++ /dev/null
@@ -1,30 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="96dp"
- android:height="96dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
-
- <path
- android:fillColor="#000000"
- android:pathData="M15.5,14h-0.79l-0.28-0.27c1.2-1.4,1.82-3.31,1.48-5.34c-0.47-2.78-2.79-5-5.59-5.34c-4.23-0.52-7.79,3.04-7.27,7.27
-c0.34,2.8,2.56,5.12,5.34,5.59c2.03,0.34,3.94-0.28,5.34-1.48L14,14.71v0.79l5.2,5.19c0.41,0.41,1.07,0.41,1.48,0l0.01-0.01
-c0.41-0.41,0.41-1.07,0-1.48L15.5,14z M9.5,14C7.01,14,5,11.99,5,9.5S7.01,5,9.5,5S14,7.01,14,9.5S11.99,14,9.5,14z" />
-</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_find_device_disabled.xml b/res/drawable/ic_find_device_disabled.xml
index 273fe64..39d4fda 100644
--- a/res/drawable/ic_find_device_disabled.xml
+++ b/res/drawable/ic_find_device_disabled.xml
@@ -20,8 +20,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#F09300"
- android:pathData="M14,10.5v9.06C12.87,21,12,22,12,22S5,14.25,5,9A7,7,0,0,1,18.93,8H14.29A2.5,2.5,0,1,0,14,10.5ZM16,22h2V20H16Zm0-4h2V10H16Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM11,13h2v2h-2V13zM13,6h-2v5h2V6z"/>
</vector>
diff --git a/res/drawable/ic_find_device_enabled.xml b/res/drawable/ic_find_device_enabled.xml
index c9cc86e..16f0245 100644
--- a/res/drawable/ic_find_device_enabled.xml
+++ b/res/drawable/ic_find_device_enabled.xml
@@ -20,10 +20,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#4285F4"
- android:pathData="M12,2 C8.13400675,2 5,5.13400675 5,9 C5,14.25 12,22 12,22 C12,22 19,14.25 19,9
-C19,5.13400675 15.8659932,2 12,2 L12,2 Z M8.2,9.66 L9.61,8.24 L11,9.66
-L15.24,5.42 L16.65,6.83 L11,12.49 L8.2,9.66 Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9zM14.5,9c0,1.38 -1.12,2.5 -2.5,2.5S9.5,10.38 9.5,9s1.12,-2.5 2.5,-2.5S14.5,7.62 14.5,9z"/>
</vector>
diff --git a/res/drawable/ic_ota_update_available.xml b/res/drawable/ic_ota_update_available.xml
index be81ea8..2b0d82d 100644
--- a/res/drawable/ic_ota_update_available.xml
+++ b/res/drawable/ic_ota_update_available.xml
@@ -20,8 +20,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#F09300"
- android:pathData="M17,1H7A2,2,0,0,0,5,3V21a2,2,0,0,0,2,2H17a2,2,0,0,0,2-2V3A2,2,0,0,0,17,1Zm0,18H7V5H17Zm-1-6H13V8H11v5H8l4,4Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM16,12.5l-4,4l-4,-4l1.41,-1.41L11,12.67V8.5V8h2v0.5v4.17l1.59,-1.59L16,12.5z"/>
</vector>
diff --git a/res/drawable/ic_ota_update_current.xml b/res/drawable/ic_ota_update_current.xml
index e569774..e9b987a 100644
--- a/res/drawable/ic_ota_update_current.xml
+++ b/res/drawable/ic_ota_update_current.xml
@@ -20,8 +20,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#4285F4"
- android:pathData="M17,1H7A2,2,0,0,0,5,3V21a2,2,0,0,0,2,2H17a2,2,0,0,0,2-2V3A2,2,0,0,0,17,1ZM9.11,14.06h0l1.41,1.41,5.66-5.66-1.42-1.4-4.24,4.24L9.11,11.24,7.7,12.66ZM17,19H7V5H17Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16z"/>
</vector>
diff --git a/res/drawable/ic_ota_update_stale.xml b/res/drawable/ic_ota_update_stale.xml
index 57bd6d5..266920b 100644
--- a/res/drawable/ic_ota_update_stale.xml
+++ b/res/drawable/ic_ota_update_stale.xml
@@ -20,8 +20,6 @@
android:viewportHeight="24">
<path
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#F09300"
- android:pathData="M17,1a2,2,0,0,1,2,2V21a2,2,0,0,1-2,2H7a2,2,0,0,1-2-2V3A2,2,0,0,1,7,1Zm0,18V5H7V19ZM11,6.5h2v7H11Zm0,9h2v2H11Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
</vector>
diff --git a/res/drawable/ic_package_verifier_disabled.xml b/res/drawable/ic_package_verifier_disabled.xml
index fa148d1..9dfcb9d 100644
--- a/res/drawable/ic_package_verifier_disabled.xml
+++ b/res/drawable/ic_package_verifier_disabled.xml
@@ -14,20 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="22dp"
- android:height="22dp"
- android:viewportWidth="22"
- android:viewportHeight="22">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillColor="#F5A623"
- android:fillType="evenOdd"
- android:pathData="M20.5515334,2.919 C15.9049774,0.613 11,0 11,0 C11,0 6.09502262,0.613
-1.44846657,2.919 C1.15485168,4.149 1,5.432 1,6.752 C1,8.109 1.16490699,9.429
-1.47561589,10.693 C2.13624937,13.382 3.45852187,15.813 5.26143791,17.807
-C6.84313725,19.559 8.79788839,20.973 11,21.926 C13.2021116,20.973
-15.1568627,19.559 16.7395676,17.807 C18.5414781,15.813 19.8637506,13.382
-20.5253896,10.693 C20.835093,9.429 21,8.109 21,6.752 C21,5.432 20.8461538,4.149
-20.5515334,2.919 M12,15.5 L10,15.5 L10,13.5 L12,13.5 L12,15.5 L12,15.5 Z M12,12
-L10,12 L10,6 L12,6 L12,12 L12,12 Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/>
</vector>
diff --git a/res/drawable/ic_package_verifier_enabled.xml b/res/drawable/ic_package_verifier_enabled.xml
index b954258..670ede4 100644
--- a/res/drawable/ic_package_verifier_enabled.xml
+++ b/res/drawable/ic_package_verifier_enabled.xml
@@ -14,22 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="22dp"
- android:height="22dp"
- android:viewportWidth="22"
- android:viewportHeight="22">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillColor="#4285F4"
- android:fillType="evenOdd"
- android:pathData="M20.5515334,2.92885159 C20.8461538,4.16300283 21,5.45033294 21,6.77478792
-C21,8.13636778 20.835093,9.46082277 20.5253896,10.7290888 C19.8637506,13.4271641
-18.5414781,15.8663687 16.7395676,17.8670984 C15.1568627,19.6250114
-13.2021116,21.0437836 11,22 C8.79788839,21.0437836 6.84313725,19.6250114
-5.26143791,17.8670984 C3.45852187,15.8663687 2.13624937,13.4271641
-1.47561589,10.7290888 C1.16490699,9.46082277 1,8.13636778 1,6.77478792
-C1,5.45033294 1.15485168,4.16300283 1.44846657,2.92885159
-C6.09502262,0.615068868 11,0 11,0 C11,0 15.9049774,0.615068868
-20.5515334,2.92885159 Z M15.6984615,6 L9.61538462,12.2961783 L7,10
-L5.69846154,11.3471338 L9.61538462,15 L17,7.3566879 L15.6984615,6 Z" />
+ android:fillColor="#FF000000"
+ android:pathData="M11.14,16l-3.84,-3.84l1.41,-1.42l2.43,2.42l4.16,-4.16l1.42,1.41L11.14,16zM12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2z"/>
</vector>
diff --git a/res/drawable/ic_package_verifier_removed.xml b/res/drawable/ic_package_verifier_removed.xml
index e225ee5..66ad8ed 100644
--- a/res/drawable/ic_package_verifier_removed.xml
+++ b/res/drawable/ic_package_verifier_removed.xml
@@ -14,30 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="22dp"
- android:height="22dp"
- android:viewportWidth="22"
- android:viewportHeight="22">
-
- <group
- android:translateX="-1"
- android:translateY="-1">
- <path
- android:fillType="evenOdd"
- android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
- <path
- android:fillColor="#D84336"
- android:fillType="evenOdd"
- android:pathData="M21.5515334,3.92885159 C21.8461538,5.16300283 22,6.45033294 22,7.77478792
-C22,9.13636778 21.835093,10.4608228 21.5253896,11.7290888 C20.8637506,14.4271641
-19.5414781,16.8663687 17.7395676,18.8670984 C16.1568627,20.6250114
-14.2021116,22.0437836 12,23 C9.79788839,22.0437836 7.84313725,20.6250114
-6.26143791,18.8670984 C4.45852187,16.8663687 3.13624937,14.4271641
-2.47561589,11.7290888 C2.16490699,10.4608228 2,9.13636778 2,7.77478792
-C2,6.45033294 2.15485168,5.16300283 2.44846657,3.92885159 C7.09502262,1.61506887
-12,1 12,1 C12,1 16.9049774,1.61506887 21.5515334,3.92885159 Z M14.6469246,7
-L11.9600359,9.71972847 L9.272253,7 L8.00878156,8.28072408 L10.6956703,11.0004526
-L8,13.720181 L9.26347144,15 L11.9600359,12.2802715 L14.7347402,15 L16,13.720181
-L13.2252957,11.0004526 L15.9121844,8.28072408 L14.6469246,7 Z" />
- </group>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15.5,9.91L14.09,8.5L12,10.59L9.91,8.5L8.5,9.91L10.59,12L8.5,14.09l1.41,1.41L12,13.42l2.09,2.08l1.41,-1.41L13.42,12L15.5,9.91zM12,4.24l6,3v4.1c0,3.9 -2.55,7.5 -6,8.59c-3.45,-1.09 -6,-4.7 -6,-8.59v-4.1L12,4.24M12,2L4,6v5.33c0,4.93 3.41,9.55 8,10.67c4.59,-1.12 8,-5.73 8,-10.67V6L12,2L12,2z"/>
</vector>
diff --git a/res/layout-sw320dp/settings_entity_header.xml b/res/layout-sw320dp/settings_entity_header.xml
index 79e12a9..9a46adf 100644
--- a/res/layout-sw320dp/settings_entity_header.xml
+++ b/res/layout-sw320dp/settings_entity_header.xml
@@ -62,35 +62,22 @@
<TextView
android:id="@+id/install_type"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:visibility="gone"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content"/>
<TextView
android:id="@+id/entity_header_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content" />
<TextView
android:id="@+id/entity_header_second_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
diff --git a/res/layout/app_domains_item.xml b/res/layout/app_domains_item.xml
index 5aa9cfa..9583bce 100644
--- a/res/layout/app_domains_item.xml
+++ b/res/layout/app_domains_item.xml
@@ -23,4 +23,5 @@
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:paddingTop="8dp"
- android:paddingBottom="8dp" />
+ android:paddingBottom="8dp"
+ android:textAlignment="viewStart"/>
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
index f1b631e..2c94524 100644
--- a/res/layout/choose_lock_password.xml
+++ b/res/layout/choose_lock_password.xml
@@ -20,6 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:icon="@drawable/ic_lock"
+ android:importantForAutofill="noExcludeDescendants"
settings:suwFooter="@layout/choose_lock_password_footer"
settings:suwHeaderText="@string/lockpassword_choose_your_screen_lock_header">
diff --git a/res/layout/settings_entity_header.xml b/res/layout/settings_entity_header.xml
index b534c5e..6698f3f 100644
--- a/res/layout/settings_entity_header.xml
+++ b/res/layout/settings_entity_header.xml
@@ -55,36 +55,22 @@
<TextView
android:id="@+id/install_type"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:visibility="gone"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content" />
<TextView
android:id="@+id/entity_header_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content" />
<TextView
android:id="@+id/entity_header_second_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_height="wrap_content" />
</LinearLayout>
diff --git a/res/values/config.xml b/res/values/config.xml
index ec611f0..e3ec74f 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -128,4 +128,7 @@
doesn't interact well with scroll view -->
<bool name="config_lock_pattern_minimal_ui">true</bool>
+ <!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
+ <string-array name="config_settings_slices_accessibility_components" translatable="false"/>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7ba4715..2b850e8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9078,13 +9078,13 @@
<!-- Data usage remaining string [CHAR LIMIT=30] -->
<string name="data_used"><xliff:g name="bytes" example="2 GB">^1</xliff:g> used</string>
- <!-- Data usage remaining string [CHAR LIMIT=30] -->
+ <!-- Data usage remaining string [CHAR LIMIT=13] -->
<string name="data_used_formatted"><xliff:g name="value" example="500">^1</xliff:g> <xliff:g name="units" example="GB">^2</xliff:g> used</string>
- <!-- Data usage over limit string [CHAR LIMIT=30] -->
+ <!-- Data usage over limit string [CHAR LIMIT=13] -->
<string name="data_overusage"><xliff:g name="bytes" example="2 GB">^1</xliff:g> over</string>
- <!-- Optional part of data usage showing the remaining amount [CHAR LIMIT=30] -->
+ <!-- Optional part of data usage showing the remaining amount [CHAR LIMIT=13] -->
<string name="data_remaining"><xliff:g name="bytes" example="2 GB">^1</xliff:g> left</string>
<!-- Informational text about time left in billing cycle [CHAR LIMIT=60] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 23ec207..6ca4715 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -423,6 +423,15 @@
<item name="android:textSize">16sp</item>
</style>
+ <style name="TextAppearance.EntityHeaderSummary"
+ parent="@android:style/TextAppearance.Material.Body1">
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:gravity">start</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ </style>
+
<style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored"/>
<style name="ActionSecondaryButton" parent="android:Widget.DeviceDefault.Button"/>
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index 5b371fa..1e9d97e 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -52,8 +52,7 @@
android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment"
android:key="bluetooth_settings"
android:title="@string/bluetooth_settings_title"
- android:icon="@drawable/ic_settings_bluetooth"
- settings:allowDividerAbove="true"/>
+ android:icon="@drawable/ic_settings_bluetooth"/>
<PreferenceCategory
android:key="dashboard_tile_placeholder" />
diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml
index 858cbaf..7519cef 100644
--- a/res/xml/security_dashboard_settings.xml
+++ b/res/xml/security_dashboard_settings.xml
@@ -41,7 +41,7 @@
<com.android.settings.widget.GearPreference
android:key="unlock_set_or_change"
android:title="@string/unlock_set_unlock_launch_picker_title"
- android:summary="@string/unlock_set_unlock_mode_none"
+ android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_lockscreen" />
<Preference
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index 7ba1c76..c079807 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -20,7 +20,7 @@
android:title="@string/sound_settings"
android:key="sound_settings"
settings:keywords="@string/keywords_sounds"
- settings:initialExpandedChildrenCount="8">
+ settings:initialExpandedChildrenCount="9">
<!-- Media volume -->
<com.android.settings.notification.VolumeSeekBarPreference
@@ -141,11 +141,6 @@
android:key="screen_locking_sounds"
android:title="@string/screen_locking_sounds_title" />
- <!-- Charging sounds -->
- <SwitchPreference
- android:key="charging_sounds"
- android:title="@string/charging_sounds_title" />
-
<!-- Docking sounds -->
<SwitchPreference
android:key="docking_sounds"
diff --git a/res/xml/zen_mode_block_settings.xml b/res/xml/zen_mode_block_settings.xml
index 63dbd47..cccc63c 100644
--- a/res/xml/zen_mode_block_settings.xml
+++ b/res/xml/zen_mode_block_settings.xml
@@ -24,15 +24,15 @@
android:title="@string/zen_mode_block_effects_screen_off"
android:key="zen_mode_block_screen_off">
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_intent"
android:title="@string/zen_mode_block_effect_intent" />
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_light"
android:title="@string/zen_mode_block_effect_light" />
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_ambient"
android:title="@string/zen_mode_block_effect_ambient" />
@@ -40,19 +40,19 @@
<PreferenceCategory
android:title="@string/zen_mode_block_effects_screen_on"
android:key="zen_mode_block_screen_on">
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_badge"
android:title="@string/zen_mode_block_effect_badge" />
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_status"
android:title="@string/zen_mode_block_effect_status" />
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_peek"
android:title="@string/zen_mode_block_effect_peek" />
- <CheckBoxPreference
+ <com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_list"
android:title="@string/zen_mode_block_effect_list" />
</PreferenceCategory>
diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml
index 385e8ff..717b6c5 100644
--- a/res/xml/zen_mode_settings.xml
+++ b/res/xml/zen_mode_settings.xml
@@ -25,7 +25,8 @@
<!-- sound vibration -->
<com.android.settings.widget.DisabledCheckBoxPreference
android:key="zen_effect_sound"
- android:title="@string/zen_mode_block_effect_sound" />
+ android:title="@string/zen_mode_block_effect_sound"
+ android:enabled="false"/>
<!-- What to block (effects) -->
<Preference
diff --git a/src/com/android/settings/EditPinPreference.java b/src/com/android/settings/EditPinPreference.java
index 3f992e9..4efed4a 100644
--- a/src/com/android/settings/EditPinPreference.java
+++ b/src/com/android/settings/EditPinPreference.java
@@ -57,6 +57,7 @@
if (editText != null) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER |
InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+ editText.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
}
}
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index fdec662..4bdd8e1 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -32,9 +32,11 @@
import android.os.RecoverySystem;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Telephony;
import android.support.annotation.VisibleForTesting;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -151,9 +153,20 @@
ImsManager.factoryReset(context);
restoreDefaultApn(context);
esimFactoryReset(context, context.getPackageName());
+ // There has been issues when Sms raw table somehow stores orphan
+ // fragments. They lead to garbled message when new fragments come
+ // in and combied with those stale ones. In case this happens again,
+ // user can reset all network settings which will clean up this table.
+ cleanUpSmsRawTable(context);
}
};
+ private void cleanUpSmsRawTable(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ Uri uri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
+ resolver.delete(uri, null, null);
+ }
+
@VisibleForTesting
void esimFactoryReset(Context context, String packageName) {
if (mEraseEsim) {
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index e0e8e4e..3f7bd25 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -342,6 +342,21 @@
return super.onPreferenceTreeClick(preference);
}
+ public static CharSequence getServiceSummary(Context context, AccessibilityServiceInfo info,
+ boolean serviceEnabled) {
+ final String serviceState = serviceEnabled
+ ? context.getString(R.string.accessibility_summary_state_enabled)
+ : context.getString(R.string.accessibility_summary_state_disabled);
+ final CharSequence serviceSummary = info.loadSummary(context.getPackageManager());
+ final String stateSummaryCombo = context.getString(
+ R.string.preference_summary_default_combination,
+ serviceState, serviceSummary);
+
+ return (TextUtils.isEmpty(serviceSummary))
+ ? serviceState
+ : stateSummaryCombo;
+ }
+
private void handleToggleTextContrastPreferenceClick() {
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
@@ -543,15 +558,9 @@
preference.setSummary(R.string.accessibility_summary_state_stopped);
description = getString(R.string.accessibility_description_state_stopped);
} else {
- final String serviceState = serviceEnabled ?
- getString(R.string.accessibility_summary_state_enabled) :
- getString(R.string.accessibility_summary_state_disabled);
- final CharSequence serviceSummary = info.loadSummary(getPackageManager());
- final String stateSummaryCombo = getString(
- R.string.preference_summary_default_combination,
- serviceState, serviceSummary);
- preference.setSummary((TextUtils.isEmpty(serviceSummary)) ? serviceState
- : stateSummaryCombo);
+ final CharSequence serviceSummary = getServiceSummary(getContext(), info,
+ serviceEnabled);
+ preference.setSummary(serviceSummary);
}
// Disable all accessibility services that are not permitted.
diff --git a/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java b/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java
new file mode 100644
index 0000000..6b9a480
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilitySlicePreferenceController.java
@@ -0,0 +1,108 @@
+/*
+ * 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.accessibility;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * PreferenceController for accessibility services to be used by Slices.
+ * Wraps the common logic which enables accessibility services and checks their availability.
+ * <p>
+ * Should not be used in a {@link com.android.settings.dashboard.DashboardFragment}.
+ */
+public class AccessibilitySlicePreferenceController extends TogglePreferenceController {
+
+ private final ComponentName mComponentName;
+
+ private final int ON = 1;
+ private final int OFF = 0;
+
+ public AccessibilitySlicePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mComponentName = ComponentName.unflattenFromString(getPreferenceKey());
+
+ if (mComponentName == null) {
+ throw new IllegalArgumentException(
+ "Illegal Component Name from: " + preferenceKey);
+ }
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ final AccessibilityServiceInfo serviceInfo = getAccessibilityServiceInfo();
+ return serviceInfo == null
+ ? "" : AccessibilitySettings.getServiceSummary(mContext, serviceInfo, isChecked());
+ }
+
+ @Override
+ public boolean isChecked() {
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ final boolean accessibilityEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_ENABLED, OFF) == ON;
+
+ if (!accessibilityEnabled) {
+ return false;
+ }
+
+ final Set<ComponentName> componentNames =
+ AccessibilityUtils.getEnabledServicesFromSettings(mContext);
+
+ return componentNames.contains(mComponentName);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (getAccessibilityServiceInfo() == null) {
+ return false;
+ }
+ AccessibilityUtils.setAccessibilityServiceState(mContext, mComponentName, isChecked);
+ return isChecked == isChecked(); // Verify that it was probably changed.
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // Return unsupported when the service is disabled or not installed.
+ return getAccessibilityServiceInfo() == null ? DISABLED_UNSUPPORTED : AVAILABLE;
+ }
+
+ private AccessibilityServiceInfo getAccessibilityServiceInfo() {
+ final AccessibilityManager accessibilityManager = mContext.getSystemService(
+ AccessibilityManager.class);
+ final List<AccessibilityServiceInfo> serviceList =
+ accessibilityManager.getInstalledAccessibilityServiceList();
+
+ for (AccessibilityServiceInfo serviceInfo : serviceList) {
+ if (mComponentName.equals(serviceInfo.getComponentName())) {
+ return serviceInfo;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index b172198..d9410b2 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -40,6 +40,7 @@
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
+import android.text.BidiFormatter;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
@@ -313,7 +314,7 @@
preferenceGroup.setOrder(mAccountProfileOrder++);
if (isSingleProfile()) {
preferenceGroup.setTitle(context.getString(R.string.account_for_section_header,
- userInfo.name));
+ BidiFormatter.getInstance().unicodeWrap(userInfo.name)));
preferenceGroup.setContentDescription(
mContext.getString(R.string.account_settings));
} else if (userInfo.isManagedProfile()) {
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index 3ed76d8..82a5b9b 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -259,8 +259,10 @@
return;
}
tile.icon = Icon.createWithResource(iconInfo.first, iconInfo.second);
- ThreadUtils.postOnMainThread(() ->
- preference.setIcon(tile.icon.loadDrawable(preference.getContext()))
+ ThreadUtils.postOnMainThread(() -> {
+ preference.setIcon(tile.icon.loadDrawable(preference.getContext()));
+ tile.icon = null;
+ }
);
});
}
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index c8d2cef..e5e83eb 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -187,7 +187,7 @@
updateCarrierInfo(carrierInfo);
if (mLaunchIntent != null) {
launchButton.setOnClickListener((view) -> {
- getContext().sendBroadcast(mLaunchIntent);
+ getContext().startActivity(mLaunchIntent);
});
launchButton.setVisibility(View.VISIBLE);
} else {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index 4787ac5..40fc249 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -22,6 +22,7 @@
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.annotation.LayoutRes;
+import android.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -145,7 +146,7 @@
((TextView) aux.requireViewById(R.id.storage_wizard_migrate_v2_checklist_media))
.setText(TextUtils.expandTemplate(
getText(R.string.storage_wizard_migrate_v2_checklist_media),
- mDisk.getShortDescription()));
+ getDiskShortDescription()));
}
protected void setBackButtonText(int resId, CharSequence... args) {
@@ -228,6 +229,26 @@
}
}
+ protected @NonNull CharSequence getDiskDescription() {
+ if (mDisk != null) {
+ return mDisk.getDescription();
+ } else if (mVolume != null) {
+ return mVolume.getDescription();
+ } else {
+ return getText(R.string.unknown);
+ }
+ }
+
+ protected @NonNull CharSequence getDiskShortDescription() {
+ if (mDisk != null) {
+ return mDisk.getShortDescription();
+ } else if (mVolume != null) {
+ return mVolume.getDescription();
+ } else {
+ return getText(R.string.unknown);
+ }
+ }
+
private final StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onDiskDestroyed(DiskInfo disk) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index 8e3f8ef..0711907 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -57,8 +57,8 @@
mFormatPrivate = getIntent().getBooleanExtra(EXTRA_FORMAT_PRIVATE, false);
- setHeaderText(R.string.storage_wizard_format_progress_title, mDisk.getShortDescription());
- setBodyText(R.string.storage_wizard_format_progress_body, mDisk.getDescription());
+ setHeaderText(R.string.storage_wizard_format_progress_title, getDiskShortDescription());
+ setBodyText(R.string.storage_wizard_format_progress_body, getDiskDescription());
mTask = (PartitionTask) getLastNonConfigurationInstance();
if (mTask == null) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatSlow.java b/src/com/android/settings/deviceinfo/StorageWizardFormatSlow.java
index 9c80ff6..37df2170 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatSlow.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatSlow.java
@@ -39,10 +39,10 @@
mFormatPrivate = getIntent().getBooleanExtra(EXTRA_FORMAT_PRIVATE, false);
- setHeaderText(R.string.storage_wizard_slow_v2_title, mDisk.getShortDescription());
- setBodyText(R.string.storage_wizard_slow_v2_body, mDisk.getDescription(),
- mDisk.getShortDescription(), mDisk.getShortDescription(),
- mDisk.getShortDescription());
+ setHeaderText(R.string.storage_wizard_slow_v2_title, getDiskShortDescription());
+ setBodyText(R.string.storage_wizard_slow_v2_body, getDiskDescription(),
+ getDiskShortDescription(), getDiskShortDescription(),
+ getDiskShortDescription());
setBackButtonText(R.string.storage_wizard_slow_v2_start_over);
setNextButtonText(R.string.storage_wizard_slow_v2_continue);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
index 2233cf9..0fc850b 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardInit.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -45,7 +45,7 @@
mIsPermittedToAdopt = UserManager.get(this).isAdminUser()
&& !ActivityManager.isUserAMonkey();
- setHeaderText(R.string.storage_wizard_init_v2_title, mDisk.getShortDescription());
+ setHeaderText(R.string.storage_wizard_init_v2_title, getDiskShortDescription());
mExternal = requireViewById(R.id.storage_wizard_init_external);
mInternal = requireViewById(R.id.storage_wizard_init_internal);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
index 755f093..969a50a 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
@@ -59,7 +59,7 @@
}
setIcon(R.drawable.ic_swap_horiz);
- setHeaderText(R.string.storage_wizard_migrate_v2_title, mDisk.getShortDescription());
+ setHeaderText(R.string.storage_wizard_migrate_v2_title, getDiskShortDescription());
setBodyText(R.string.memory_calculating_size);
setAuxChecklist();
@@ -67,7 +67,7 @@
@Override
public void onPostExecute(String size, String time) {
setBodyText(R.string.storage_wizard_migrate_v2_body,
- mDisk.getDescription(), size, time);
+ getDiskDescription(), size, time);
}
};
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
index c5c4ca2..fdb8d8a 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardReady.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -33,20 +33,20 @@
}
setContentView(R.layout.storage_wizard_generic);
- setHeaderText(R.string.storage_wizard_ready_title, mDisk.getShortDescription());
+ setHeaderText(R.string.storage_wizard_ready_title, getDiskShortDescription());
final VolumeInfo privateVol = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
if (privateVol != null) {
if (getIntent().getBooleanExtra(EXTRA_MIGRATE_SKIP, false)) {
setBodyText(R.string.storage_wizard_ready_v2_internal_body,
- mDisk.getDescription());
+ getDiskDescription());
} else {
setBodyText(R.string.storage_wizard_ready_v2_internal_moved_body,
- mDisk.getDescription(), mDisk.getShortDescription());
+ getDiskDescription(), getDiskShortDescription());
}
} else {
setBodyText(R.string.storage_wizard_ready_v2_external_body,
- mDisk.getDescription());
+ getDiskDescription());
}
setNextButtonText(R.string.done);
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c8a5d47..639c1fb 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -416,6 +416,11 @@
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
}
+ public boolean isForceAppStandbyEnabled(int uid, String packageName) {
+ return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid,
+ packageName) == AppOpsManager.MODE_IGNORED;
+ }
+
public void initBatteryStatsHelper(BatteryStatsHelper statsHelper, Bundle bundle,
UserManager userManager) {
statsHelper.create(bundle);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 2c8f961..4c4b6e9 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -107,7 +107,8 @@
BatteryHeaderPreferenceController mBatteryHeaderPreferenceController;
@VisibleForTesting
boolean mNeedUpdateBatteryTip;
- private BatteryTipPreferenceController mBatteryTipPreferenceController;
+ @VisibleForTesting
+ BatteryTipPreferenceController mBatteryTipPreferenceController;
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
@VisibleForTesting
@@ -213,8 +214,8 @@
mAnomalySparseArray = new SparseArray<>();
restartBatteryInfoLoader();
- mNeedUpdateBatteryTip = icicle == null;
mBatteryTipPreferenceController.restoreInstanceState(icicle);
+ updateBatteryTipFlag(icicle);
}
@Override
@@ -382,6 +383,11 @@
}
}
+ @VisibleForTesting
+ void updateBatteryTipFlag(Bundle icicle) {
+ mNeedUpdateBatteryTip = icicle == null || mBatteryTipPreferenceController.needUpdate();
+ }
+
@Override
public boolean onLongClick(View view) {
showBothEstimates();
diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
index e75112c..96fafb3 100644
--- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
+++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
@@ -133,7 +133,8 @@
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfoAsUser(
appInfo.packageName, 0 /* flags */, UserHandle.getUserId(appInfo.uid));
- checkBoxPreference.setChecked(true);
+ checkBoxPreference.setChecked(
+ mBatteryUtils.isForceAppStandbyEnabled(appInfo.uid, appInfo.packageName));
checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo));
checkBoxPreference.setIcon(
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager,
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
index 249bf9b..784c54c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java
@@ -52,6 +52,7 @@
private Map<String, BatteryTip> mBatteryTipMap;
private SettingsActivity mSettingsActivity;
private MetricsFeatureProvider mMetricsFeatureProvider;
+ private boolean mNeedUpdate;
@VisibleForTesting
PreferenceGroup mPreferenceGroup;
@VisibleForTesting
@@ -71,6 +72,7 @@
mFragment = fragment;
mSettingsActivity = settingsActivity;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ mNeedUpdate = true;
}
@Override
@@ -111,6 +113,7 @@
mBatteryTipMap.put(preference.getKey(), batteryTip);
mPreferenceGroup.addPreference(preference);
batteryTip.log(mContext, mMetricsFeatureProvider);
+ mNeedUpdate = batteryTip.needUpdate();
break;
}
}
@@ -153,6 +156,10 @@
outState.putParcelableList(KEY_BATTERY_TIPS, mBatteryTips);
}
+ public boolean needUpdate() {
+ return mNeedUpdate;
+ }
+
/**
* Listener to give the control back to target fragment
*/
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 3c3a5c0..f02dd72 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -86,17 +86,23 @@
protected int mType;
protected int mState;
protected boolean mShowDialog;
+ /**
+ * Whether we need to update battery tip when configuration change
+ */
+ protected boolean mNeedUpdate;
BatteryTip(Parcel in) {
mType = in.readInt();
mState = in.readInt();
mShowDialog = in.readBoolean();
+ mNeedUpdate = in.readBoolean();
}
BatteryTip(int type, int state, boolean showDialog) {
mType = type;
mState = state;
mShowDialog = showDialog;
+ mNeedUpdate = true;
}
@Override
@@ -109,6 +115,7 @@
dest.writeInt(mType);
dest.writeInt(mState);
dest.writeBoolean(mShowDialog);
+ dest.writeBoolean(mNeedUpdate);
}
public abstract CharSequence getTitle(Context context);
@@ -144,6 +151,10 @@
return mShowDialog;
}
+ public boolean needUpdate() {
+ return mNeedUpdate;
+ }
+
public String getKey() {
return KEY_PREFIX + mType;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
index 8b16166..9aa8363 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
@@ -42,12 +42,14 @@
public RestrictAppTip(@StateType int state, List<AppInfo> restrictApps) {
super(TipType.APP_RESTRICTION, state, state == StateType.NEW /* showDialog */);
mRestrictAppList = restrictApps;
+ mNeedUpdate = false;
}
public RestrictAppTip(@StateType int state, AppInfo appInfo) {
super(TipType.APP_RESTRICTION, state, state == StateType.NEW /* showDialog */);
mRestrictAppList = new ArrayList<>();
mRestrictAppList.add(appInfo);
+ mNeedUpdate = false;
}
@VisibleForTesting
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index c028298..6776931 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -125,7 +125,7 @@
mControllers.add(new VibrationPreferenceController(context, mBackend));
mControllers.add(new VisibilityPreferenceController(context, new LockPatternUtils(context),
mBackend));
- mControllers.add(new DndPreferenceController(context, getLifecycle(), mBackend));
+ mControllers.add(new DndPreferenceController(context, mBackend));
mControllers.add(new AppLinkPreferenceController(context));
mControllers.add(new DescriptionPreferenceController(context));
mControllers.add(new NotificationsOffPreferenceController(context));
diff --git a/src/com/android/settings/notification/ChannelNotificationSettings.java b/src/com/android/settings/notification/ChannelNotificationSettings.java
index a138429..bd9771a 100644
--- a/src/com/android/settings/notification/ChannelNotificationSettings.java
+++ b/src/com/android/settings/notification/ChannelNotificationSettings.java
@@ -18,13 +18,16 @@
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
+import com.android.settings.applications.AppInfoBase;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
@@ -39,6 +42,19 @@
}
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final PreferenceScreen screen = getPreferenceScreen();
+ Bundle args = getArguments();
+ // If linking to this screen from an external app, expand settings
+ if (screen != null && args != null) {
+ if (!args.getBoolean(ARG_FROM_SETTINGS, false)) {
+ screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
+ }
+ }
+ }
+
+ @Override
public void onResume() {
super.onResume();
if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null || mChannel == null) {
@@ -92,7 +108,7 @@
mBackend));
mControllers.add(new LightsPreferenceController(context, mBackend));
mControllers.add(new BadgePreferenceController(context, mBackend));
- mControllers.add(new DndPreferenceController(context, getLifecycle(), mBackend));
+ mControllers.add(new DndPreferenceController(context, mBackend));
mControllers.add(new NotificationsOffPreferenceController(context));
return new ArrayList<>(mControllers);
}
diff --git a/src/com/android/settings/notification/DndPreferenceController.java b/src/com/android/settings/notification/DndPreferenceController.java
index d4c7a10..899c585 100644
--- a/src/com/android/settings/notification/DndPreferenceController.java
+++ b/src/com/android/settings/notification/DndPreferenceController.java
@@ -28,17 +28,12 @@
import com.android.settingslib.core.lifecycle.events.OnResume;
public class DndPreferenceController extends NotificationPreferenceController
- implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
- LifecycleObserver {
+ implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
private static final String KEY_BYPASS_DND = "bypass_dnd";
- public DndPreferenceController(Context context, Lifecycle lifecycle,
- NotificationBackend backend) {
+ public DndPreferenceController(Context context, NotificationBackend backend) {
super(context, backend);
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
}
@Override
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 6436de6..7eb0ba4 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -58,6 +58,7 @@
abstract public class NotificationSettingsBase extends DashboardFragment {
private static final String TAG = "NotifiSettingsBase";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ protected static final String ARG_FROM_SETTINGS = "fromSettings";
protected PackageManager mPm;
protected NotificationBackend mBackend = new NotificationBackend();
@@ -249,6 +250,7 @@
channelArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
+ channelArgs.putBoolean(ARG_FROM_SETTINGS, true);
channelPref.setIntent(new SubSettingLauncher(getActivity())
.setDestination(ChannelNotificationSettings.class.getName())
.setArguments(channelArgs)
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index dbf8ecf..6535812 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -211,8 +211,6 @@
new DialPadTonePreferenceController(context, fragment, lifecycle);
final ScreenLockSoundPreferenceController screenLockSoundPreferenceController =
new ScreenLockSoundPreferenceController(context, fragment, lifecycle);
- final ChargingSoundPreferenceController chargingSoundPreferenceController =
- new ChargingSoundPreferenceController(context, fragment, lifecycle);
final DockingSoundPreferenceController dockingSoundPreferenceController =
new DockingSoundPreferenceController(context, fragment, lifecycle);
final TouchSoundPreferenceController touchSoundPreferenceController =
@@ -228,7 +226,6 @@
controllers.add(dialPadTonePreferenceController);
controllers.add(screenLockSoundPreferenceController);
- controllers.add(chargingSoundPreferenceController);
controllers.add(dockingSoundPreferenceController);
controllers.add(touchSoundPreferenceController);
controllers.add(vibrateOnTouchPreferenceController);
@@ -239,7 +236,6 @@
"other_sounds_and_vibrations_category").setChildren(
Arrays.asList(dialPadTonePreferenceController,
screenLockSoundPreferenceController,
- chargingSoundPreferenceController,
dockingSoundPreferenceController,
touchSoundPreferenceController,
vibrateOnTouchPreferenceController,
diff --git a/src/com/android/settings/notification/ZenModeVisEffectPreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectPreferenceController.java
index 23723c5..67fd822 100644
--- a/src/com/android/settings/notification/ZenModeVisEffectPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeVisEffectPreferenceController.java
@@ -24,6 +24,7 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settings.widget.DisabledCheckBoxPreference;
public class ZenModeVisEffectPreferenceController
extends AbstractZenModePreferenceController
@@ -78,9 +79,9 @@
if (parentSuppressed) {
((CheckBoxPreference) preference).setChecked(parentSuppressed);
onPreferenceChange(preference, parentSuppressed);
- preference.setEnabled(false);
+ ((DisabledCheckBoxPreference) preference).enableCheckbox(false);
} else {
- preference.setEnabled(true);
+ ((DisabledCheckBoxPreference) preference).enableCheckbox(true);
((CheckBoxPreference) preference).setChecked(suppressed);
}
}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index 1a73ea7..70e9d76 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -18,19 +18,27 @@
import android.app.PendingIntent;
import android.app.slice.SliceManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.provider.SettingsSlicesContract;
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.drawable.IconCompat;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.settings.R;
import com.android.settingslib.utils.ThreadUtils;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -144,11 +152,90 @@
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
}
+ /**
+ * Get a list of all valid Uris based on the keys indexed in the Slices database.
+ * <p>
+ * This will return a list of {@link Uri uris} depending on {@param uri}, following:
+ * 1. Authority & Full Path -> Only {@param uri}. It is only a prefix for itself.
+ * 2. Authority & No path -> A list of authority/action/$KEY$, where
+ * {@code $KEY$} is a list of all Slice-enabled keys for the authority.
+ * 3. Authority & action path -> A list of authority/action/$KEY$, where
+ * {@code $KEY$} is a list of all Slice-enabled keys for the authority.
+ * 4. Empty authority & path -> A list of Uris with all keys for both supported authorities.
+ * 5. Else -> Empty list.
+ * <p>
+ * Note that the authority will stay consistent with {@param uri}, and the list of valid Slice
+ * keys depends on if the authority is {@link SettingsSlicesContract#AUTHORITY} or
+ * {@link #SLICE_AUTHORITY}.
+ *
+ * @param uri The uri to look for descendants under.
+ * @returns all valid Settings uris for which {@param uri} is a prefix.
+ */
+ @Override
+ public Collection<Uri> onGetSliceDescendants(Uri uri) {
+ final List<Uri> descendants = new ArrayList<>();
+ final Pair<Boolean, String> pathData = SliceBuilderUtils.getPathData(uri);
+
+ if (pathData != null) {
+ // Uri has a full path and will not have any descendants.
+ descendants.add(uri);
+ return descendants;
+ }
+
+ final String authority = uri.getAuthority();
+ final String pathPrefix = uri.getPath();
+ final boolean isPathEmpty = pathPrefix.isEmpty();
+
+ // No path nor authority. Return all possible Uris.
+ if (isPathEmpty && TextUtils.isEmpty(authority)) {
+ final List<String> platformKeys = mSlicesDatabaseAccessor.getSliceKeys(
+ true /* isPlatformSlice */);
+ final List<String> oemKeys = mSlicesDatabaseAccessor.getSliceKeys(
+ false /* isPlatformSlice */);
+ final List<Uri> allUris = buildUrisFromKeys(platformKeys,
+ SettingsSlicesContract.AUTHORITY);
+ allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY));
+
+ return allUris;
+ }
+
+ // Path is anything but empty, "action", or "intent". Return empty list.
+ if (!isPathEmpty
+ && !TextUtils.equals(pathPrefix, "/" + SettingsSlicesContract.PATH_SETTING_ACTION)
+ && !TextUtils.equals(pathPrefix,
+ "/" + SettingsSlicesContract.PATH_SETTING_INTENT)) {
+ // Invalid path prefix, there are no valid Uri descendants.
+ return descendants;
+ }
+
+ // Can assume authority belongs to the provider. Return all Uris for the authority.
+ final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY);
+ final List<String> keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri);
+ return buildUrisFromKeys(keys, authority);
+ }
+
+ private List<Uri> buildUrisFromKeys(List<String> keys, String authority) {
+ final List<Uri> descendants = new ArrayList<>();
+
+ final Uri.Builder builder = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION);
+
+ final String newUriPathPrefix = SettingsSlicesContract.PATH_SETTING_ACTION + "/";
+ for (String key : keys) {
+ builder.path(newUriPathPrefix + key);
+ descendants.add(builder.build());
+ }
+
+ return descendants;
+ }
+
@VisibleForTesting
void loadSlice(Uri uri) {
long startBuildTime = System.currentTimeMillis();
- SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
+ final SliceData sliceData = mSlicesDatabaseAccessor.getSliceDataFromUri(uri);
mSliceDataCache.put(uri, sliceData);
getContext().getContentResolver().notifyChange(uri, null /* content observer */);
@@ -204,13 +291,14 @@
.addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
null, finalWifiEnabled))
.setPrimaryAction(
- new SliceAction(getIntent(Intent.ACTION_MAIN),
+ new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
(IconCompat) null, null)))
.build();
}
private PendingIntent getIntent(String action) {
Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
return pi;
}
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 80b7519..d2a6d10 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -54,16 +54,16 @@
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final String key = intent.getStringExtra(EXTRA_SLICE_KEY);
- final boolean isPlatformDefined = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
+ final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED,
false /* default */);
switch (action) {
case ACTION_TOGGLE_CHANGED:
- handleToggleAction(context, key, isPlatformDefined);
+ handleToggleAction(context, key, isPlatformSlice);
break;
case ACTION_SLIDER_CHANGED:
int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1);
- handleSliderAction(context, key, newPosition);
+ handleSliderAction(context, key, newPosition, isPlatformSlice);
break;
case ACTION_WIFI_CHANGED:
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -95,6 +95,7 @@
if (!controller.isAvailable()) {
Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
updateUri(context, key, isPlatformSlice);
+ return;
}
// TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
@@ -107,7 +108,8 @@
updateUri(context, key, isPlatformSlice);
}
- private void handleSliderAction(Context context, String key, int newPosition) {
+ private void handleSliderAction(Context context, String key, int newPosition,
+ boolean isPlatformSlice) {
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException(
"No key passed to Intent for slider controller. Use extra: " + EXTRA_SLICE_KEY);
@@ -123,6 +125,12 @@
throw new IllegalArgumentException("Slider action passed for a non-slider key: " + key);
}
+ if (!controller.isAvailable()) {
+ Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
+ updateUri(context, key, isPlatformSlice);
+ return;
+ }
+
final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
final int maxSteps = sliderController.getMaxSteps();
if (newPosition < 0 || newPosition > maxSteps) {
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index a2479a2..6674344 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -113,13 +113,13 @@
* - key
* <p>
* Examples of valid paths are:
- * - intent/wifi
- * - intent/bluetooth
- * - action/wifi
- * - action/accessibility/servicename
+ * - /intent/wifi
+ * - /intent/bluetooth
+ * - /action/wifi
+ * - /action/accessibility/servicename
*
* @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
- * @return Pair whose first element {@code true} if the path is prepended with "action", and
+ * @return Pair whose first element {@code true} if the path is prepended with "intent", and
* second is a key.
*/
public static Pair<Boolean, String> getPathData(Uri uri) {
@@ -130,13 +130,13 @@
// Example: "/action/wifi" -> [{}, "action", "wifi"]
// "/action/longer/path" -> [{}, "action", "longer/path"]
if (split.length != 3) {
- throw new IllegalArgumentException("Uri (" + uri + ") has incomplete path: " + path);
+ return null;
}
- final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
+ final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
split[1]);
- return new Pair<>(isInline, split[2]);
+ return new Pair<>(isIntent, split[2]);
}
/**
@@ -215,8 +215,8 @@
static Intent getContentIntent(Context context, SliceData sliceData) {
final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
- sliceData.getFragmentClassName(), sliceData.getKey(), sliceData.getScreenTitle(),
- 0 /* TODO */);
+ sliceData.getFragmentClassName(), sliceData.getKey(),
+ sliceData.getScreenTitle().toString(), 0 /* TODO */);
intent.setClassName(context.getPackageName(), SubSettings.class.getName());
intent.setData(contentUri);
return intent;
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
index c02b113..2caf6e6 100644
--- a/src/com/android/settings/slices/SliceData.java
+++ b/src/com/android/settings/slices/SliceData.java
@@ -57,7 +57,7 @@
private final String mSummary;
- private final String mScreenTitle;
+ private final CharSequence mScreenTitle;
private final int mIconResource;
@@ -84,7 +84,7 @@
return mSummary;
}
- public String getScreenTitle() {
+ public CharSequence getScreenTitle() {
return mScreenTitle;
}
@@ -146,7 +146,7 @@
private String mSummary;
- private String mScreenTitle;
+ private CharSequence mScreenTitle;
private int mIconResource;
@@ -175,7 +175,7 @@
return this;
}
- public Builder setScreenTitle(String screenTitle) {
+ public Builder setScreenTitle(CharSequence screenTitle) {
mScreenTitle = screenTitle;
return this;
}
diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java
index 7cf1994..27724bf 100644
--- a/src/com/android/settings/slices/SliceDataConverter.java
+++ b/src/com/android/settings/slices/SliceDataConverter.java
@@ -23,7 +23,12 @@
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
@@ -32,9 +37,14 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
+import android.view.accessibility.AccessibilityManager;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.core.PreferenceXmlParserUtils;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.DatabaseIndexingUtils;
@@ -46,10 +56,16 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
- * Converts {@link DashboardFragment} to {@link SliceData}.
+ * Converts all Slice sources into {@link SliceData}.
+ * This includes:
+ * - All {@link DashboardFragment DashboardFragments} indexed by settings search
+ * - Accessibility services
*/
class SliceDataConverter {
@@ -101,6 +117,8 @@
mSliceData.addAll(providerSliceData);
}
+ final List<SliceData> a11ySliceData = getAccessibilitySliceData();
+ mSliceData.addAll(a11ySliceData);
return mSliceData;
}
@@ -208,4 +226,58 @@
}
return xmlSliceData;
}
+
+ private List<SliceData> getAccessibilitySliceData() {
+ final List<SliceData> sliceData = new ArrayList<>();
+
+ final String accessibilityControllerClassName =
+ AccessibilitySlicePreferenceController.class.getName();
+ final String fragmentClassName = AccessibilitySettings.class.getName();
+ final CharSequence screenTitle = mContext.getText(R.string.accessibility_settings);
+
+ final SliceData.Builder sliceDataBuilder = new SliceData.Builder()
+ .setFragmentName(fragmentClassName)
+ .setScreenTitle(screenTitle)
+ .setPreferenceControllerClassName(accessibilityControllerClassName);
+
+ final Set<String> a11yServiceNames = new HashSet<>();
+ Collections.addAll(a11yServiceNames, mContext.getResources()
+ .getStringArray(R.array.config_settings_slices_accessibility_components));
+ final List<AccessibilityServiceInfo> installedServices = getAccessibilityServiceInfoList();
+ final PackageManager packageManager = mContext.getPackageManager();
+
+ for (AccessibilityServiceInfo a11yServiceInfo : installedServices) {
+ final ResolveInfo resolveInfo = a11yServiceInfo.getResolveInfo();
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ final String packageName = serviceInfo.packageName;
+ final ComponentName componentName = new ComponentName(packageName, serviceInfo.name);
+ final String flattenedName = componentName.flattenToString();
+
+ if (!a11yServiceNames.contains(flattenedName)) {
+ continue;
+ }
+
+ final String title = resolveInfo.loadLabel(packageManager).toString();
+ int iconResource = resolveInfo.getIconResource();
+ if (iconResource == 0) {
+ iconResource = R.mipmap.ic_accessibility_generic;
+ }
+
+ sliceDataBuilder.setKey(flattenedName)
+ .setTitle(title)
+ .setIcon(iconResource)
+ .setSliceType(SliceData.SliceType.SWITCH);
+
+ sliceData.add(sliceDataBuilder.build());
+ }
+
+ return sliceData;
+ }
+
+ @VisibleForTesting
+ List<AccessibilityServiceInfo> getAccessibilityServiceInfoList() {
+ final AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(
+ mContext);
+ return accessibilityManager.getInstalledAccessibilityServiceList();
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index 82b3506..432be36 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -29,6 +29,9 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
+import java.util.ArrayList;
+import java.util.List;
+
import androidx.slice.Slice;
/**
@@ -51,10 +54,12 @@
// Cursor value for boolean true
private final int TRUE = 1;
- Context mContext;
+ private final Context mContext;
+ private final SlicesDatabaseHelper mHelper;
public SlicesDatabaseAccessor(Context context) {
mContext = context;
+ mHelper = SlicesDatabaseHelper.getInstance(mContext);
}
/**
@@ -76,19 +81,47 @@
*/
public SliceData getSliceDataFromKey(String key) {
Cursor cursor = getIndexedSliceData(key);
- return buildSliceData(cursor, null /* uri */, false /* isInlineOnly */);
+ return buildSliceData(cursor, null /* uri */, false /* isIntentOnly */);
+ }
+
+ /**
+ * @return a list of keys in the Slices database matching on {@param isPlatformSlice}.
+ */
+ public List<String> getSliceKeys(boolean isPlatformSlice) {
+ final String whereClause;
+
+ if (isPlatformSlice) {
+ whereClause = IndexColumns.PLATFORM_SLICE + " = 1";
+ } else {
+ whereClause = IndexColumns.PLATFORM_SLICE + " = 0";
+ }
+
+ final SQLiteDatabase database = mHelper.getReadableDatabase();
+ final String[] columns = new String[]{IndexColumns.KEY};
+ final List<String> keys = new ArrayList<>();
+
+ try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, whereClause,
+ null /* selection */, null /* groupBy */, null /* having */, null /* orderBy */)) {
+ if (!resultCursor.moveToFirst()) {
+ return keys;
+ }
+
+ do {
+ keys.add(resultCursor.getString(0 /* key index */));
+ } while (resultCursor.moveToNext());
+ }
+
+ return keys;
}
private Cursor getIndexedSliceData(String path) {
verifyIndexing();
final String whereClause = buildKeyMatchWhereClause();
- final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
- final SQLiteDatabase database = helper.getReadableDatabase();
+ final SQLiteDatabase database = mHelper.getReadableDatabase();
final String[] selection = new String[]{path};
-
- Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL, whereClause,
- selection, null /* groupBy */, null /* having */, null /* orderBy */);
+ final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL,
+ whereClause, selection, null /* groupBy */, null /* having */, null /* orderBy */);
int numResults = resultCursor.getCount();
@@ -111,7 +144,7 @@
.toString();
}
- private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isInlineOnly) {
+ private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isIntentOnly) {
final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
@@ -127,7 +160,7 @@
int sliceType = cursor.getInt(
cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
- if (!isInlineOnly) {
+ if (isIntentOnly) {
sliceType = SliceData.SliceType.INTENT;
}
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index d7de7bc..e2ab40d 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -104,7 +104,7 @@
values.put(IndexColumns.KEY, dataRow.getKey());
values.put(IndexColumns.TITLE, dataRow.getTitle());
values.put(IndexColumns.SUMMARY, dataRow.getSummary());
- values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle());
+ values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle().toString());
values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
values.put(IndexColumns.CONTROLLER, dataRow.getPreferenceController());
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index 25a0518..28ad3f5 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -193,8 +193,12 @@
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
+ protected boolean isStreamFromOutputDevice(int streamType, int device) {
+ return mAudioManager.getDevicesForStream(streamType) == device;
+ }
+
protected boolean isOngoingCallStatus() {
- int audioMode = mAudioManager.getMode();
+ final int audioMode = mAudioManager.getMode();
return audioMode == AudioManager.MODE_RINGTONE
|| audioMode == AudioManager.MODE_IN_CALL
|| audioMode == AudioManager.MODE_IN_COMMUNICATION;
diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
index b0b3dc5..2f21f1b 100644
--- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
+++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
@@ -16,6 +16,9 @@
package com.android.settings.sound;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.support.v7.preference.Preference;
@@ -76,7 +79,7 @@
// Setup devices entries, select active connected device
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
- if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothScoOn()) {
+ if (isStreamFromOutputDevice(STREAM_VOICE_CALL, DEVICE_OUT_USB_HEADSET)) {
// If wired headset is plugged in and active, select to default device.
mSelectedIndex = getDefaultDeviceIndex();
}
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index 2e52f77..df07dc5 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -16,12 +16,13 @@
package com.android.settings.sound;
-import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.AudioManager;
-import android.media.MediaRouter;
import android.support.v7.preference.Preference;
import com.android.internal.util.ArrayUtils;
@@ -49,8 +50,7 @@
return;
}
- if (mAudioManager.isMusicActiveRemotely() || isCastDevice(mMediaRouter)) {
- // TODO(76455906): Workaround for cast mode, need a solid way to identify cast mode.
+ if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_REMOTE_SUBMIX)) {
// In cast mode, disable switch entry.
preference.setEnabled(false);
preference.setSummary(mContext.getText(R.string.media_output_summary_unavailable));
@@ -91,7 +91,7 @@
// Setup devices entries, select active connected device
setupPreferenceEntries(mediaOutputs, mediaValues, activeDevice);
- if (mAudioManager.isWiredHeadsetOn() && !mAudioManager.isBluetoothA2dpOn()) {
+ if (isStreamFromOutputDevice(STREAM_MUSIC, DEVICE_OUT_USB_HEADSET)) {
// If wired headset is plugged in and active, select to default device.
mSelectedIndex = getDefaultDeviceIndex();
}
@@ -106,11 +106,4 @@
mProfileManager.getA2dpProfile().setActiveDevice(device);
}
}
-
- private static boolean isCastDevice(MediaRouter mediaRouter) {
- final MediaRouter.RouteInfo selected = mediaRouter.getSelectedRoute(
- ROUTE_TYPE_REMOTE_DISPLAY);
- return selected != null && selected.getPresentationDisplay() != null
- && selected.getPresentationDisplay().isValid();
- }
}
diff --git a/src/com/android/settings/widget/DisabledCheckBoxPreference.java b/src/com/android/settings/widget/DisabledCheckBoxPreference.java
index 482cff3..e441e21 100644
--- a/src/com/android/settings/widget/DisabledCheckBoxPreference.java
+++ b/src/com/android/settings/widget/DisabledCheckBoxPreference.java
@@ -17,46 +17,85 @@
package com.android.settings.widget;
import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.preference.CheckBoxPreference;
+import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
-import android.support.v7.preference.CheckBoxPreference;
-import android.support.v7.preference.PreferenceViewHolder;
-
/**
- * A CheckboxPreference with a disabled checkbox. Differs from CheckboxPreference.setDisabled()
- * in that the text is not dimmed.
+ * A CheckboxPreference that can disable its checkbox separate from its text.
+ * Differs from CheckboxPreference.setDisabled() in that the text is not dimmed.
*/
public class DisabledCheckBoxPreference extends CheckBoxPreference {
+ private PreferenceViewHolder mViewHolder;
+ private View mCheckBox;
+ private boolean mEnabledCheckBox;
- public DisabledCheckBoxPreference(Context context, AttributeSet attrs,
- int defStyleAttr, int defStyleRes) {
+ public DisabledCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ setupDisabledCheckBoxPreference(context, attrs, defStyleAttr, defStyleRes);
}
public DisabledCheckBoxPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ setupDisabledCheckBoxPreference(context, attrs, defStyleAttr, 0);
}
public DisabledCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
+ setupDisabledCheckBoxPreference(context, attrs, 0, 0);
}
public DisabledCheckBoxPreference(Context context) {
super(context);
+ setupDisabledCheckBoxPreference(context, null, 0, 0);
+ }
+
+ private void setupDisabledCheckBoxPreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.Preference, defStyleAttr, defStyleRes);
+ for (int i = a.getIndexCount() - 1; i >= 0; i--) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case com.android.internal.R.styleable.Preference_enabled:
+ mEnabledCheckBox = a.getBoolean(attr, true);
+ break;
+ }
+ }
+ a.recycle();
+
+ // Always tell super class this preference is enabled.
+ // We manually enable/disable checkbox using enableCheckBox.
+ super.setEnabled(true);
+ enableCheckbox(mEnabledCheckBox);
+ }
+
+ public void enableCheckbox(boolean enabled) {
+ mEnabledCheckBox = enabled;
+ if (mViewHolder != null && mCheckBox != null) {
+ mCheckBox.setEnabled(mEnabledCheckBox);
+ mViewHolder.itemView.setEnabled(mEnabledCheckBox);
+ }
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ mViewHolder = holder;
+ mCheckBox = holder.findViewById(android.R.id.checkbox);
- View view = holder.findViewById(android.R.id.checkbox);
- view.setEnabled(false);
- holder.itemView.setEnabled(false);
+ enableCheckbox(mEnabledCheckBox);
}
@Override
protected void performClick(View view) {
- // Do nothing
+ // only perform clicks if the checkbox is enabled
+ if (mEnabledCheckBox) {
+ super.performClick(view);
+ }
}
+
}
diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java
index a5bab1c..707da00 100644
--- a/src/com/android/settings/widget/ValidatedEditTextPreference.java
+++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java
@@ -74,7 +74,7 @@
editText.removeTextChangedListener(mTextWatcher);
if (mIsPassword) {
editText.setInputType(
- InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
editText.setMaxLines(1);
}
editText.addTextChangedListener(mTextWatcher);
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
index b38558c..5ba0583 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -55,6 +55,7 @@
mPassword = generateRandomPassword();
}
((ValidatedEditTextPreference) mPreference).setValidator(this);
+ ((ValidatedEditTextPreference) mPreference).setIsPassword(true);
((ValidatedEditTextPreference) mPreference).setIsSummaryPassword(true);
updatePasswordDisplay((EditTextPreference) mPreference);
}
diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
index 5a09997..d2274e6 100644
--- a/tests/robotests/assets/grandfather_slice_controller_not_in_xml
+++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
@@ -1,2 +1,4 @@
com.android.settings.testutils.FakeToggleController
-com.android.settings.testutils.FakeSliderController
\ No newline at end of file
+com.android.settings.testutils.FakeSliderController
+com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
+com.android.settings.accessibility.AccessibilitySlicePreferenceController
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 39620d8..cecc9c5 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -62,4 +62,9 @@
<bool name="config_show_wifi_ip_address">false</bool>
<bool name="config_show_wifi_mac_address">false</bool>
<bool name="config_disable_uninstall_update">true</bool>
+
+ <!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
+ <string-array name="config_settings_slices_accessibility_components" translatable="false">
+ <item>fake_package/fake_service</item>
+ </string-array>
</resources>
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
new file mode 100644
index 0000000..fe6d1a3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySlicePreferenceControllerTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_UNSUPPORTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.accessibility.AccessibilityUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowAccessibilityManager;
+import org.xmlpull.v1.XmlPullParserException;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AccessibilitySlicePreferenceControllerTest {
+
+ private final String PACKAGE_NAME = "com.android.settings.fake";
+ private final String CLASS_NAME = "com.android.settings.fake.classname";
+ private final String SERVICE_NAME = PACKAGE_NAME + "/" + CLASS_NAME;
+
+ private Context mContext;
+
+ private AccessibilitySlicePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ Settings.Secure.putInt(contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 1 /* on */);
+ Settings.Secure.putString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ SERVICE_NAME);
+
+ // Register the fake a11y Service
+ ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract(
+ RuntimeEnvironment.application.getSystemService(AccessibilityManager.class));
+ shadowAccessibilityManager.setInstalledAccessibilityServiceList(getFakeServiceList());
+
+ mController = new AccessibilitySlicePreferenceController(mContext, SERVICE_NAME);
+ }
+
+ @Test
+ public void getAvailability_availableService_returnsAvailable() {
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_unknownService_returnsUnsupported() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(DISABLED_UNSUPPORTED);
+ }
+
+ @Test
+ public void setChecked_availableService_serviceIsEnabled() {
+ mController.setChecked(true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void setNotChecked_availableService_serviceIsDisabled() {
+ mController.setChecked(false);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_serviceEnabled_returnsTrue() {
+ AccessibilityUtils.setAccessibilityServiceState(mContext,
+ ComponentName.unflattenFromString(mController.getPreferenceKey()), true);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isChecked_serviceNotEnabled_returnsFalse() {
+ AccessibilitySlicePreferenceController controller =
+ new AccessibilitySlicePreferenceController(mContext, "fake_service/name");
+
+ assertThat(controller.isChecked()).isFalse();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void illegalServiceName_exceptionThrown() {
+ new AccessibilitySlicePreferenceController(mContext, "not_split_by_slash");
+ }
+
+ private List<AccessibilityServiceInfo> getFakeServiceList() {
+ final List<AccessibilityServiceInfo> infoList = new ArrayList<>();
+
+ final ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = PACKAGE_NAME;
+ serviceInfo.name = CLASS_NAME;
+
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.serviceInfo = serviceInfo;
+
+ try {
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
+ mContext);
+ ComponentName componentName = new ComponentName(PACKAGE_NAME, CLASS_NAME);
+ info.setComponentName(componentName);
+ infoList.add(info);
+ } catch (XmlPullParserException | IOException e) {
+
+ }
+
+ return infoList;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index 4a09b40..a0e5ed8 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -297,7 +297,7 @@
"content://com.android.settings/tile_icon");
mImpl.bindIcon(preference, tile);
- assertThat(tile.icon).isNotNull();
+ assertThat(preference.getIcon()).isNotNull();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
index a5a1c45..876f5d1 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
@@ -26,6 +26,7 @@
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.support.v7.preference.PreferenceViewHolder;
+import android.telephony.SubscriptionManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
@@ -401,6 +402,31 @@
}
@Test
+ public void testSetAppIntent_toMdpApp_intentCorrect() {
+ final Activity activity = Robolectric.setupActivity(Activity.class);
+ final Intent intent = new Intent(SubscriptionManager.ACTION_MANAGE_SUBSCRIPTION_PLANS);
+ intent.setPackage("test-owner.example.com");
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 42);
+
+ mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, DUMMY_CARRIER, 0 /* numPlans */,
+ intent);
+
+ bindViewHolder();
+ assertThat(mLaunchButton.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mLaunchButton.getText())
+ .isEqualTo(mContext.getString(R.string.launch_mdp_app_text));
+
+ mLaunchButton.callOnClick();
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent startedIntent = shadowActivity.getNextStartedActivity();
+ assertThat(startedIntent.getAction())
+ .isEqualTo(SubscriptionManager.ACTION_MANAGE_SUBSCRIPTION_PLANS);
+ assertThat(startedIntent.getPackage()).isEqualTo("test-owner.example.com");
+ assertThat(startedIntent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, -1))
+ .isEqualTo(42);
+ }
+
+ @Test
public void testSetWifiMode_withUsageInfo_dataUsageShown() {
final int daysLeft = 3;
final long cycleEnd = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(daysLeft)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 772bb8d..dc34016 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -565,6 +565,22 @@
}
@Test
+ public void testIsForceAppStandbyEnabled_enabled_returnTrue() {
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_IGNORED);
+
+ assertThat(mBatteryUtils.isForceAppStandbyEnabled(UID, PACKAGE_NAME)).isTrue();
+ }
+
+ @Test
+ public void testIsForceAppStandbyEnabled_disabled_returnFalse() {
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_ALLOWED);
+
+ assertThat(mBatteryUtils.isForceAppStandbyEnabled(UID, PACKAGE_NAME)).isFalse();
+ }
+
+ @Test
public void testIsAppHeavilyUsed_usageMoreThanThreshold_returnTrue() {
assertThat(mBatteryUtils.isAppHeavilyUsed(mBatteryStatsHelper, mUserManager, UID,
10 /* threshold */ )).isTrue();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 989c033..b20cf16 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -49,6 +49,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.fuelgauge.anomaly.Anomaly;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.XmlTestUtils;
@@ -187,7 +188,7 @@
}
@Test
- public void testUpdateLastFullChargePreference_noAverageTime_showLastFullChargeSummary() {
+ public void updateLastFullChargePreference_noAverageTime_showLastFullChargeSummary() {
mFragment.mBatteryInfo = null;
when(mFragment.getContext()).thenReturn(mRealContext);
doReturn(TIME_SINCE_LAST_FULL_CHARGE_MS).when(
@@ -200,7 +201,7 @@
}
@Test
- public void testUpdateLastFullChargePreference_hasAverageTime_showFullChargeLastSummary() {
+ public void updateLastFullChargePreference_hasAverageTime_showFullChargeLastSummary() {
mFragment.mBatteryInfo = mBatteryInfo;
mBatteryInfo.averageTimeToDischarge = TIME_SINCE_LAST_FULL_CHARGE_MS;
when(mFragment.getContext()).thenReturn(mRealContext);
@@ -212,7 +213,7 @@
}
@Test
- public void testNonIndexableKeys_MatchPreferenceKeys() {
+ public void nonIndexableKeys_MatchPreferenceKeys() {
final Context context = RuntimeEnvironment.application;
final List<String> niks =
PowerUsageSummary.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(context);
@@ -224,7 +225,7 @@
}
@Test
- public void testPreferenceControllers_getPreferenceKeys_existInPreferenceScreen() {
+ public void preferenceControllers_getPreferenceKeys_existInPreferenceScreen() {
final Context context = RuntimeEnvironment.application;
final PowerUsageSummary fragment = new PowerUsageSummary();
final List<String> preferenceScreenKeys =
@@ -239,7 +240,7 @@
}
@Test
- public void testUpdateAnomalySparseArray() {
+ public void updateAnomalySparseArray() {
mFragment.mAnomalySparseArray = new SparseArray<>();
final List<Anomaly> anomalies = new ArrayList<>();
final Anomaly anomaly1 = new Anomaly.Builder().setUid(UID).build();
@@ -256,7 +257,7 @@
}
@Test
- public void testRestartBatteryTipLoader() {
+ public void restartBatteryTipLoader() {
//TODO: add policy logic here when BatteryTipPolicy is implemented
doReturn(mLoaderManager).when(mFragment).getLoaderManager();
@@ -267,7 +268,7 @@
}
@Test
- public void testShowBothEstimates_summariesAreBothModified() {
+ public void showBothEstimates_summariesAreBothModified() {
when(mFeatureFactory.powerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(any()))
.thenReturn(true);
doAnswer(new Answer() {
@@ -296,7 +297,7 @@
}
@Test
- public void testDebugMode() {
+ public void debugMode() {
doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isEstimateDebugEnabled();
doReturn(new TextView(mRealContext)).when(mBatteryLayoutPref).findViewById(R.id.summary2);
@@ -315,7 +316,7 @@
}
@Test
- public void testRestartBatteryStatsLoader_notClearHeader_quickUpdateNotInvoked() {
+ public void restartBatteryStatsLoader_notClearHeader_quickUpdateNotInvoked() {
mFragment.mBatteryHeaderPreferenceController = mBatteryHeaderPreferenceController;
mFragment.restartBatteryStatsLoader(false /* clearHeader */);
@@ -324,7 +325,7 @@
}
@Test
- public void testOptionsMenu_advancedPageEnabled() {
+ public void optionsMenu_advancedPageEnabled() {
when(mFeatureFactory.powerUsageFeatureProvider.isPowerAccountingToggleEnabled())
.thenReturn(true);
@@ -335,7 +336,7 @@
}
@Test
- public void testOptionsMenu_clickAdvancedPage_fireIntent() {
+ public void optionsMenu_clickAdvancedPage_fireIntent() {
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
doAnswer(invocation -> {
// Get the intent in which it has the app info bundle
@@ -353,13 +354,27 @@
}
@Test
- public void testRefreshUi_deviceRotate_doNotUpdateBatteryTip() {
- mFragment.mNeedUpdateBatteryTip = false;
+ public void refreshUi_deviceRotate_doNotUpdateBatteryTip() {
+ mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
+ when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(false);
+ mFragment.updateBatteryTipFlag(new Bundle());
+
mFragment.refreshUi();
verify(mFragment, never()).restartBatteryTipLoader();
}
+ @Test
+ public void refreshUi_tipNeedUpdate_updateBatteryTip() {
+ mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
+ when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true);
+ mFragment.updateBatteryTipFlag(new Bundle());
+
+ mFragment.refreshUi();
+
+ verify(mFragment).restartBatteryTipLoader();
+ }
+
public static class TestFragment extends PowerUsageSummary {
private Context mContext;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
index 94a6903..0fad0a7 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
@@ -28,10 +28,12 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
+import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceManager;
import android.util.IconDrawableFactory;
+import android.widget.CheckBox;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
@@ -93,7 +95,7 @@
mRestrictedAppDetails.mAppInfos = new ArrayList<>();
mRestrictedAppDetails.mAppInfos.add(mAppInfo);
mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext));
- mRestrictedAppDetails.mBatteryUtils = new BatteryUtils(mContext);
+ mRestrictedAppDetails.mBatteryUtils = spy(new BatteryUtils(mContext));
doReturn(mPreferenceManager).when(
mRestrictedAppDetails.mRestrictedAppListGroup).getPreferenceManager();
}
@@ -103,13 +105,16 @@
doReturn(mApplicationInfo).when(mPackageManager)
.getApplicationInfoAsUser(PACKAGE_NAME, 0, USER_ID);
doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo);
+ doReturn(true).when(mRestrictedAppDetails.mBatteryUtils).isForceAppStandbyEnabled(UID,
+ PACKAGE_NAME);
mRestrictedAppDetails.refreshUi();
assertThat(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1);
- final Preference preference = mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(
- 0);
+ final CheckBoxPreference preference =
+ (CheckBoxPreference) mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0);
assertThat(preference.getTitle()).isEqualTo(APP_NAME);
+ assertThat(preference.isChecked()).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
index cee647e..405e761 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
@@ -74,6 +74,7 @@
assertThat(parcelTip.getTitle(mContext)).isEqualTo(TITLE);
assertThat(parcelTip.getSummary(mContext)).isEqualTo(SUMMARY);
assertThat(parcelTip.getIconId()).isEqualTo(ICON_ID);
+ assertThat(parcelTip.needUpdate()).isTrue();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/DndPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/DndPreferenceControllerTest.java
index 54dda6a..ba612ac 100644
--- a/tests/robotests/src/com/android/settings/notification/DndPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/DndPreferenceControllerTest.java
@@ -64,8 +64,6 @@
private UserManager mUm;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
- @Mock
- private Lifecycle mLifecycle;
private DndPreferenceController mController;
@@ -76,7 +74,7 @@
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
mContext = RuntimeEnvironment.application;
- mController = spy(new DndPreferenceController(mContext, mLifecycle, mBackend));
+ mController = spy(new DndPreferenceController(mContext, mBackend));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectPreferenceControllerTest.java
index 6ca04ba..29ced0b 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectPreferenceControllerTest.java
@@ -42,6 +42,7 @@
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settings.widget.DisabledCheckBoxPreference;
import org.junit.Before;
import org.junit.Test;
@@ -58,7 +59,7 @@
@Mock
private ZenModeBackend mBackend;
@Mock
- private CheckBoxPreference mockPref;
+ private DisabledCheckBoxPreference mockPref;
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@Mock
@@ -114,7 +115,7 @@
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
- verify(mockPref).setEnabled(true);
+ verify(mockPref).enableCheckbox(true);
}
@Test
@@ -123,7 +124,7 @@
mController.updateState(mockPref);
verify(mockPref).setChecked(true);
- verify(mockPref).setEnabled(true);
+ verify(mockPref).enableCheckbox(true);
}
@Test
@@ -138,7 +139,7 @@
mController.updateState(mockPref);
verify(mockPref).setChecked(true);
- verify(mockPref).setEnabled(false);
+ verify(mockPref).enableCheckbox(false);
verify(mBackend, times(1)).saveVisualEffectsPolicy(SUPPRESSED_EFFECT_PEEK, true);
}
@@ -154,7 +155,7 @@
mController.updateState(mockPref);
verify(mockPref).setChecked(false);
- verify(mockPref).setEnabled(true);
+ verify(mockPref).enableCheckbox(true);
verify(mBackend, never()).saveVisualEffectsPolicy(SUPPRESSED_EFFECT_PEEK, true);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index d54d16f..b5399ea 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -17,6 +17,8 @@
package com.android.settings.slices;
+import static android.content.ContentResolver.SCHEME_CONTENT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
@@ -41,6 +43,7 @@
import androidx.slice.Slice;
+import java.util.Collection;
import java.util.HashMap;
/**
@@ -114,7 +117,190 @@
assertThat(cachedData).isNull();
}
+ @Test
+ public void getDescendantUris_fullActionUri_returnsSelf() {
+ final Uri uri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(uri);
+ }
+
+ @Test
+ public void getDescendantUris_fullIntentUri_returnsSelf() {
+ final Uri uri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/key", true);
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(uri);
+ }
+
+ @Test
+ public void getDescendantUris_wrongPath_returnsEmpty() {
+ final Uri uri = SliceBuilderUtils.getUri("invalid_path", true);
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_invalidPath_returnsEmpty() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath("invalid")
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
+ insertSpecialCase("oem_key", false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
+ insertSpecialCase("platform_key", true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ insertSpecialCase(key, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ insertSpecialCase(key, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ insertSpecialCase(key, true /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .build();
+ final Uri expectedUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(key)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedUri);
+ }
+
+ @Test
+ public void getDescendantUris_noAuthorityNorPath_returnsAllUris() {
+ final String platformKey = "platform_key";
+ final String oemKey = "oemKey";
+ insertSpecialCase(platformKey, true /* isPlatformSlice */);
+ insertSpecialCase(oemKey, false /* isPlatformSlice */);
+ final Uri uri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .build();
+ final Uri expectedPlatformUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(platformKey)
+ .build();
+ final Uri expectedOemUri = new Uri.Builder()
+ .scheme(SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(oemKey)
+ .build();
+
+ final Collection<Uri> descendants = mProvider.onGetSliceDescendants(uri);
+
+ assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri);
+ }
+
private void insertSpecialCase(String key) {
+ insertSpecialCase(key, true);
+ }
+
+ private void insertSpecialCase(String key, boolean isPlatformSlice) {
ContentValues values = new ContentValues();
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, TITLE);
@@ -123,6 +309,8 @@
values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, 1234);
values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test");
values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, "test");
+ values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
+ values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index 0cdb2f4..0b6e4b5 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -18,17 +18,28 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+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 android.app.slice.Slice;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.provider.Settings;
+import android.provider.SettingsSlicesContract;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
@@ -36,6 +47,7 @@
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeSliderController;
import com.android.settings.testutils.FakeToggleController;
+import com.android.settings.testutils.FakeUnavailablePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
@@ -65,7 +77,7 @@
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
mReceiver = new SliceBroadcastReceiver();
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
@@ -192,6 +204,77 @@
mReceiver.onReceive(mContext, intent);
}
+ @Test
+ public void toggleUpdate_unavailableUriNotified() {
+ // Monitor the ContentResolver
+ final ContentResolver resolver = spy(mContext.getContentResolver());
+ doReturn(resolver).when(mContext).getContentResolver();
+
+ // Disable Setting
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FakeToggleController.AVAILABILITY_KEY,
+ BasePreferenceController.DISABLED_UNSUPPORTED);
+
+ // Insert Fake Toggle into Database
+ final String key = "key";
+ mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
+ insertSpecialCase(FakeToggleController.class, key);
+
+ // Turn on toggle setting
+ final FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
+ fakeToggleController.setChecked(true);
+
+ // Build Action
+ final Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
+ intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
+
+ // Trigger Slice change
+ mReceiver.onReceive(mContext, intent);
+
+ // Check the value is the same and the Uri has been notified.
+ assertThat(fakeToggleController.isChecked()).isTrue();
+ final Uri expectedUri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
+ verify(resolver).notifyChange(eq(expectedUri), eq(null));
+ }
+
+ @Test
+ public void sliderUpdate_unavailableUriNotified() {
+ // Monitor the ContentResolver
+ final ContentResolver resolver = spy(mContext.getContentResolver());
+ doReturn(resolver).when(mContext).getContentResolver();
+
+ // Disable Setting
+ Settings.Global.putInt(mContext.getContentResolver(),
+ FakeSliderController.AVAILABILITY_KEY,
+ BasePreferenceController.DISABLED_UNSUPPORTED);
+
+ // Insert Fake Slider into Database
+ final String key = "key";
+ final int position = FakeSliderController.MAX_STEPS - 1;
+ final int oldPosition = FakeSliderController.MAX_STEPS;
+ mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
+ insertSpecialCase(FakeSliderController.class, key);
+
+ // Set slider setting
+ final FakeSliderController fakeSliderController = new FakeSliderController(mContext, key);
+ fakeSliderController.setSliderPosition(oldPosition);
+
+ // Build action
+ final Intent intent = new Intent(SettingsSliceProvider.ACTION_SLIDER_CHANGED);
+ intent.putExtra(Slice.EXTRA_RANGE_VALUE, position);
+ intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
+
+ // Trigger Slice change
+ mReceiver.onReceive(mContext, intent);
+
+ // Check position is the same and the Uri has been notified.
+ assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
+ final Uri expectedUri = SliceBuilderUtils.getUri(
+ SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
+ verify(resolver).notifyChange(eq(expectedUri), eq(null));
+ }
+
private void insertSpecialCase(String key) {
insertSpecialCase(fakeControllerName, key);
}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 59eb7ce..96cf1dc 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -24,7 +24,6 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +39,7 @@
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.FakeSliderController;
import com.android.settings.testutils.FakeToggleController;
+import com.android.settings.testutils.FakeUnavailablePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.SliceTester;
@@ -277,7 +277,7 @@
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isFalse();
+ assertThat(pathPair.first).isTrue();
assertThat(pathPair.second).isEqualTo(KEY);
}
@@ -291,18 +291,20 @@
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY);
}
- @Test(expected = IllegalArgumentException.class)
+ @Test
public void getPathData_noKey_returnsNull() {
final Uri uri = new Uri.Builder()
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.build();
- SliceBuilderUtils.getPathData(uri);
+ final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
+
+ assertThat(pathPair).isNull();
}
@Test
@@ -316,7 +318,7 @@
final Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
- assertThat(pathPair.first).isTrue();
+ assertThat(pathPair.first).isFalse();
assertThat(pathPair.second).isEqualTo(KEY + "/" + KEY);
}
@@ -324,7 +326,7 @@
public void testUnsupportedSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_UNSUPPORTED);
@@ -337,7 +339,7 @@
public void testDisabledForUserSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_FOR_USER);
@@ -350,7 +352,7 @@
public void testDisabledDependentSettingSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.INTENT);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -372,7 +374,7 @@
public void testUnavailableUnknownSlice_validTitleSummary() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
- Settings.System.putInt(mContext.getContentResolver(),
+ Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.UNAVAILABLE_UNKNOWN);
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index 36c2754..adc7a96 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -17,8 +17,22 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilitySettings;
+import com.android.settings.accessibility.AccessibilitySlicePreferenceController;
import com.android.settings.search.FakeIndexProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.search.SearchFeatureProviderImpl;
@@ -32,17 +46,29 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class SliceDataConverterTest {
- private final String fakeKey = "key";
- private final String fakeTitle = "title";
- private final String fakeSummary = "summary";
- private final String fakeScreenTitle = "screen_title";
- private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
- private final String fakeControllerName = FakePreferenceController.class.getName();
+ private final String FAKE_KEY = "key";
+ private final String FAKE_TITLE = "title";
+ private final String FAKE_SUMMARY = "summary";
+ private final String FAKE_SCREEN_TITLE = "screen_title";
+ private final String FAKE_FRAGMENT_CLASSNAME = FakeIndexProvider.class.getName();
+ private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
+
+ private final String ACCESSIBILITY_FRAGMENT = AccessibilitySettings.class.getName();
+ private final String A11Y_CONTROLLER_NAME =
+ AccessibilitySlicePreferenceController.class.getName();
+ private final String FAKE_SERVICE_NAME = "fake_service";
+ private final String FAKE_ACCESSIBILITY_PACKAGE = "fake_package";
+ private final String FAKE_A11Y_SERVICE_NAME =
+ FAKE_ACCESSIBILITY_PACKAGE + "/" + FAKE_SERVICE_NAME;
+ private final int FAKE_ICON = 1234;
+
+ private Context mContext;
private SliceDataConverter mSliceDataConverter;
private SearchFeatureProvider mSearchFeatureProvider;
@@ -50,7 +76,8 @@
@Before
public void setUp() {
- mSliceDataConverter = new SliceDataConverter(RuntimeEnvironment.application);
+ mContext = RuntimeEnvironment.application;
+ mSliceDataConverter = spy(new SliceDataConverter(RuntimeEnvironment.application));
mSearchFeatureProvider = new SearchFeatureProviderImpl();
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.searchFeatureProvider = mSearchFeatureProvider;
@@ -68,20 +95,64 @@
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues()
.add(FakeIndexProvider.class);
+ doReturn(getFakeService()).when(mSliceDataConverter).getAccessibilityServiceInfoList();
+
List<SliceData> sliceDataList = mSliceDataConverter.getSliceData();
- assertThat(sliceDataList).hasSize(1);
- SliceData fakeSlice = sliceDataList.get(0);
+ assertThat(sliceDataList).hasSize(2);
+ SliceData fakeSlice0 = sliceDataList.get(0);
+ SliceData fakeSlice1 = sliceDataList.get(1);
- assertThat(fakeSlice.getKey()).isEqualTo(fakeKey);
- assertThat(fakeSlice.getTitle()).isEqualTo(fakeTitle);
- assertThat(fakeSlice.getSummary()).isEqualTo(fakeSummary);
- assertThat(fakeSlice.getScreenTitle()).isEqualTo(fakeScreenTitle);
+ // Should not assume the order of the data list.
+ if (TextUtils.equals(fakeSlice0.getKey(), FAKE_KEY)) {
+ assertFakeSlice(fakeSlice0);
+ assertFakeA11ySlice(fakeSlice1);
+ } else {
+ assertFakeSlice(fakeSlice1);
+ assertFakeA11ySlice(fakeSlice0);
+ }
+ }
+
+ private void assertFakeSlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_KEY);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
assertThat(fakeSlice.getIconResource()).isNotNull();
assertThat(fakeSlice.getUri()).isNull();
- assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
- assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName);
- assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_CLASSNAME);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
+ assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
}
+
+ private void assertFakeA11ySlice(SliceData fakeSlice) {
+ assertThat(fakeSlice.getKey()).isEqualTo(FAKE_A11Y_SERVICE_NAME);
+ assertThat(fakeSlice.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(fakeSlice.getSummary()).isNull();
+ assertThat(fakeSlice.getScreenTitle()).isEqualTo(
+ mContext.getString(R.string.accessibility_settings));
+ assertThat(fakeSlice.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(fakeSlice.getUri()).isNull();
+ assertThat(fakeSlice.getFragmentClassName()).isEqualTo(ACCESSIBILITY_FRAGMENT);
+ assertThat(fakeSlice.getPreferenceController()).isEqualTo(A11Y_CONTROLLER_NAME);
+ }
+
+ // This is fragile. Should be replaced by a proper fake Service if possible.
+ private List<AccessibilityServiceInfo> getFakeService() {
+ List<AccessibilityServiceInfo> serviceInfoList = new ArrayList<>();
+ AccessibilityServiceInfo serviceInfo = spy(new AccessibilityServiceInfo());
+
+ ResolveInfo resolveInfo = spy(new ResolveInfo());
+ resolveInfo.serviceInfo = new ServiceInfo();
+ resolveInfo.serviceInfo.name = FAKE_SERVICE_NAME;
+ resolveInfo.serviceInfo.packageName = FAKE_ACCESSIBILITY_PACKAGE;
+ doReturn(FAKE_TITLE).when(resolveInfo).loadLabel(any(PackageManager.class));
+ doReturn(FAKE_ICON).when(resolveInfo).getIconResource();
+
+ doReturn(resolveInfo).when(serviceInfo).getResolveInfo();
+ serviceInfoList.add(serviceInfo);
+
+ return serviceInfoList;
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index 77c9891..45ec064 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -18,6 +18,7 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.spy;
import android.content.ContentValues;
@@ -35,15 +36,17 @@
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
+import java.util.List;
+
@RunWith(SettingsRobolectricTestRunner.class)
public class SlicesDatabaseAccessorTest {
- private final String fakeTitle = "title";
- private final String fakeSummary = "summary";
- private final String fakeScreenTitle = "screen_title";
- private final int fakeIcon = 1234;
- private final String fakeFragmentClassName = FakeIndexProvider.class.getName();
- private final String fakeControllerName = FakePreferenceController.class.getName();
+ private final String FAKE_TITLE = "title";
+ private final String FAKE_SUMMARY = "summary";
+ private final String FAKE_SCREEN_TITLE = "screen_title";
+ private final int FAKE_ICON = 1234;
+ private final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName();
+ private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName();
private Context mContext;
private SQLiteDatabase mDb;
@@ -70,13 +73,13 @@
SliceData data = mAccessor.getSliceDataFromKey(key);
assertThat(data.getKey()).isEqualTo(key);
- assertThat(data.getTitle()).isEqualTo(fakeTitle);
- assertThat(data.getSummary()).isEqualTo(fakeSummary);
- assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
- assertThat(data.getIconResource()).isEqualTo(fakeIcon);
- assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
+ assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isNull();
- assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
+ assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
}
@Test(expected = IllegalStateException.class)
@@ -96,13 +99,13 @@
SliceData data = mAccessor.getSliceDataFromUri(uri);
assertThat(data.getKey()).isEqualTo(key);
- assertThat(data.getTitle()).isEqualTo(fakeTitle);
- assertThat(data.getSummary()).isEqualTo(fakeSummary);
- assertThat(data.getScreenTitle()).isEqualTo(fakeScreenTitle);
- assertThat(data.getIconResource()).isEqualTo(fakeIcon);
- assertThat(data.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
+ assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
+ assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isEqualTo(uri);
- assertThat(data.getPreferenceController()).isEqualTo(fakeControllerName);
+ assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
}
@Test(expected = IllegalStateException.class)
@@ -111,15 +114,62 @@
mAccessor.getSliceDataFromUri(uri);
}
+ @Test
+ public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() {
+ final String key = "oem_key";
+ final boolean isPlatformSlice = false;
+ insertSpecialCase(key, isPlatformSlice);
+ final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice);
+
+ assertThat(keys).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() {
+ final String key = "platform_key";
+ final boolean isPlatformSlice = true;
+ insertSpecialCase(key, isPlatformSlice);
+ final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice);
+
+ assertThat(keys).isEmpty();
+ }
+
+ @Test
+ public void getDescendantUris_oemSlice_returnsOEMUriDescendant() {
+ final String key = "oem_key";
+ final boolean isPlatformSlice = false;
+ insertSpecialCase(key, isPlatformSlice);
+ final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice);
+
+ assertThat(keys).containsExactly(key);
+ }
+
+ @Test
+ public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() {
+ final String key = "platform_key";
+ final boolean isPlatformSlice = true;
+ insertSpecialCase(key, isPlatformSlice);
+ final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice);
+
+ assertThat(keys).containsExactly(key);
+ }
+
private void insertSpecialCase(String key) {
+ insertSpecialCase(key, true);
+ }
+
+ private void insertSpecialCase(String key, boolean isPlatformSlice) {
ContentValues values = new ContentValues();
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
- values.put(SlicesDatabaseHelper.IndexColumns.TITLE, fakeTitle);
- values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, fakeSummary);
- values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, fakeScreenTitle);
- values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, fakeIcon);
- values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, fakeFragmentClassName);
- values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, fakeControllerName);
+ values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
+ values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY);
+ values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE);
+ values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON);
+ values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME);
+ values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME);
+ values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice);
+ values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
+
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
}
diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
index c6c4b45..f3f1c83 100644
--- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
@@ -17,6 +17,8 @@
package com.android.settings.sound;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -205,10 +207,9 @@
* Preference summary should be "This device"
*/
@Test
- public void hapBtDevicesAreAvailableButWiredHeadsetIsActivated_shouldSetDefaultSummary() {
+ public void updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
- mShadowAudioManager.setWiredHeadsetOn(true);
- mShadowAudioManager.setBluetoothScoOn(false);
+ mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
when(mHeadsetProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
when(mHeadsetProfile.getActiveDevice()).thenReturn(
mBluetoothDevice); // BT device is still activated in this case
@@ -226,7 +227,7 @@
* Preference summary should be "This device"
*/
@Test
- public void noAvailableHeadsetBtDevices_preferenceEnableIsFalse_shouldSetDefaultSummary() {
+ public void updateState_noAvailableHeadsetBtDevices_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
when(mHeadsetProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
index 2b15b8e..1c7c1c4 100644
--- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java
@@ -17,6 +17,9 @@
package com.android.settings.sound;
+import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
@@ -196,7 +199,7 @@
*/
@Test
public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
- mShadowAudioManager.setMusicActiveRemotely(true);
+ mShadowAudioManager.setStream(DEVICE_OUT_REMOTE_SUBMIX);
mController.updateState(mPreference);
@@ -256,8 +259,7 @@
@Test
public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
mShadowAudioManager.setMode(AudioManager.MODE_NORMAL);
- mShadowAudioManager.setWiredHeadsetOn(true);
- mShadowAudioManager.setBluetoothA2dpOn(false);
+ mShadowAudioManager.setStream(DEVICE_OUT_USB_HEADSET);
when(mA2dpProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
when(mA2dpProfile.getActiveDevice()).thenReturn(
mBluetoothDevice); // BT device is still activated in this case
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
index f4f91ed..530bdee 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
@@ -19,13 +19,14 @@
import android.content.Context;
import android.provider.Settings;
-import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SliderPreferenceController;
public class FakeSliderController extends SliderPreferenceController {
private final String settingKey = "fake_slider_key";
+ public static final String AVAILABILITY_KEY = "fake_slider_availability_key";
+
public static final int MAX_STEPS = 9;
public FakeSliderController(Context context, String key) {
@@ -49,6 +50,7 @@
@Override
public int getAvailabilityStatus() {
- return BasePreferenceController.AVAILABLE;
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ AVAILABILITY_KEY, AVAILABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
index c984c6c..d0ce76f 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeToggleController.java
@@ -26,6 +26,8 @@
private String settingKey = "toggle_key";
+ public static final String AVAILABILITY_KEY = "fake_toggle_availability_key";
+
private final int ON = 1;
private final int OFF = 0;
@@ -47,6 +49,7 @@
@Override
public int getAvailabilityStatus() {
- return AVAILABLE;
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ AVAILABILITY_KEY, AVAILABLE);
}
}
diff --git a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
similarity index 82%
rename from tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java
rename to tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
index a7e5d75..1ceaad8 100644
--- a/tests/robotests/src/com/android/settings/slices/FakeUnavailablePreferenceController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeUnavailablePreferenceController.java
@@ -1,4 +1,4 @@
-package com.android.settings.slices;
+package com.android.settings.testutils;
import android.content.Context;
import android.provider.Settings;
@@ -15,7 +15,7 @@
@Override
public int getAvailabilityStatus() {
- return Settings.System.getInt(mContext.getContentResolver(),
+ return Settings.Global.getInt(mContext.getContentResolver(),
AVAILABILITY_KEY, 0);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
index 6817648..0de2156 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
@@ -16,6 +16,15 @@
package com.android.settings.testutils.shadow;
+import static android.media.AudioManager.STREAM_ACCESSIBILITY;
+import static android.media.AudioManager.STREAM_ALARM;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioManager.STREAM_NOTIFICATION;
+import static android.media.AudioManager.STREAM_RING;
+import static android.media.AudioManager.STREAM_SYSTEM;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.AudioManager.STREAM_DTMF;
+
import static org.robolectric.RuntimeEnvironment.application;
import android.media.AudioDeviceCallback;
@@ -32,6 +41,7 @@
@Implements(value = AudioManager.class, inheritImplementationMethods = true)
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
private int mRingerMode;
+ private int mStream;
private boolean mMusicActiveRemotely = false;
private ArrayList<AudioDeviceCallback> mDeviceCallbacks = new ArrayList();
@@ -48,10 +58,12 @@
mRingerMode = mode;
}
+ @Implementation
public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) {
mDeviceCallbacks.add(callback);
}
+ @Implementation
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
if (mDeviceCallbacks.contains(callback)) {
mDeviceCallbacks.remove(callback);
@@ -62,10 +74,32 @@
mMusicActiveRemotely = flag;
}
+ @Implementation
public boolean isMusicActiveRemotely() {
return mMusicActiveRemotely;
}
+ public void setStream(int stream) {
+ mStream = stream;
+ }
+
+ @Implementation
+ public int getDevicesForStream(int streamType) {
+ switch (streamType) {
+ case STREAM_VOICE_CALL:
+ case STREAM_SYSTEM:
+ case STREAM_RING:
+ case STREAM_MUSIC:
+ case STREAM_ALARM:
+ case STREAM_NOTIFICATION:
+ case STREAM_DTMF:
+ case STREAM_ACCESSIBILITY:
+ return mStream;
+ default:
+ return 0;
+ }
+ }
+
@Resetter
public void reset() {
mDeviceCallbacks.clear();
diff --git a/tests/robotests/src/com/android/settings/widget/DisabledCheckBoxPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/DisabledCheckBoxPreferenceTest.java
index 5ab7013..ff10833 100644
--- a/tests/robotests/src/com/android/settings/widget/DisabledCheckBoxPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/DisabledCheckBoxPreferenceTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -70,14 +71,28 @@
}
@Test
- public void checkboxOnClick_doesNothing() {
+ public void checkboxOnClick_checkboxDisabled() {
Preference.OnPreferenceClickListener onClick =
mock(Preference.OnPreferenceClickListener.class);
mPref.setOnPreferenceClickListener(onClick);
inflatePreference();
+ mPref.enableCheckbox(false);
mPref.performClick(mRootView);
verify(onClick, never()).onPreferenceClick(any());
}
+
+ @Test
+ public void checkboxOnClick_checkboxEnabled() {
+ Preference.OnPreferenceClickListener onClick =
+ mock(Preference.OnPreferenceClickListener.class);
+ mPref.setOnPreferenceClickListener(onClick);
+ inflatePreference();
+
+ mPref.enableCheckbox(true);
+ mPref.performClick(mRootView);
+
+ verify(onClick, times(1)).onPreferenceClick(any());
+ }
}
diff --git a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
index 5ba9f8a..865422c 100644
--- a/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/ValidatedEditTextPreferenceTest.java
@@ -116,7 +116,7 @@
mPreference.onBindDialogView(mView);
assertThat(editText.getInputType()
- & (InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_CLASS_TEXT))
+ & (InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_CLASS_TEXT))
.isNotEqualTo(0);
}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
index 60faa2e..7e757ad 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceControllerTest.java
@@ -145,4 +145,21 @@
assertThat(mController.getSecuritySettingForPassword())
.isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK);
}
+
+ @Test
+ public void updateDisplay_shouldSetInputType() {
+ // Set controller password to anything and verify is set.
+ mController.displayPreference(mScreen);
+ mController.onPreferenceChange(mPreference, "1");
+ assertThat(mController.getPassword()).isEqualTo("1");
+
+ // Create a new config using different password
+ final WifiConfiguration config = new WifiConfiguration();
+ config.preSharedKey = "test_1234";
+ when(mWifiManager.getWifiApConfiguration()).thenReturn(config);
+
+ // Call updateDisplay and verify it's changed.
+ mController.updateDisplay();
+ assertThat(mPreference.isPassword()).isTrue();
+ }
}