Merge "Remove On/Off string from Night light slice" into qt-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dfbc02c..c112115 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1562,6 +1562,11 @@
android:exported="false"
android:screenOrientation="portrait"/>
+ <!-- Must not be exported -->
+ <activity android:name=".biometrics.BiometricEnrollActivity$InternalActivity"
+ android:exported="false"
+ android:theme="@style/GlifTheme.Light"/>
+
<activity android:name=".biometrics.BiometricEnrollActivity"
android:exported="true"
android:theme="@style/GlifTheme.Light">
@@ -2687,10 +2692,12 @@
android:excludeFromRecents="true"
android:exported="false" />
- <activity android:name=".sim.SimDialogActivity"
- android:theme="@style/Theme.AlertDialog"
- android:label="@string/sim_settings_title"
- android:excludeFromRecents="true">
+ <activity
+ android:name=".sim.SimDialogActivity"
+ android:theme="@style/Theme.AlertDialog"
+ android:label="@string/sim_settings_title"
+ android:launchMode="singleTop"
+ android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
@@ -2902,7 +2909,7 @@
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
- <action android:name="android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL" />
+ <action android:name="android.settings.APP_BATTERY_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
</intent-filter>
diff --git a/res/drawable/dark_theme.xml b/res/drawable/dark_theme.xml
new file mode 100644
index 0000000..3425002
--- /dev/null
+++ b/res/drawable/dark_theme.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,22C17.52,22 22,17.52 22,12 22,6.48 17.52,2 12,2 6.48,2 2,6.48 2,12 2,17.52 6.48,22 12,22ZM12,3.915c3.889,0 8,4.005 8,8.085 0,4.08 -3.927,7.992 -7.928,7.992z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_battery_saver_accent_24dp.xml b/res/drawable/ic_battery_saver_accent_24dp.xml
index 764402d..31eb193 100644
--- a/res/drawable/ic_battery_saver_accent_24dp.xml
+++ b/res/drawable/ic_battery_saver_accent_24dp.xml
@@ -13,17 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorAccent">
- <path
- android:fillColor="#FF000000"
- android:pathData="M16.67,4H14.5V2h-5v2H7.33C6.6,4 6,4.6 6,5.33V15v5.67C6,21.4 6.6,22 7.33,22h9.33C17.4,22 18,21.4 18,20.67V15V5.33C18,4.6 17.4,4 16.67,4zM16,15v5H8v-5V6h8V15z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M15,12l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_battery_status_bad_24dp"
+ android:tint="?android:attr/colorAccent" />
diff --git a/res/drawable/ic_delete_accent.xml b/res/drawable/ic_delete_accent.xml
index 86a9cca..2f087e8 100644
--- a/res/drawable/ic_delete_accent.xml
+++ b/res/drawable/ic_delete_accent.xml
@@ -13,19 +13,7 @@
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="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorAccent">
- <path
- android:fillColor="#FF000000"
- android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V6h1V4H15zM17,19H7V6h10V19z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,8h2v9h-2z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M13,8h2v9h-2z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_delete"
+ android:tint="?android:attr/colorAccent" />
diff --git a/res/drawable/ic_settings_wireless_white.xml b/res/drawable/ic_settings_wireless_white.xml
index 3271b8b..63be43b 100644
--- a/res/drawable/ic_settings_wireless_white.xml
+++ b/res/drawable/ic_settings_wireless_white.xml
@@ -13,12 +13,7 @@
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="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3l3,-3C13.35,15.34 10.66,15.34 9,17zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_settings_wireless"
+ android:tint="@android:color/white" />
\ No newline at end of file
diff --git a/res/drawable/ic_wifi_signal_0.xml b/res/drawable/ic_wifi_signal_0.xml
index 55faf64..4a3567a 100644
--- a/res/drawable/ic_wifi_signal_0.xml
+++ b/res/drawable/ic_wifi_signal_0.xml
@@ -14,13 +14,7 @@
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="26dp"
- android:height="24dp"
- android:viewportWidth="26"
- android:viewportHeight="24">
- <path
- android:fillAlpha="0.3"
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
-</vector>
\ No newline at end of file
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_wifi_signal_0"
+ android:tint="?attr/wifi_signal_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_wifi_signal_1.xml b/res/drawable/ic_wifi_signal_1.xml
index e0a2072..88a9468 100644
--- a/res/drawable/ic_wifi_signal_1.xml
+++ b/res/drawable/ic_wifi_signal_1.xml
@@ -14,16 +14,7 @@
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="26dp"
- android:height="24dp"
- android:viewportWidth="26"
- android:viewportHeight="24">
- <path
- android:fillAlpha="0.3"
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.1,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.5,6.5L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
- <path
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.1,22.0l5.5,-6.8c-0.2,-0.2 -2.3,-1.9 -5.5,-1.9s-5.3,1.8 -5.5,1.9L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_wifi_signal_1"
+ android:tint="?attr/wifi_signal_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_wifi_signal_2.xml b/res/drawable/ic_wifi_signal_2.xml
index d0daa60..b1c2859d 100644
--- a/res/drawable/ic_wifi_signal_2.xml
+++ b/res/drawable/ic_wifi_signal_2.xml
@@ -14,16 +14,7 @@
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="26dp"
- android:height="24dp"
- android:viewportWidth="26"
- android:viewportHeight="24">
- <path
- android:fillAlpha="0.3"
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
- <path
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0l7.6,-9.4C20.3,12.4 17.4,10.0 13.0,10.0s-7.3,2.4 -7.6,2.7L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_wifi_signal_2"
+ android:tint="?attr/wifi_signal_color" />
diff --git a/res/drawable/ic_wifi_signal_3.xml b/res/drawable/ic_wifi_signal_3.xml
index c542c69..b058eba 100644
--- a/res/drawable/ic_wifi_signal_3.xml
+++ b/res/drawable/ic_wifi_signal_3.xml
@@ -14,16 +14,7 @@
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="26dp"
- android:height="24dp"
- android:viewportWidth="26"
- android:viewportHeight="24">
- <path
- android:fillAlpha="0.3"
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
- <path
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0l9.2,-11.4c-0.4,-0.3 -3.9,-3.2 -9.2,-3.2s-8.9,3.0 -9.2,3.2L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_wifi_signal_3"
+ android:tint="?attr/wifi_signal_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_wifi_signal_4.xml b/res/drawable/ic_wifi_signal_4.xml
index bb7dbd0..e84066a 100644
--- a/res/drawable/ic_wifi_signal_4.xml
+++ b/res/drawable/ic_wifi_signal_4.xml
@@ -14,12 +14,7 @@
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="26dp"
- android:height="24dp"
- android:viewportWidth="26"
- android:viewportHeight="24">
- <path
- android:fillColor="?attr/wifi_signal_color"
- android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
-</vector>
+<com.android.settings.widget.TintDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@*android:drawable/ic_wifi_signal_4"
+ android:tint="?attr/wifi_signal_color" />
\ No newline at end of file
diff --git a/res/drawable/search_bar_selected_background.xml b/res/drawable/search_bar_selected_background.xml
new file mode 100644
index 0000000..b98ed9f
--- /dev/null
+++ b/res/drawable/search_bar_selected_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@color/search_bar_background"/>
+</ripple>
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
index b779526..be947dc 100644
--- a/res/layout/choose_lock_password.xml
+++ b/res/layout/choose_lock_password.xml
@@ -34,7 +34,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/message"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/choose_lock_pattern_common.xml b/res/layout/choose_lock_pattern_common.xml
index 5d3cbca..0a2294f 100644
--- a/res/layout/choose_lock_pattern_common.xml
+++ b/res/layout/choose_lock_pattern_common.xml
@@ -70,7 +70,7 @@
android:paddingRight="0dp">
<TextView
- android:id="@+id/message"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/confirm_lock_password_normal.xml b/res/layout/confirm_lock_password_normal.xml
index 7b04127..61d8505 100644
--- a/res/layout/confirm_lock_password_normal.xml
+++ b/res/layout/confirm_lock_password_normal.xml
@@ -28,7 +28,7 @@
android:layout_height="match_parent">
<TextView
- android:id="@+id/detailsText"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/confirm_lock_pattern_normal_base.xml b/res/layout/confirm_lock_pattern_normal_base.xml
index 03d3367..7e2cf8e 100644
--- a/res/layout/confirm_lock_pattern_normal_base.xml
+++ b/res/layout/confirm_lock_pattern_normal_base.xml
@@ -48,7 +48,7 @@
<TextView
style="@style/SudDescription.Glif"
- android:id="@+id/detailsText"
+ android:id="@+id/sud_layout_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="?attr/sudMarginSides"
diff --git a/res/layout/encryption_interstitial.xml b/res/layout/encryption_interstitial.xml
index a2305f8..61ed292 100644
--- a/res/layout/encryption_interstitial.xml
+++ b/res/layout/encryption_interstitial.xml
@@ -30,7 +30,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/encryption_message"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index b55041a..71a02db 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -33,7 +33,7 @@
android:orientation="vertical">
<com.google.android.setupdesign.view.RichTextView
- android:id="@+id/description_text"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/fingerprint_enroll_enrolling_base.xml b/res/layout/fingerprint_enroll_enrolling_base.xml
index eed6fab..e1a9707 100644
--- a/res/layout/fingerprint_enroll_enrolling_base.xml
+++ b/res/layout/fingerprint_enroll_enrolling_base.xml
@@ -38,7 +38,7 @@
<TextView
style="@style/SudDescription.Glif"
- android:id="@+id/start_message"
+ android:id="@+id/sud_layout_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minLines="3"
diff --git a/res/layout/fingerprint_enroll_find_sensor_base.xml b/res/layout/fingerprint_enroll_find_sensor_base.xml
index 2bef539..ce3104f 100644
--- a/res/layout/fingerprint_enroll_find_sensor_base.xml
+++ b/res/layout/fingerprint_enroll_find_sensor_base.xml
@@ -39,6 +39,7 @@
<TextView
style="@style/SudDescription.Glif"
+ android:id="@+id/sud_layout_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/sud_description_glif_margin_top"
diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml
index d85c56c..1f9167e 100644
--- a/res/layout/fingerprint_enroll_finish_base.xml
+++ b/res/layout/fingerprint_enroll_finish_base.xml
@@ -31,7 +31,7 @@
android:clipChildren="false">
<TextView
- android:id="@+id/message"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/fingerprint_enroll_introduction.xml b/res/layout/fingerprint_enroll_introduction.xml
index 47d2f02..41be2f6 100644
--- a/res/layout/fingerprint_enroll_introduction.xml
+++ b/res/layout/fingerprint_enroll_introduction.xml
@@ -31,7 +31,7 @@
android:orientation="vertical">
<com.google.android.setupdesign.view.RichTextView
- android:id="@+id/description_text"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/master_clear.xml b/res/layout/master_clear.xml
index 6368588..bf22b88 100644
--- a/res/layout/master_clear.xml
+++ b/res/layout/master_clear.xml
@@ -41,6 +41,7 @@
<TextView
style="@style/TextAppearance.SudGlifItemSummary"
+ android:id="@+id/sud_layout_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/master_clear_desc"/>
diff --git a/res/layout/master_clear_confirm.xml b/res/layout/master_clear_confirm.xml
index b4c0270..a236cd3 100644
--- a/res/layout/master_clear_confirm.xml
+++ b/res/layout/master_clear_confirm.xml
@@ -31,7 +31,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/master_clear_confirm"
+ android:id="@+id/sud_layout_description"
style="@style/SudItemTitle.GlifDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/panel_layout.xml b/res/layout/panel_layout.xml
index 3a8045f..c697afc 100644
--- a/res/layout/panel_layout.xml
+++ b/res/layout/panel_layout.xml
@@ -15,50 +15,60 @@
limitations under the License
-->
-<!-- Note: There is a landscape version of this layout. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/panel_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingBottom="24dp"
- android:paddingTop="18dp"
- android:textColor="?android:attr/colorPrimary"
- android:textSize="20sp"/>
-
- <include layout="@layout/panel_slice_list"/>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/panel_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/settings_panel_background" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp">
+ android:orientation="vertical">
- <Button
- android:id="@+id/see_more"
- style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginStart="12dp"
- android:text="@string/see_more"/>
+ <TextView
+ android:id="@+id/panel_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingBottom="24dp"
+ android:paddingTop="18dp"
+ android:textColor="?android:attr/colorPrimary"
+ android:textSize="20sp"/>
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
+ <include layout="@layout/horizontal_divider"/>
- <Button
- android:id="@+id/done"
- style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginEnd="12dp"
- android:text="@string/done"/>
+ <!-- Note: There is a landscape version of panel_slice_list which supports scrolling. -->
+ <include layout="@layout/panel_slice_list"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
+
+ <Button
+ android:id="@+id/see_more"
+ style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginStart="12dp"
+ android:text="@string/see_more"/>
+
+ <Space
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" />
+
+ <Button
+ android:id="@+id/done"
+ style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginEnd="12dp"
+ android:text="@string/done"/>
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index fc8cc26..5c918fc 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -25,6 +25,19 @@
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true">
+ <!-- Phone index -->
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/phone_index_label"
+ style="@style/info_label"
+ />
+
+ <Spinner android:id="@+id/phoneIndex"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
<!-- IMEI -->
<LinearLayout style="@style/entry_layout">
<TextView android:text="@string/radio_info_imei_label" style="@style/info_label" />
@@ -37,6 +50,18 @@
<TextView android:id="@+id/number" style="@style/info_value" />
</LinearLayout>
+ <!-- Subscription ID -->
+ <LinearLayout style="@style/entry_layout">
+ <TextView android:text="@string/radio_info_subid" style="@style/info_label" />
+ <TextView android:id="@+id/subid" style="@style/info_value" />
+ </LinearLayout>
+
+ <!-- Default data subscription -->
+ <LinearLayout style="@style/entry_layout">
+ <TextView android:text="@string/radio_info_dds" style="@style/info_label" />
+ <TextView android:id="@+id/dds" style="@style/info_value" />
+ </LinearLayout>
+
<!-- IMSI -->
<LinearLayout style="@style/entry_layout">
<TextView android:text="@string/radio_info_imsi_label" style="@style/info_label" />
diff --git a/res/layout/redaction_interstitial.xml b/res/layout/redaction_interstitial.xml
index f911572..0ad8b4d 100644
--- a/res/layout/redaction_interstitial.xml
+++ b/res/layout/redaction_interstitial.xml
@@ -33,7 +33,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/message"
+ android:id="@+id/sud_layout_description"
style="@style/SudDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/screen_zoom_preview_1.xml b/res/layout/screen_zoom_preview_1.xml
index b7d2d15..65d27ee 100644
--- a/res/layout/screen_zoom_preview_1.xml
+++ b/res/layout/screen_zoom_preview_1.xml
@@ -28,7 +28,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/conversation_background"
+ android:background="?android:attr/colorBackgroundFloating"
android:paddingTop="@dimen/conversation_message_list_padding"
android:paddingStart="@dimen/conversation_message_list_padding"
android:paddingEnd="@dimen/conversation_message_list_padding"
diff --git a/res/layout/search_bar.xml b/res/layout/search_bar.xml
index dbd61df..420c965 100644
--- a/res/layout/search_bar.xml
+++ b/res/layout/search_bar.xml
@@ -28,7 +28,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/search_bar_height"
android:layout_marginStart="-2dp"
- android:background="?android:attr/selectableItemBackground"
+ android:background="@drawable/search_bar_selected_background"
android:contentInsetStartWithNavigation="@dimen/search_bar_content_inset"
android:navigationIcon="@drawable/ic_homepage_search">
<TextView
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index c86bccf..856bd80 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -25,7 +25,6 @@
android:id="@+id/main_content_scrollable_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:importantForAccessibility="no"
app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
<LinearLayout
diff --git a/res/layout/settings_panel.xml b/res/layout/settings_panel.xml
index 3405ef0..0b0b227 100644
--- a/res/layout/settings_panel.xml
+++ b/res/layout/settings_panel.xml
@@ -15,6 +15,5 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_content"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:animateLayoutChanges="true"/>
\ No newline at end of file
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"/>
\ No newline at end of file
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 8a6b697..f6f86f0 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <color name="switchbar_text_color">@android:color/black</color>
<color name="switchbar_switch_track_tint">#82000000</color>
<color name="switchbar_switch_thumb_tint">@android:color/black</color>
<color name="homepage_accessibility_background">#783BE5</color>
@@ -24,5 +23,6 @@
<color name="homepage_status_bar_color">#cc000000</color>
<color name="homepage_card_dismissal_background">@*android:color/material_grey_900</color>
<color name="contextual_card_background">@*android:color/material_grey_900</color>
+ <color name="search_bar_background">@*android:color/material_grey_800</color>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index be6345b..83269cc 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -164,6 +164,11 @@
<attr name="textOff" format="reference" />
</declare-styleable>
+ <declare-styleable name="TintDrawable">
+ <attr name="android:tint" />
+ <attr name="android:drawable" />
+ </declare-styleable>
+
<attr name="twoStateButtonPreferenceStyle" format="reference" />
<attr name="fingerprint_layout_theme" format="reference" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5d681ca..23fe255 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -63,7 +63,6 @@
<color name="timestamp_text_incoming">#99ffffff</color>
<color name="message_bubble_incoming">#689f38</color>
<color name="message_bubble_outgoing">#ffffffff</color>
- <color name="conversation_background">#eeeeee</color>
<color name="message_icon_background_incoming">#689f38</color>
<color name="message_icon_text_incoming">#ffffffff</color>
<color name="message_icon_background_outgoing">#4285f4</color>
@@ -103,7 +102,7 @@
<color name="contextual_card_background">@*android:color/background_device_default_light</color>
<!-- End of dashboard/homepage icon background colors -->
- <color name="switchbar_text_color">@android:color/white</color>
+ <color name="switchbar_background_color">@*android:color/material_grey_600</color>
<color name="switchbar_switch_track_tint">#BFFFFFFF</color>
<color name="switchbar_switch_thumb_tint">@android:color/white</color>
@@ -140,4 +139,7 @@
<color name="qr_background_color">#b3ffffff</color> <!-- 70% white transparency -->
<!-- End of QR code scanner colors -->
+ <!-- Search bar background color -->
+ <color name="search_bar_background">@android:color/white</color>
+
</resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1567c75..6e85806 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -485,6 +485,10 @@
<string name="proxy_url_title">"PAC URL: "</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_subid">Current subId:</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="radio_info_dds">SubId of default data SIM:</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_dl_kbps">DL Bandwidth (kbps):</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_ul_kbps">UL Bandwidth (kbps):</string>
@@ -531,6 +535,8 @@
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_data_network_type_label">Data Network Type:</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
+ <string name="phone_index_label">Select phone index</string>
+ <!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_set_perferred_label">Set Preferred Network Type:</string>
<!-- Radio Info screen. Label for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="radio_info_ping_hostname_v4">Ping Hostname(www.google.com) IPv4:</string>
@@ -884,9 +890,9 @@
<string name="security_settings_face_preference_title">Face authentication</string>
<!-- Button shown which shows accessibility toggles for face enrollment when clicked. [CHAR LIMIT=32] -->
<string name="security_settings_face_enroll_introduction_accessibility">Use accessibility setup</string>
- <!-- Message shown for a toggle which when disabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
+ <!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_accessibility_diversity"></string>
- <!-- Message shown for a toggle which when disabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
+ <!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_accessibility_vision"></string>
<!-- Button text to cancel enrollment from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_face_enroll_introduction_cancel">Cancel</string>
@@ -2237,6 +2243,8 @@
<string name="wifi_carrier_content">Connect via <xliff:g id="name">%1$s</xliff:g></string>
<string name="wifi_scan_always_turnon_message">To improve location accuracy and for other purposes, <xliff:g id="app_name">%1$s</xliff:g> wants to turn on network scanning, even when Wi-Fi is off.\n\nAllow this for all apps that want to scan?</string>
+ <!-- Message to inform user, an unknown app want to enable network scanning. [CHAR LIMIT=200] -->
+ <string name="wifi_scan_always_turn_on_message_unknown">To improve location accuracy and for other purposes, an unknown app wants to turn on network scanning, even when Wi\u2011Fi is off.\n\nAllow this for all apps that want to scan?</string>
<!-- Message informing the user how to turn off [CHAR LIMIT=200] -->
<string name="wifi_scan_always_turnoff_message">To turn this off, go to Advanced in the overflow menu.</string>
<string name="wifi_scan_always_confirm_allow">Allow</string>
@@ -2783,7 +2791,7 @@
<!-- Display settings screen, display white balance settings title [CHAR LIMIT=30] -->
<string name="display_white_balance_title">Display white balance</string>
<!-- Display settings screen, setting option name to enable adaptive sleep [CHAR LIMIT=30] -->
- <string name="adaptive_sleep_title">Screen aware</string>
+ <string name="adaptive_sleep_title">Screen attention</string>
<!-- Setting option summary when adaptive sleep is on [CHAR LIMIT=NONE] -->
<string name="adaptive_sleep_summary_on">On / Screen won’t turn off if you’re looking at it</string>
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
@@ -2791,7 +2799,7 @@
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
<string name="adaptive_sleep_description">Prevents your screen from turning off if you’re looking at it.</string>
<!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
- <string name="adaptive_sleep_privacy">Screen aware uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
+ <string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
<!-- Night display screen, setting option name to enable night display (renamed "Night Light" with title caps). [CHAR LIMIT=30] -->
@@ -5321,11 +5329,11 @@
<!-- Summary for the battery high usage tip, which presents battery may run out earlier [CHAR LIMIT=NONE] -->
<string name="battery_tip_high_usage_summary">Battery may run out earlier than usual</string>
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
- <string name="battery_tip_dialog_message" product="default">Your phone has been used more than usual. Your battery may run out sooner than expected.\n\nMost used apps since full charge:</string>
+ <string name="battery_tip_dialog_message" product="default">Your phone has been used more than usual. Your battery may run out sooner than expected.\n\nTop apps by battery usage:</string>
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
- <string name="battery_tip_dialog_message" product="tablet">Your tablet has been used more than usual. Your battery may run out sooner than expected.\n\nMost used apps since full charge:</string>
+ <string name="battery_tip_dialog_message" product="tablet">Your tablet has been used more than usual. Your battery may run out sooner than expected.\n\nTop apps by battery usage:</string>
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
- <string name="battery_tip_dialog_message" product="device">Your device has been used more than usual. Your battery may run out sooner than expected.\n\nMost used apps since full charge:</string>
+ <string name="battery_tip_dialog_message" product="device">Your device has been used more than usual. Your battery may run out sooner than expected.\n\nTop apps by battery usage:</string>
<!-- Footer message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
<string name="battery_tip_dialog_message_footer">Includes high-power background activity</string>
<!-- Title for restricted app preference, showing how many app need to be restricted [CHAR LIMIT=NONE] -->
@@ -9892,17 +9900,14 @@
<string name="demo_mode">System UI demo mode</string>
<!-- [CHAR LIMIT=60] Name of setting that changes the UI to dark -->
- <string name="dark_ui_mode">Theme</string>
-
- <!-- [CHAR LIMIT=60] Name of dev option that changes the color of the UI -->
- <string name="dark_ui_mode_title">Choose Theme</string>
-
- <!-- [CHAR_LIMIT=NONE] Summary that is shown in the footer when light mode is selected -->
- <string name="dark_ui_settings_light_summary">This setting also applies to apps</string>
+ <string name="dark_ui_mode">Dark Theme</string>
<!-- [CHAR_LIMIT=NONE] Summary that is shown in the footer when dark mode is selected -->
<string name="dark_ui_settings_dark_summary">Supported apps will also switch to dark theme</string>
+ <!-- [CHAR_LIMIT=40] Positive button text in dark theme notification -->
+ <string name="dark_ui_settings_dialog_acknowledge">Got it</string>
+
<!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
<string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
@@ -11017,12 +11022,12 @@
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
- <!-- Keywords for Content Capture / Smart Suggestions feature [CHAR_LIMIT=none] -->
- <string name="keywords_content_capture">content capture, smart suggestions</string>
+ <!-- Keywords for Content Capture feature [CHAR_LIMIT=none] -->
+ <string name="keywords_content_capture">content capture</string>
<!-- Title of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=none]-->
- <string name="content_capture">Smart Suggestions</string>
- <!-- Description of the 'Content Capture / Smart Suggestions' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
- <string name="content_capture_summary">Allow Android to save information seen on your screen or heard in video or audio content. Android makes helpful suggestions based on your device activity.</string>
+ <string name="content_capture">Content Capture</string>
+ <!-- Description of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
+ <string name="content_capture_summary">Allow apps to send content to the Android system</string>
<!-- Title for the button to initiate a heap dump for the system server. [CHAR LIMIT=NONE] -->
<string name="capture_system_heap_dump_title">Capture system heap dump</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b51a45d..9a02fcd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -422,6 +422,7 @@
<item name="cardElevation">0dp</item>
<item name="strokeColor">@color/contextual_card_stroke_color</item>
<item name="strokeWidth">1dp</item>
+ <item name="rippleColor">?android:attr/colorControlHighlight</item>
</style>
<style name="SearchBarStyle">
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 196e85b..5db5f2f 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -87,10 +87,10 @@
<item name="android:backgroundDimEnabled">false</item>
</style>
- <style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.ActionBar">
+ <style name="ThemeOverlay.SwitchBar.Settings" parent="@*android:style/ThemeOverlay.DeviceDefault.ActionBar">
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
- <item name="switchBarBackgroundColor">?android:attr/textColorSecondary</item>
+ <item name="switchBarBackgroundColor">@color/switchbar_background_color</item>
<item name="switchBarBackgroundActivatedColor">?android:attr/colorAccent</item>
<item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item>
</style>
@@ -203,7 +203,7 @@
<!-- Note that Dialog themes do not set list dividers -->
<style name="Theme.BottomDialog" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
- <item name="android:windowBackground">@drawable/settings_panel_background</item>
+ <item name="android:windowBackground">@null</item>
<item name="android:dividerHorizontal">@*android:drawable/list_divider_material</item>
<item name="android:windowNoTitle">true</item>
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
diff --git a/res/values/themes_suw.xml b/res/values/themes_suw.xml
index 9bb67cf..add2fed 100644
--- a/res/values/themes_suw.xml
+++ b/res/values/themes_suw.xml
@@ -191,12 +191,20 @@
</style>
<style name="SuwAlertDialogThemeCompat" parent="@style/Theme.AppCompat.Dialog.Alert">
+ <!-- Referenced SudThemeGlifV3 style -->
+ <item name="android:textAllCaps">false</item>
+
+ <item name="android:windowSoftInputMode">adjustResize</item>
<!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
</style>
<style name="SuwAlertDialogThemeCompat.Light" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
+ <!-- Referenced SudThemeGlifV3.Light style -->
+ <item name="android:textAllCaps">false</item>
+
+ <item name="android:windowSoftInputMode">adjustResize</item>
<!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 26849d1..b4968f8 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -58,11 +58,10 @@
android:title="@string/screen_zoom_title"
settings:searchable="false"/>
- <Preference
+ <SwitchPreference
android:key="dark_ui_mode_accessibility"
- android:fragment="com.android.settings.display.DarkUISettings"
android:title="@string/dark_ui_mode"
- settings:searchable="false" />
+ settings:searchable="false"/>
<Preference
android:fragment="com.android.settings.accessibility.MagnificationPreferenceFragment"
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index a612a47..bcd5100 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -56,11 +56,10 @@
</com.android.settingslib.RestrictedPreference>
- <Preference
+ <SwitchPreference
android:key="dark_ui_mode"
- android:fragment="com.android.settings.display.DarkUISettings"
android:title="@string/dark_ui_mode"
- settings:searchable="false"
+ settings:keywords="@string/keywords_dark_ui_mode"
settings:controller="com.android.settings.display.DarkUIPreferenceController"/>
<!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index e610df2..d99cc00 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -103,7 +103,7 @@
settings:useAdminDisabledSummary="true"
settings:keywords="@string/keywords_sounds_and_notifications_interruptions"
settings:allowDividerAbove="true"
- settings:controller="com.android.settings.notification.ZenModeSoundSettingsPreferenceController"/>
+ settings:controller="com.android.settings.notification.ZenModePreferenceController"/>
<Preference
android:key="gesture_prevent_ringing_sound"
diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml
index 832150a..320a37c 100644
--- a/res/xml/zen_mode_settings.xml
+++ b/res/xml/zen_mode_settings.xml
@@ -20,7 +20,7 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="zen_mode_settings"
android:title="@string/zen_mode_settings_title"
- settings:keywords="@string/keywords_zen_mode_settings">
+ settings:searchable="false">
<PreferenceCategory
android:key="zen_mode_settings_category_behavior"
@@ -66,11 +66,13 @@
<!-- Turn on DND button -->
<com.android.settingslib.widget.LayoutPreference
- android:key="zen_mode_settings_button_container"
+ android:key="zen_mode_toggle"
+ android:title="@string/zen_mode_settings_title"
android:selectable="false"
android:layout="@layout/zen_mode_settings_button"
settings:allowDividerAbove="true"
- settings:allowDividerBelow="true"/>
+ settings:allowDividerBelow="true"
+ settings:keywords="@string/keywords_zen_mode_settings"/>
<!-- Footer that shows if user is put into alarms only or total silence mode by an app -->
<com.android.settingslib.widget.FooterPreference/>
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index b67e6e8..eb77d4a 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -18,11 +18,13 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.SearchIndexableResource;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.display.BrightnessLevelPreferenceController;
import com.android.settings.display.CameraGesturePreferenceController;
+import com.android.settings.display.DarkUIPreferenceController;
import com.android.settings.display.LiftToWakePreferenceController;
import com.android.settings.display.NightDisplayPreferenceController;
import com.android.settings.display.NightModePreferenceController;
@@ -63,6 +65,12 @@
}
@Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ use(DarkUIPreferenceController.class).setParentFragment(this);
+ }
+
+ @Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getSettingsLifecycle());
}
diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java
index 317e3bd..515b1b0 100644
--- a/src/com/android/settings/EncryptionInterstitial.java
+++ b/src/com/android/settings/EncryptionInterstitial.java
@@ -141,7 +141,7 @@
R.string.encryption_interstitial_message_password;
break;
}
- TextView message = (TextView) getActivity().findViewById(R.id.encryption_message);
+ TextView message = (TextView) getActivity().findViewById(R.id.sud_layout_description);
message.setText(msgId);
setRequirePasswordState(getActivity().getIntent().getBooleanExtra(
diff --git a/src/com/android/settings/MasterClearConfirm.java b/src/com/android/settings/MasterClearConfirm.java
index ac97c11..a8c4341 100644
--- a/src/com/android/settings/MasterClearConfirm.java
+++ b/src/com/android/settings/MasterClearConfirm.java
@@ -207,7 +207,7 @@
private void setAccessibilityTitle() {
CharSequence currentTitle = getActivity().getTitle();
- TextView confirmationMessage = mContentView.findViewById(R.id.master_clear_confirm);
+ TextView confirmationMessage = mContentView.findViewById(R.id.sud_layout_description);
if (confirmationMessage != null) {
String accessibleText = new StringBuilder(currentTitle).append(",").append(
confirmationMessage.getText()).toString();
@@ -218,7 +218,7 @@
@VisibleForTesting
void setSubtitle() {
if (mEraseEsims) {
- ((TextView) mContentView.findViewById(R.id.master_clear_confirm))
+ ((TextView) mContentView.findViewById(R.id.sud_layout_description))
.setText(R.string.master_clear_final_desc_esim);
}
}
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 0b7d1be..e0ce1c0 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -125,6 +125,7 @@
"Unknown"
};
+ private static String[] mPhoneIndexLabels;
private static final int CELL_INFO_LIST_RATE_DISABLED = Integer.MAX_VALUE;
private static final int CELL_INFO_LIST_RATE_MAX = 0;
@@ -160,7 +161,7 @@
60000
};
- private void log(String s) {
+ private static void log(String s) {
Log.d(TAG, s);
}
@@ -171,15 +172,17 @@
private static final int EVENT_QUERY_SMSC_DONE = 1005;
private static final int EVENT_UPDATE_SMSC_DONE = 1006;
- private static final int MENU_ITEM_SELECT_BAND = 0;
- private static final int MENU_ITEM_VIEW_ADN = 1;
- private static final int MENU_ITEM_VIEW_FDN = 2;
- private static final int MENU_ITEM_VIEW_SDN = 3;
- private static final int MENU_ITEM_GET_IMS_STATUS = 4;
- private static final int MENU_ITEM_TOGGLE_DATA = 5;
+ private static final int MENU_ITEM_SELECT_BAND = 0;
+ private static final int MENU_ITEM_VIEW_ADN = 1;
+ private static final int MENU_ITEM_VIEW_FDN = 2;
+ private static final int MENU_ITEM_VIEW_SDN = 3;
+ private static final int MENU_ITEM_GET_IMS_STATUS = 4;
+ private static final int MENU_ITEM_TOGGLE_DATA = 5;
private TextView mDeviceId; //DeviceId is the IMEI in GSM and the MEID in CDMA
private TextView number;
+ private TextView mSubscriptionId;
+ private TextView mDds;
private TextView mSubscriberId;
private TextView callState;
private TextView operatorName;
@@ -219,12 +222,13 @@
private Switch cbrsDataSwitch;
private Switch dsdsSwitch;
private Spinner preferredNetworkType;
+ private Spinner mSelectPhoneIndex;
private Spinner cellInfoRefreshRateSpinner;
private ConnectivityManager mConnectivityManager;
private TelephonyManager mTelephonyManager;
private ImsManager mImsManager = null;
- private Phone phone = null;
+ private Phone mPhone = null;
private String mPingHostnameResultV4;
private String mPingHostnameResultV6;
@@ -237,6 +241,7 @@
private int mPreferredNetworkTypeResult;
private int mCellInfoRefreshRateIndex;
+ private int mSelectedPhoneIndex;
private final NetworkRequest mDefaultNetworkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -251,7 +256,9 @@
}
};
- private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ // not final because we need to recreate this object to register on a new subId (b/117555407)
+ private PhoneStateListener mPhoneStateListener = new RadioInfoPhoneStateListener();
+ private class RadioInfoPhoneStateListener extends PhoneStateListener {
@Override
public void onDataConnectionStateChanged(int state) {
updateDataState();
@@ -319,7 +326,7 @@
updatePhysicalChannelConfiguration(configs);
}
- };
+ }
private void updatePhysicalChannelConfiguration(List<PhysicalChannelConfig> configs) {
StringBuilder sb = new StringBuilder();
@@ -346,6 +353,21 @@
preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
}
+ private void updatePhoneIndex(int phoneIndex, int subId) {
+ // unregister listeners on the old subId
+ unregisterPhoneStateListener();
+ mTelephonyManager.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
+
+ // update the subId
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+
+ // update the phoneId
+ mImsManager = ImsManager.getInstance(getApplicationContext(), phoneIndex);
+ mPhone = PhoneFactory.getPhone(phoneIndex);
+
+ updateAllFields();
+ }
+
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -404,15 +426,17 @@
mTelephonyManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
mConnectivityManager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
- phone = PhoneFactory.getDefaultPhone();
+ mPhone = PhoneFactory.getDefaultPhone();
- //TODO: Need to update this if the default phoneId changes?
- // Better to have an instance per phone?
mImsManager = ImsManager.getInstance(getApplicationContext(),
SubscriptionManager.getDefaultVoicePhoneId());
+ mPhoneIndexLabels = getPhoneIndexLabels(mTelephonyManager);
+
mDeviceId = (TextView) findViewById(R.id.imei);
number = (TextView) findViewById(R.id.number);
+ mSubscriptionId = (TextView) findViewById(R.id.subid);
+ mDds = (TextView) findViewById(R.id.dds);
mSubscriberId = (TextView) findViewById(R.id.imsi);
callState = (TextView) findViewById(R.id.call);
operatorName = (TextView) findViewById(R.id.operator);
@@ -439,10 +463,17 @@
mPhyChanConfig = (TextView) findViewById(R.id.phy_chan_config);
preferredNetworkType = (Spinner) findViewById(R.id.preferredNetworkType);
- ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
+ ArrayAdapter<String> preferredNetworkTypeAdapter = new ArrayAdapter<String> (this,
android.R.layout.simple_spinner_item, mPreferredNetworkLabels);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- preferredNetworkType.setAdapter(adapter);
+ preferredNetworkTypeAdapter
+ .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ preferredNetworkType.setAdapter(preferredNetworkTypeAdapter);
+
+ mSelectPhoneIndex = (Spinner) findViewById(R.id.phoneIndex);
+ ArrayAdapter<String> phoneIndexAdapter = new ArrayAdapter<String> (this,
+ android.R.layout.simple_spinner_item, mPhoneIndexLabels);
+ phoneIndexAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mSelectPhoneIndex.setAdapter(phoneIndexAdapter);
cellInfoRefreshRateSpinner = (Spinner) findViewById(R.id.cell_info_rate_select);
ArrayAdapter<String> cellInfoAdapter = new ArrayAdapter<String>(this,
@@ -455,7 +486,7 @@
imsWfcProvisionedSwitch = (Switch) findViewById(R.id.wfc_provisioned_switch);
eabProvisionedSwitch = (Switch) findViewById(R.id.eab_provisioned_switch);
- if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+ if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
imsVolteProvisionedSwitch.setVisibility(View.GONE);
imsVtProvisionedSwitch.setVisibility(View.GONE);
imsWfcProvisionedSwitch.setVisibility(View.GONE);
@@ -513,9 +544,10 @@
mCellInfoRefreshRateIndex = 0; //disabled
mPreferredNetworkTypeResult = mPreferredNetworkLabels.length - 1; //Unknown
+ mSelectedPhoneIndex = 0; //phone 0
//FIXME: Replace with TelephonyManager call
- phone.getPreferredNetworkType(
+ mPhone.getPreferredNetworkType(
mHandler.obtainMessage(EVENT_QUERY_PREFERRED_TYPE_DONE));
restoreFromBundle(icicle);
@@ -527,6 +559,10 @@
log("Started onResume");
+ updateAllFields();
+ }
+
+ private void updateAllFields() {
updateMessageWaiting();
updateCallRedirect();
updateDataState();
@@ -539,6 +575,7 @@
updateLocation(mCellLocationResult);
updateCellInfo(mCellInfoResult);
+ updateSubscriptionIds();
mPingHostnameV4.setText(mPingHostnameResultV4);
mPingHostnameV6.setText(mPingHostnameResultV6);
@@ -552,6 +589,10 @@
preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
+ // set phone index
+ mSelectPhoneIndex.setSelection(mSelectedPhoneIndex, true);
+ mSelectPhoneIndex.setOnItemSelectedListener(mSelectPhoneIndexHandler);
+
radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
imsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
imsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
@@ -563,19 +604,8 @@
cbrsDataSwitch.setOnCheckedChangeListener(mCbrsDataSwitchChangeListener);
}
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_CALL_STATE
- //b/27803938 - RadioInfo currently cannot read PRECISE_CALL_STATE
- // | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
- | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_DATA_ACTIVITY
- | PhoneStateListener.LISTEN_CELL_LOCATION
- | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
- | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
- | PhoneStateListener.LISTEN_CELL_INFO
- | PhoneStateListener.LISTEN_SERVICE_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION);
+ unregisterPhoneStateListener();
+ registerPhoneStateListener();
mConnectivityManager.registerNetworkCallback(
mDefaultNetworkRequest, mNetworkCallback, mHandler);
@@ -611,6 +641,8 @@
mPreferredNetworkTypeResult = b.getInt("mPreferredNetworkTypeResult",
mPreferredNetworkLabels.length - 1);
+ mSelectedPhoneIndex = b.getInt("mSelectedPhoneIndex", 0);
+
mCellInfoRefreshRateIndex = b.getInt("mCellInfoRefreshRateIndex", 0);
}
@@ -621,6 +653,7 @@
outState.putString("mHttpClientTestResult", mHttpClientTestResult);
outState.putInt("mPreferredNetworkTypeResult", mPreferredNetworkTypeResult);
+ outState.putInt("mSelectedPhoneIndex", mSelectedPhoneIndex);
outState.putInt("mCellInfoRefreshRateIndex", mCellInfoRefreshRateIndex);
}
@@ -636,7 +669,7 @@
R.string.radioInfo_menu_viewFDN).setOnMenuItemClickListener(mViewFDNCallback);
menu.add(1, MENU_ITEM_VIEW_SDN, 0,
R.string.radioInfo_menu_viewSDN).setOnMenuItemClickListener(mViewSDNCallback);
- if (ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+ if (ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
menu.add(1, MENU_ITEM_GET_IMS_STATUS,
0, R.string.radioInfo_menu_getIMS).setOnMenuItemClickListener(mGetImsStatus);
}
@@ -668,9 +701,61 @@
return true;
}
+ // returns array of string labels for each phone index. The array index is equal to the phone
+ // index.
+ private static String[] getPhoneIndexLabels(TelephonyManager tm) {
+ int phones = tm.getPhoneCount();
+ String[] labels = new String[phones];
+ for (int i = 0; i < phones; i++) {
+ labels[i] = "Phone " + i;
+ }
+ return labels;
+ }
+
+ private void unregisterPhoneStateListener() {
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+
+ // clear all fields so they are blank until the next listener event occurs
+ operatorName.setText("");
+ gprsState.setText("");
+ dataNetwork.setText("");
+ voiceNetwork.setText("");
+ sent.setText("");
+ received.setText("");
+ callState.setText("");
+ mLocation.setText("");
+ mMwiValue = false;
+ mMwi.setText("");
+ mCfiValue = false;
+ mCfi.setText("");
+ mCellInfo.setText("");
+ dBm.setText("");
+ gsmState.setText("");
+ roamingState.setText("");
+ mPhyChanConfig.setText("");
+ }
+
+ // register mPhoneStateListener for relevant fields using the current TelephonyManager
+ private void registerPhoneStateListener() {
+ mPhoneStateListener = new RadioInfoPhoneStateListener();
+ mTelephonyManager.listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_CALL_STATE
+ //b/27803938 - RadioInfo currently cannot read PRECISE_CALL_STATE
+ // | PhoneStateListener.LISTEN_PRECISE_CALL_STATE
+ | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_DATA_ACTIVITY
+ | PhoneStateListener.LISTEN_CELL_LOCATION
+ | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+ | PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
+ | PhoneStateListener.LISTEN_CELL_INFO
+ | PhoneStateListener.LISTEN_SERVICE_STATE
+ | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
+ | PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION);
+ }
+
private void updateDnsCheckState() {
//FIXME: Replace with a TelephonyManager call
- dnsCheckState.setText(phone.isDnsCheckDisabled() ?
+ dnsCheckState.setText(mPhone.isDnsCheckDisabled() ?
"0.0.0.0 allowed" :"0.0.0.0 not allowed");
}
@@ -889,6 +974,11 @@
mCellInfo.setText(buildCellInfoString(arrayCi));
}
+ private final void updateSubscriptionIds() {
+ mSubscriptionId.setText(Integer.toString(mPhone.getSubId()));
+ mDds.setText(Integer.toString(SubscriptionManager.getDefaultDataSubscriptionId()));
+ }
+
private final void
updateMessageWaiting() {
mMwi.setText(String.valueOf(mMwiValue));
@@ -975,12 +1065,12 @@
}
private final void updateNetworkType() {
- if(phone != null) {
- ServiceState ss = phone.getServiceState();
+ if(mPhone != null) {
+ ServiceState ss = mPhone.getServiceState();
dataNetwork.setText(ServiceState.rilRadioTechnologyToString(
- phone.getServiceState().getRilDataRadioTechnology()));
+ mPhone.getServiceState().getRilDataRadioTechnology()));
voiceNetwork.setText(ServiceState.rilRadioTechnologyToString(
- phone.getServiceState().getRilVoiceRadioTechnology()));
+ mPhone.getServiceState().getRilVoiceRadioTechnology()));
}
}
@@ -989,16 +1079,16 @@
String s;
Resources r = getResources();
- s = phone.getDeviceId();
+ s = mPhone.getDeviceId();
if (s == null) s = r.getString(R.string.radioInfo_unknown);
mDeviceId.setText(s);
- s = phone.getSubscriberId();
+ s = mPhone.getSubscriberId();
if (s == null) s = r.getString(R.string.radioInfo_unknown);
mSubscriberId.setText(s);
//FIXME: Replace with a TelephonyManager call
- s = phone.getLine1Number();
+ s = mPhone.getLine1Number();
if (s == null) s = r.getString(R.string.radioInfo_unknown);
number.setText(s);
}
@@ -1075,7 +1165,7 @@
private void refreshSmsc() {
//FIXME: Replace with a TelephonyManager call
- phone.getSmscAddress(mHandler.obtainMessage(EVENT_QUERY_SMSC_DONE));
+ mPhone.getSmscAddress(mHandler.obtainMessage(EVENT_QUERY_SMSC_DONE));
}
private final void updateAllCellInfo() {
@@ -1147,8 +1237,7 @@
// the content provider, which causes it to be loaded in a process
// other than the Dialer process, which causes a lot of stuff to
// break.
- intent.setClassName("com.android.phone",
- "com.android.phone.SimContacts");
+ intent.setClassName("com.android.phone", "com.android.phone.SimContacts");
startActivity(intent);
return true;
}
@@ -1162,8 +1251,7 @@
// the content provider, which causes it to be loaded in a process
// other than the Dialer process, which causes a lot of stuff to
// break.
- intent.setClassName("com.android.phone",
- "com.android.phone.settings.fdn.FdnList");
+ intent.setClassName("com.android.phone", "com.android.phone.settings.fdn.FdnList");
startActivity(intent);
return true;
}
@@ -1178,8 +1266,7 @@
// the content provider, which causes it to be loaded in a process
// other than the Dialer process, which causes a lot of stuff to
// break.
- intent.setClassName("com.android.phone",
- "com.android.phone.ADNList");
+ intent.setClassName("com.android.phone", "com.android.phone.ADNList");
startActivity(intent);
return true;
}
@@ -1187,11 +1274,11 @@
private MenuItem.OnMenuItemClickListener mGetImsStatus = new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- boolean isImsRegistered = phone.isImsRegistered();
- boolean availableVolte = phone.isVolteEnabled();
- boolean availableWfc = phone.isWifiCallingEnabled();
- boolean availableVt = phone.isVideoEnabled();
- boolean availableUt = phone.isUtEnabled();
+ boolean isImsRegistered = mPhone.isImsRegistered();
+ boolean availableVolte = mPhone.isVolteEnabled();
+ boolean availableWfc = mPhone.isWifiCallingEnabled();
+ boolean availableVt = mPhone.isVideoEnabled();
+ boolean availableUt = mPhone.isUtEnabled();
final String imsRegString = isImsRegistered ?
getString(R.string.radio_info_ims_reg_status_registered) :
@@ -1248,7 +1335,7 @@
private boolean isRadioOn() {
//FIXME: Replace with a TelephonyManager call
- return phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
+ return mPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
}
private void updateRadioPowerState() {
@@ -1280,7 +1367,7 @@
}
void setImsConfigProvisionedState(int configItem, boolean state) {
- if (phone != null && mImsManager != null) {
+ if (mPhone != null && mImsManager != null) {
QueuedWork.queue(new Runnable() {
public void run() {
try {
@@ -1299,14 +1386,14 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
log("toggle radio power: currently " + (isRadioOn()?"on":"off"));
- phone.setRadioPower(isChecked);
+ mPhone.setRadioPower(isChecked);
}
};
private boolean isImsVolteProvisioned() {
- if (phone != null && mImsManager != null) {
- return mImsManager.isVolteEnabledByPlatform(phone.getContext())
- && mImsManager.isVolteProvisionedOnDevice(phone.getContext());
+ if (mPhone != null && mImsManager != null) {
+ return mImsManager.isVolteEnabledByPlatform(mPhone.getContext())
+ && mImsManager.isVolteProvisionedOnDevice(mPhone.getContext());
}
return false;
}
@@ -1319,9 +1406,9 @@
};
private boolean isImsVtProvisioned() {
- if (phone != null && mImsManager != null) {
- return mImsManager.isVtEnabledByPlatform(phone.getContext())
- && mImsManager.isVtProvisionedOnDevice(phone.getContext());
+ if (mPhone != null && mImsManager != null) {
+ return mImsManager.isVtEnabledByPlatform(mPhone.getContext())
+ && mImsManager.isVtProvisionedOnDevice(mPhone.getContext());
}
return false;
}
@@ -1334,9 +1421,9 @@
};
private boolean isImsWfcProvisioned() {
- if (phone != null && mImsManager != null) {
- return mImsManager.isWfcEnabledByPlatform(phone.getContext())
- && mImsManager.isWfcProvisionedOnDevice(phone.getContext());
+ if (mPhone != null && mImsManager != null) {
+ return mImsManager.isWfcEnabledByPlatform(mPhone.getContext())
+ && mImsManager.isWfcProvisionedOnDevice(mPhone.getContext());
}
return false;
}
@@ -1391,7 +1478,7 @@
}
private void updateImsProvisionedState() {
- if (!ImsManager.isImsSupportedOnDevice(phone.getContext())) {
+ if (!ImsManager.isImsSupportedOnDevice(mPhone.getContext())) {
return;
}
log("updateImsProvisionedState isImsVolteProvisioned()=" + isImsVolteProvisioned());
@@ -1401,31 +1488,31 @@
imsVolteProvisionedSwitch.setChecked(isImsVolteProvisioned());
imsVolteProvisionedSwitch.setOnCheckedChangeListener(mImsVolteCheckedChangeListener);
imsVolteProvisionedSwitch.setEnabled(!Build.IS_USER
- && mImsManager.isVolteEnabledByPlatform(phone.getContext()));
+ && mImsManager.isVolteEnabledByPlatform(mPhone.getContext()));
imsVtProvisionedSwitch.setOnCheckedChangeListener(null);
imsVtProvisionedSwitch.setChecked(isImsVtProvisioned());
imsVtProvisionedSwitch.setOnCheckedChangeListener(mImsVtCheckedChangeListener);
imsVtProvisionedSwitch.setEnabled(!Build.IS_USER
- && mImsManager.isVtEnabledByPlatform(phone.getContext()));
+ && mImsManager.isVtEnabledByPlatform(mPhone.getContext()));
imsWfcProvisionedSwitch.setOnCheckedChangeListener(null);
imsWfcProvisionedSwitch.setChecked(isImsWfcProvisioned());
imsWfcProvisionedSwitch.setOnCheckedChangeListener(mImsWfcCheckedChangeListener);
imsWfcProvisionedSwitch.setEnabled(!Build.IS_USER
- && mImsManager.isWfcEnabledByPlatform(phone.getContext()));
+ && mImsManager.isWfcEnabledByPlatform(mPhone.getContext()));
eabProvisionedSwitch.setOnCheckedChangeListener(null);
eabProvisionedSwitch.setChecked(isEabProvisioned());
eabProvisionedSwitch.setOnCheckedChangeListener(mEabCheckedChangeListener);
eabProvisionedSwitch.setEnabled(!Build.IS_USER
- && isEabEnabledByPlatform(phone.getContext()));
+ && isEabEnabledByPlatform(mPhone.getContext()));
}
OnClickListener mDnsCheckButtonHandler = new OnClickListener() {
public void onClick(View v) {
//FIXME: Replace with a TelephonyManager call
- phone.disableDnsCheck(!phone.isDnsCheckDisabled());
+ mPhone.disableDnsCheck(!mPhone.isDnsCheckDisabled());
updateDnsCheckState();
}
};
@@ -1452,7 +1539,7 @@
OnClickListener mUpdateSmscButtonHandler = new OnClickListener() {
public void onClick(View v) {
updateSmscButton.setEnabled(false);
- phone.setSmscAddress(smsc.getText().toString(),
+ mPhone.setSmscAddress(smsc.getText().toString(),
mHandler.obtainMessage(EVENT_UPDATE_SMSC_DONE));
}
};
@@ -1497,14 +1584,40 @@
// want this setting to be set, so that if the radio hiccups and this setting
// is for some reason unsuccessful, future calls to the radio will reflect
// the users's preference which is set here.
- final int subId = phone.getSubId();
+ final int subId = mPhone.getSubId();
if (SubscriptionManager.isUsableSubIdValue(subId)) {
- Settings.Global.putInt(phone.getContext().getContentResolver(),
+ Settings.Global.putInt(mPhone.getContext().getContentResolver(),
PREFERRED_NETWORK_MODE + subId, mPreferredNetworkTypeResult);
}
log("Calling setPreferredNetworkType(" + mPreferredNetworkTypeResult + ")");
Message msg = mHandler.obtainMessage(EVENT_SET_PREFERRED_TYPE_DONE);
- phone.setPreferredNetworkType(mPreferredNetworkTypeResult, msg);
+ mPhone.setPreferredNetworkType(mPreferredNetworkTypeResult, msg);
+ }
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ }
+ };
+
+ AdapterView.OnItemSelectedListener mSelectPhoneIndexHandler =
+ new AdapterView.OnItemSelectedListener() {
+
+ public void onItemSelected(AdapterView parent, View v, int pos, long id) {
+ if (pos >= 0 && pos <= mPhoneIndexLabels.length - 1) {
+ // the array position is equal to the phone index
+ int phoneIndex = pos;
+ Phone[] phones = PhoneFactory.getPhones();
+ if (phones == null || phones.length <= phoneIndex) {
+ return;
+ }
+ // getSubId says it takes a slotIndex, but it actually takes a phone index
+ int[] subIds = SubscriptionManager.getSubId(phoneIndex);
+ if (subIds == null || subIds.length < 1) {
+ return;
+ }
+ mSelectedPhoneIndex = phoneIndex;
+
+ updatePhoneIndex(phoneIndex, subIds[0]);
}
}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index d34dfeb..8077ee3 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -639,12 +639,7 @@
showDev, isAdmin)
|| somethingChanged;
- // For profiles, we want them to be included in the profile select dialog even if
- // backup is not activated.
- // For other users, enable/disable backup settings depending on whether backup is activated
- // for the user.
- boolean enableBackupTile = um.isManagedProfile()
- || new BackupSettingsHelper(this).isBackupServiceActive();
+ boolean enableBackupTile = new BackupSettingsHelper(this).showBackupSettingsForUser();
somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
UserBackupSettingsActivity.class.getName()), enableBackupTile, isAdmin)
|| somethingChanged;
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index efa14f6..478db9f 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -244,7 +244,7 @@
private SwitchPreference mToggleInversionPreference;
private ColorInversionPreferenceController mInversionPreferenceController;
private AccessibilityHearingAidPreferenceController mHearingAidPreferenceController;
- private Preference mDarkUIModePreference;
+ private SwitchPreference mDarkUIModePreference;
private DarkUIPreferenceController mDarkUIPreferenceController;
private LiveCaptionPreferenceController mLiveCaptionPreferenceController;
@@ -524,8 +524,8 @@
mDarkUIModePreference = findPreference(DARK_UI_MODE_PREFERENCE);
mDarkUIPreferenceController = new DarkUIPreferenceController(getContext(),
DARK_UI_MODE_PREFERENCE);
+ mDarkUIPreferenceController.setParentFragment(this);
mDarkUIPreferenceController.displayPreference(getPreferenceScreen());
- mDarkUIModePreference.setSummary(mDarkUIPreferenceController.getSummary());
}
private void updateAllPreferences() {
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index b4b909d..ba5e73f 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -135,7 +135,7 @@
implements View.OnClickListener, OnItemSelectedListener, SearchView.OnQueryTextListener {
static final String TAG = "ManageApplications";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
// Intent extras.
public static final String EXTRA_CLASSNAME = "classname";
@@ -151,6 +151,7 @@
private static final String EXTRA_HAS_ENTRIES = "hasEntries";
private static final String EXTRA_HAS_BRIDGE = "hasBridge";
private static final String EXTRA_FILTER_TYPE = "filterType";
+ private static final String EXTRA_EXPAND_SEARCH_VIEW = "expand_search_view";
// attributes used as keys when passing values to AppInfoDashboardFragment activity
public static final String APP_CHG = "chg";
@@ -220,6 +221,9 @@
FilterSpinnerAdapter mFilterAdapter;
@VisibleForTesting
RecyclerView mRecyclerView;
+ // Whether or not search view is expanded.
+ @VisibleForTesting
+ boolean mExpandSearch;
private View mRootView;
private Spinner mFilterSpinner;
@@ -307,12 +311,14 @@
mFilter = appFilterRegistry.get(appFilterRegistry.getDefaultFilterType(mListType));
mIsWorkOnly = args != null ? args.getBoolean(EXTRA_WORK_ONLY) : false;
mWorkUserId = args != null ? args.getInt(EXTRA_WORK_ID) : NO_USER_SPECIFIED;
+ mExpandSearch = activity.getIntent().getBooleanExtra(EXTRA_EXPAND_SEARCH_VIEW, false);
if (savedInstanceState != null) {
mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);
mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
mFilterType =
savedInstanceState.getInt(EXTRA_FILTER_TYPE, AppFilterRegistry.FILTER_APPS_ALL);
+ mExpandSearch = savedInstanceState.getBoolean(EXTRA_EXPAND_SEARCH_VIEW);
}
mInvalidSizeStr = activity.getText(R.string.invalid_size_value);
@@ -501,6 +507,7 @@
outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);
outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);
+ outState.putBoolean(EXTRA_EXPAND_SEARCH_VIEW, !mSearchView.isIconified());
outState.putInt(EXTRA_FILTER_TYPE, mFilter.getFilterType());
if (mApplications != null) {
mApplications.onSaveInstanceState(outState);
@@ -607,6 +614,9 @@
mSearchView = (SearchView) searchMenuItem.getActionView();
mSearchView.setQueryHint(getText(R.string.search_settings));
mSearchView.setOnQueryTextListener(this);
+ if (mExpandSearch) {
+ searchMenuItem.expandActionView();
+ }
}
updateOptionsMenu();
diff --git a/src/com/android/settings/backup/BackupInactivePreferenceController.java b/src/com/android/settings/backup/BackupInactivePreferenceController.java
index 83a0318..92a9487 100644
--- a/src/com/android/settings/backup/BackupInactivePreferenceController.java
+++ b/src/com/android/settings/backup/BackupInactivePreferenceController.java
@@ -28,6 +28,9 @@
@Override
public int getAvailabilityStatus() {
+ if (!new BackupSettingsHelper(mContext).showBackupSettingsForUser()) {
+ return AVAILABLE_UNSEARCHABLE;
+ }
if (PrivacySettingsUtils.isInvisibleKey(mContext, PrivacySettingsUtils.BACKUP_INACTIVE)) {
return UNSUPPORTED_ON_DEVICE;
}
diff --git a/src/com/android/settings/backup/BackupSettingsHelper.java b/src/com/android/settings/backup/BackupSettingsHelper.java
index 1d3455b..ff4b0b5 100644
--- a/src/com/android/settings/backup/BackupSettingsHelper.java
+++ b/src/com/android/settings/backup/BackupSettingsHelper.java
@@ -50,6 +50,14 @@
mContext = context;
}
+ public boolean showBackupSettingsForUser() {
+ // For profiles, we want them to be included in the profile select dialog even if
+ // backup is not activated.
+ // For other users, enable/disable backup settings depending on whether backup is activated
+ // for the user.
+ return UserManager.get(mContext).isManagedProfile() || isBackupServiceActive();
+ }
+
/**
* If there is only one profile, show whether the backup is on or off.
* Otherwise, show nothing.
diff --git a/src/com/android/settings/backup/UserBackupSettingsActivity.java b/src/com/android/settings/backup/UserBackupSettingsActivity.java
index 9baa9a3..dbbb135 100644
--- a/src/com/android/settings/backup/UserBackupSettingsActivity.java
+++ b/src/com/android/settings/backup/UserBackupSettingsActivity.java
@@ -98,7 +98,7 @@
*/
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
- private static final String BACKUP_SEARCH_INDEX_KEY = "backup";
+ private static final String BACKUP_SEARCH_INDEX_KEY = "Backup";
@Override
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
@@ -119,6 +119,15 @@
return result;
}
+
+ @Override
+ public List<String> getNonIndexableKeys(Context context) {
+ final List<String> keys = super.getNonIndexableKeys(context);
+ if (!new BackupSettingsHelper(context).showBackupSettingsForUser()) {
+ keys.add(BACKUP_SEARCH_INDEX_KEY);
+ }
+ return keys;
+ }
};
@VisibleForTesting
diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
index 1b41240..64ddf4f 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
@@ -20,11 +20,15 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.os.UserHandle;
+import com.android.settings.SetupWizardUtils;
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
+import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
import com.android.settings.core.InstrumentedActivity;
+import com.android.settings.password.ChooseLockSettingsHelper;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -36,6 +40,12 @@
*/
public class BiometricEnrollActivity extends InstrumentedActivity {
+ private static final String TAG = "BiometricEnrollActivity";
+
+ public static final String EXTRA_SKIP_INTRO = "skip_intro";
+
+ public static final class InternalActivity extends BiometricEnrollActivity {}
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -45,19 +55,43 @@
// This logic may have to be modified on devices with multiple biometrics.
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- intent = getFingerprintEnrollIntent();
+ // ChooseLockGeneric can request to start fingerprint enroll bypassing the intro screen.
+ if (getIntent().getBooleanExtra(EXTRA_SKIP_INTRO, false)
+ && this instanceof InternalActivity) {
+ intent = getFingerprintFindSensorIntent();
+ } else {
+ intent = getFingerprintIntroIntent();
+ }
} else if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
- intent = getFaceEnrollIntent();
+ intent = getFaceIntroIntent();
}
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+
+ if (this instanceof InternalActivity) {
+ // Propagate challenge and user Id from ChooseLockGeneric.
+ final byte[] token = getIntent()
+ .getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+ final int userId = getIntent()
+ .getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
+
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
+ intent.putExtra(Intent.EXTRA_USER_ID, userId);
+ }
+
startActivity(intent);
}
finish();
}
- private Intent getFingerprintEnrollIntent() {
+ private Intent getFingerprintFindSensorIntent() {
+ Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
+ SetupWizardUtils.copySetupExtras(getIntent(), intent);
+ return intent;
+ }
+
+ private Intent getFingerprintIntroIntent() {
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
Intent intent = new Intent(this, SetupFingerprintEnrollIntroduction.class);
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
@@ -67,7 +101,7 @@
}
}
- private Intent getFaceEnrollIntent() {
+ private Intent getFaceIntroIntent() {
Intent intent = new Intent(this, FaceEnrollIntroduction.class);
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
return intent;
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index a8e4206..d80304f 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -150,7 +150,9 @@
if (!mHasPassword) {
// No password registered, launch into enrollment wizard.
launchChooseLock();
- } else if (!mLaunchedConfirmLock || mToken == null) {
+ } else if (mToken == null) {
+ // It's possible to have a token but mLaunchedConfirmLock == false, since
+ // ChooseLockGeneric can pass us a token.
launchConfirmLock(getConfirmLockTitleResId(), getChallenge());
}
}
@@ -276,7 +278,7 @@
protected void initViews() {
super.initViews();
- TextView description = (TextView) findViewById(R.id.description_text);
+ TextView description = (TextView) findViewById(R.id.sud_layout_description);
if (mBiometricUnlockDisabledByAdmin) {
description.setText(getDescriptionResDisabledByAdmin());
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 3d4ea16..ce5c768 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -131,7 +131,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.fingerprint_enroll_enrolling);
setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);
- mStartMessage = (TextView) findViewById(R.id.start_message);
+ mStartMessage = (TextView) findViewById(R.id.sud_layout_description);
mRepeatMessage = (TextView) findViewById(R.id.repeat_message);
mErrorText = (TextView) findViewById(R.id.error_text);
mProgressBar = (ProgressBar) findViewById(R.id.fingerprint_progress_bar);
diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
index c720b5d..7df66b7 100644
--- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
@@ -89,7 +89,7 @@
protected void initViews() {
super.initViews();
- TextView description = (TextView) findViewById(R.id.description_text);
+ TextView description = (TextView) findViewById(R.id.sud_layout_description);
description.setText(
R.string.security_settings_fingerprint_enroll_introduction_message_setup);
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 55b31d2..9c00831 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -26,7 +26,6 @@
public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
public static final String SLICE_INJECTION = "settings_slice_injection";
- public static final String WIFI_DETAILS_SAVED_SCREEN = "settings_wifi_details_saved_screen";
public static final String WIFI_DETAILS_DATAUSAGE_HEADER =
"settings_wifi_details_datausage_header";
}
diff --git a/src/com/android/settings/core/SliderPreferenceController.java b/src/com/android/settings/core/SliderPreferenceController.java
index 0ea6be3..0a7ece2 100644
--- a/src/com/android/settings/core/SliderPreferenceController.java
+++ b/src/com/android/settings/core/SliderPreferenceController.java
@@ -44,7 +44,7 @@
}
/**
- * @return the value of the Slider's position based on the range: [0, maxSteps).
+ * @return the value of the Slider's position based on the range: [min, max].
*/
public abstract int getSliderPosition();
@@ -57,9 +57,14 @@
public abstract boolean setSliderPosition(int position);
/**
- * @return the number of steps supported by the slider.
+ * @return the maximum value supported by the slider.
*/
- public abstract int getMaxSteps();
+ public abstract int getMax();
+
+ /**
+ * @return the minimum value supported by the slider.
+ */
+ public abstract int getMin();
@Override
public int getSliceType() {
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index e5158ff..96a1e22 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -99,22 +99,23 @@
}
};
- private ChartDataUsagePreference mChart;
- private TelephonyManager mTelephonyManager;
-
@VisibleForTesting
NetworkTemplate mTemplate;
@VisibleForTesting
int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@VisibleForTesting
int mNetworkType;
+ @VisibleForTesting
+ Spinner mCycleSpinner;
+ @VisibleForTesting
+ LoadingViewController mLoadingViewController;
+
+ private ChartDataUsagePreference mChart;
+ private TelephonyManager mTelephonyManager;
private List<NetworkCycleChartData> mCycleData;
private ArrayList<Long> mCycles;
-
- private LoadingViewController mLoadingViewController;
private UidDetailProvider mUidDetailProvider;
private CycleAdapter mCycleAdapter;
- private Spinner mCycleSpinner;
private Preference mUsageAmount;
private PreferenceGroup mApps;
private View mHeader;
@@ -158,6 +159,7 @@
.launch();
});
mCycleSpinner = mHeader.findViewById(R.id.filter_spinner);
+ mCycleSpinner.setVisibility(View.GONE);
mCycleAdapter = new CycleAdapter(mCycleSpinner.getContext(), new SpinnerInterface() {
@Override
public void setAdapter(CycleAdapter cycleAdapter) {
@@ -276,7 +278,8 @@
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
* current {@link #mTemplate}.
*/
- private void updatePolicy() {
+ @VisibleForTesting
+ void updatePolicy() {
final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
final View configureButton = mHeader.findViewById(R.id.filter_settings);
//SUB SELECT
@@ -486,7 +489,8 @@
}
};
- private final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
+ @VisibleForTesting
+ final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
new LoaderCallbacks<List<NetworkCycleChartData>>() {
@Override
public Loader<List<NetworkCycleChartData>> onCreateLoader(int id, Bundle args) {
@@ -503,6 +507,7 @@
mCycleData = data;
// calculate policy cycles based on available data
updatePolicy();
+ mCycleSpinner.setVisibility(View.VISIBLE);
}
@Override
diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
index bd9d386..6aa7187 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
+++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
@@ -15,9 +15,14 @@
import static android.provider.Settings.System.ADAPTIVE_SLEEP;
+import android.Manifest;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.provider.Settings;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
@@ -27,16 +32,24 @@
private final String SYSTEM_KEY = ADAPTIVE_SLEEP;
private final int DEFAULT_VALUE = 0;
+ private final boolean hasSufficientPermissions;
+
public AdaptiveSleepPreferenceController(Context context, String key) {
super(context, key);
+
+ final PackageManager packageManager = mContext.getPackageManager();
+ final String attentionPackage = packageManager.getAttentionServicePackageName();
+ hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission(
+ Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
}
@Override
public boolean isChecked() {
- return Settings.System.getInt(mContext.getContentResolver(),
+ return hasSufficientPermissions && Settings.System.getInt(mContext.getContentResolver(),
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
}
+
@Override
public boolean setChecked(boolean isChecked) {
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
@@ -64,4 +77,15 @@
? R.string.adaptive_sleep_summary_on
: R.string.adaptive_sleep_summary_off);
}
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ final Preference preference = screen.findPreference(SYSTEM_KEY);
+
+ if (preference != null) {
+ preference.setEnabled(hasSufficientPermissions);
+ }
+
+ }
}
diff --git a/src/com/android/settings/display/DarkUIInfoDialogFragment.java b/src/com/android/settings/display/DarkUIInfoDialogFragment.java
new file mode 100644
index 0000000..8fca679
--- /dev/null
+++ b/src/com/android/settings/display/DarkUIInfoDialogFragment.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.display;
+
+import static com.android.settings.display.DarkUIPreferenceController.DARK_MODE_PREFS;
+import static com.android.settings.display.DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN;
+
+import android.app.Dialog;
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class DarkUIInfoDialogFragment extends InstrumentedDialogFragment
+ implements DialogInterface.OnClickListener{
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO(b/130251804): Add metrics constant in followup change to avoid merge conflict in
+ // beta cherrypick
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ Context context = getContext();
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ LayoutInflater inflater = LayoutInflater.from(dialog.getContext());
+ View titleView = inflater.inflate(R.layout.settings_dialog_title, null);
+ ((ImageView) titleView.findViewById(R.id.settings_icon))
+ .setImageDrawable(context.getDrawable(R.drawable.dark_theme));
+ ((TextView) titleView.findViewById(R.id.settings_title)).setText(R.string.dark_ui_mode);
+
+ dialog.setCustomTitle(titleView)
+ .setMessage(R.string.dark_ui_settings_dark_summary)
+ .setPositiveButton(
+ R.string.dark_ui_settings_dialog_acknowledge,
+ this);
+ return dialog.create();
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ enableDarkTheme();
+ super.onDismiss(dialog);
+ }
+
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ // We have to manually dismiss the dialog because changing night mode causes it to
+ // recreate itself.
+ dialogInterface.dismiss();
+ enableDarkTheme();
+ }
+
+ private void enableDarkTheme() {
+ final Context context = getContext();
+ if (context != null) {
+ Settings.Secure.putInt(context.getContentResolver(),
+ Settings.Secure.DARK_MODE_DIALOG_SEEN,
+ DarkUIPreferenceController.DIALOG_SEEN);
+ context.getSystemService(UiModeManager.class)
+ .setNightMode(UiModeManager.MODE_NIGHT_YES);
+ }
+ }
+}
diff --git a/src/com/android/settings/display/DarkUIPreferenceController.java b/src/com/android/settings/display/DarkUIPreferenceController.java
index 7d8fd56..9df2402 100644
--- a/src/com/android/settings/display/DarkUIPreferenceController.java
+++ b/src/com/android/settings/display/DarkUIPreferenceController.java
@@ -18,37 +18,66 @@
import android.app.UiModeManager;
import android.content.Context;
+import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
-import androidx.preference.ListPreference;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
+import androidx.fragment.app.Fragment;
-import com.android.settings.R;
-import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
-public class DarkUIPreferenceController extends BasePreferenceController {
+public class DarkUIPreferenceController extends TogglePreferenceController {
+ public static final String DARK_MODE_PREFS = "dark_mode_prefs";
+ public static final String PREF_DARK_MODE_DIALOG_SEEN = "dark_mode_dialog_seen";
+ public static final int DIALOG_SEEN = 1;
private UiModeManager mUiModeManager;
+ private Context mContext;
+ private Fragment mFragment;
public DarkUIPreferenceController(Context context, String key) {
super(context, key);
+ mContext = context;
mUiModeManager = context.getSystemService(UiModeManager.class);
}
+ @Override
+ public boolean isChecked() {
+ return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ final boolean dialogSeen =
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.DARK_MODE_DIALOG_SEEN, 0) == DIALOG_SEEN;
+ if (!dialogSeen && isChecked) {
+ showDarkModeDialog();
+ return false;
+ }
+ mUiModeManager.setNightMode(isChecked
+ ? UiModeManager.MODE_NIGHT_YES
+ : UiModeManager.MODE_NIGHT_NO);
+ return true;
+ }
+
+ private void showDarkModeDialog() {
+ final DarkUIInfoDialogFragment frag = new DarkUIInfoDialogFragment();
+ if (mFragment.getFragmentManager() != null) {
+ frag.show(mFragment.getFragmentManager(), getClass().getName());
+ }
+ }
+
@VisibleForTesting
void setUiModeManager(UiModeManager uiModeManager) {
mUiModeManager = uiModeManager;
}
- @Override
- public int getAvailabilityStatus() {
- return AVAILABLE;
+ public void setParentFragment(Fragment fragment) {
+ mFragment = fragment;
}
@Override
- public CharSequence getSummary() {
- return DarkUISettingsRadioButtonsController.modeToDescription(
- mContext, mUiModeManager.getNightMode());
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
}
}
diff --git a/src/com/android/settings/display/DarkUISettings.java b/src/com/android/settings/display/DarkUISettings.java
deleted file mode 100644
index 50fd386..0000000
--- a/src/com/android/settings/display/DarkUISettings.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.display;
-
-import android.app.UiModeManager;
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.provider.SearchIndexableResource;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import com.android.settings.R;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settings.widget.RadioButtonPickerFragment;
-import com.android.settingslib.search.SearchIndexable;
-import com.android.settingslib.widget.CandidateInfo;
-import com.android.settingslib.widget.FooterPreference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * The screen for selecting the dark theme preference for this device. Automatically updates
- * the associated footer view with any needed information.
- */
-@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
-public class DarkUISettings extends RadioButtonPickerFragment implements Indexable {
-
- private DarkUISettingsRadioButtonsController mController;
- private Preference mFooter;
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.dark_ui_settings;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- // TODO(b/128686189): add illustration once it is ready
- setIllustration(0, 0);
- mFooter = new FooterPreference(context);
- mFooter.setIcon(android.R.color.transparent);
- mController = new DarkUISettingsRadioButtonsController(context, mFooter);
- }
-
- @Override
- protected List<? extends CandidateInfo> getCandidates() {
- final Context context = getContext();
- final List<CandidateInfo> candidates = new ArrayList<>();
- candidates.add(new DarkUISettingsCandidateInfo(
- DarkUISettingsRadioButtonsController.modeToDescription(
- context, UiModeManager.MODE_NIGHT_YES),
- /* summary */ null,
- DarkUISettingsRadioButtonsController.KEY_DARK,
- /* enabled */ true));
- candidates.add(new DarkUISettingsCandidateInfo(
- DarkUISettingsRadioButtonsController.modeToDescription(
- context, UiModeManager.MODE_NIGHT_NO),
- /* summary */ null,
- DarkUISettingsRadioButtonsController.KEY_LIGHT,
- /* enabled */ true));
- return candidates;
- }
-
- @Override
- protected void addStaticPreferences(PreferenceScreen screen) {
- screen.addPreference(mFooter);
- }
-
- @Override
- protected String getDefaultKey() {
- return mController.getDefaultKey();
- }
-
- @Override
- protected boolean setDefaultKey(String key) {
- return mController.setDefaultKey(key);
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.DARK_UI_SETTINGS;
- }
-
- static class DarkUISettingsCandidateInfo extends CandidateInfo {
-
- private final CharSequence mLabel;
- private final CharSequence mSummary;
- private final String mKey;
-
- DarkUISettingsCandidateInfo(CharSequence label, CharSequence summary, String key,
- boolean enabled) {
- super(enabled);
- mLabel = label;
- mKey = key;
- mSummary = summary;
- }
-
- @Override
- public CharSequence loadLabel() {
- return mLabel;
- }
-
- @Override
- public Drawable loadIcon() {
- return null;
- }
-
- @Override
- public String getKey() {
- return mKey;
- }
-
- public CharSequence getSummary() {
- return mSummary;
- }
- }
-
- public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.dark_ui_settings;
- return Arrays.asList(sir);
- }
- };
-}
diff --git a/src/com/android/settings/display/DarkUISettingsRadioButtonsController.java b/src/com/android/settings/display/DarkUISettingsRadioButtonsController.java
deleted file mode 100644
index 0fca306..0000000
--- a/src/com/android/settings/display/DarkUISettingsRadioButtonsController.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.display;
-
-import android.app.UiModeManager;
-import android.content.Context;
-import androidx.preference.Preference;
-import com.android.settings.R;
-import androidx.annotation.VisibleForTesting;
-
-public class DarkUISettingsRadioButtonsController {
-
- public static final String KEY_DARK = "key_dark_ui_settings_dark";
- public static final String KEY_LIGHT = "key_dark_ui_settings_light";
-
- @VisibleForTesting
- UiModeManager mManager;
-
- private Preference mFooter;
-
- public DarkUISettingsRadioButtonsController(Context context, Preference footer) {
- mManager = context.getSystemService(UiModeManager.class);
- mFooter = footer;
- }
-
- public String getDefaultKey() {
- final int mode = mManager.getNightMode();
- updateFooter();
- return mode == UiModeManager.MODE_NIGHT_YES ? KEY_DARK : KEY_LIGHT;
- }
-
- public boolean setDefaultKey(String key) {
- switch(key) {
- case KEY_DARK:
- mManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
- break;
- case KEY_LIGHT:
- mManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
- break;
- default:
- throw new IllegalStateException(
- "Not a valid key for " + this.getClass().getSimpleName() + ": " + key);
- }
- updateFooter();
- return true;
- }
-
- public void updateFooter() {
- final int mode = mManager.getNightMode();
- switch (mode) {
- case UiModeManager.MODE_NIGHT_YES:
- mFooter.setSummary(R.string.dark_ui_settings_dark_summary);
- break;
- case UiModeManager.MODE_NIGHT_NO:
- case UiModeManager.MODE_NIGHT_AUTO:
- default:
- mFooter.setSummary(R.string.dark_ui_settings_light_summary);
- }
- }
-
- public static String modeToDescription(Context context, int mode) {
- final String[] values = context.getResources().getStringArray(R.array.dark_ui_mode_entries);
- switch (mode) {
- case UiModeManager.MODE_NIGHT_YES:
- return values[0];
- case UiModeManager.MODE_NIGHT_NO:
- case UiModeManager.MODE_NIGHT_AUTO:
- default:
- return values[1];
- }
- }
-}
diff --git a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
index 48e261e..04e3b13 100644
--- a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
@@ -55,7 +55,8 @@
super.displayPreference(screen);
final SeekBarPreference preference = screen.findPreference(getPreferenceKey());
preference.setContinuousUpdates(true);
- preference.setMax(getMaxSteps());
+ preference.setMax(getMax());
+ preference.setMin(getMin());
}
@Override
@@ -75,10 +76,15 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
return convertTemperature(ColorDisplayManager.getMinimumColorTemperature(mContext));
}
+ @Override
+ public int getMin() {
+ return ColorDisplayManager.getMinimumColorTemperature(mContext);
+ }
+
/**
* Inverts and range-adjusts a raw value from the SeekBar (i.e. [0, maxTemp-minTemp]), or
* converts an inverted and range-adjusted value to the raw SeekBar value, depending on the
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
index d832640..cd79ea0 100644
--- a/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
+++ b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
@@ -79,9 +79,6 @@
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
UserHandle.getUserId(app.uid)));
holder.appName.setText(Utils.getApplicationLabel(mContext, app.packageName));
- if (app.screenOnTimeMs != 0) {
- holder.appTime.setText(StringUtil.formatElapsedTime(mContext, app.screenOnTimeMs, false));
- }
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 0867a01..ebc4939 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -160,7 +160,7 @@
}
/** Returns the color resid for tinting {@link #getIconId()} or {@link View#NO_ID} if none. */
- protected @IdRes int getIconTintColorId() {
+ public @IdRes int getIconTintColorId() {
return View.NO_ID;
}
diff --git a/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java
index e21bb75..9545939 100644
--- a/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java
+++ b/src/com/android/settings/gestures/PreventRingingSwitchPreferenceController.java
@@ -102,8 +102,15 @@
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
+ final int preventRingingSetting = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE);
+ final int newRingingSetting = preventRingingSetting == Settings.Secure.VOLUME_HUSH_OFF
+ ? Settings.Secure.VOLUME_HUSH_VIBRATE
+ : preventRingingSetting;
+
Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.VOLUME_HUSH_GESTURE, isChecked ? Settings.Secure.VOLUME_HUSH_VIBRATE
+ Settings.Secure.VOLUME_HUSH_GESTURE, isChecked
+ ? newRingingSetting
: Settings.Secure.VOLUME_HUSH_OFF);
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
index bba7f53..bdf863e 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
@@ -16,8 +16,11 @@
package com.android.settings.homepage.contextualcards;
-import java.util.List;
+import androidx.slice.Slice;
/** Feature provider for the contextual card feature. */
public interface ContextualCardFeatureProvider {
+
+ /** Log package when user clicks contextual notification channel card. */
+ void logNotificationPackage(Slice slice);
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index 03a1550..4af2838 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -16,7 +16,22 @@
package com.android.settings.homepage.contextualcards;
+import static android.content.Context.MODE_PRIVATE;
+
import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.ArraySet;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.core.SliceAction;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.applications.AppInfoBase;
+import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
+import com.android.settings.slices.CustomSliceRegistry;
+
+import java.util.Set;
public class ContextualCardFeatureProviderImpl implements ContextualCardFeatureProvider {
private final Context mContext;
@@ -24,4 +39,27 @@
public ContextualCardFeatureProviderImpl(Context context) {
mContext = context;
}
+
+ @Override
+ public void logNotificationPackage(Slice slice) {
+ if (slice == null || !slice.getUri().equals(
+ CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI)) {
+ return;
+ }
+
+ final SliceAction primaryAction = SliceMetadata.from(mContext, slice).getPrimaryAction();
+ final String currentPackage = primaryAction.getAction().getIntent()
+ .getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)
+ .getString(AppInfoBase.ARG_PACKAGE_NAME);
+
+ final SharedPreferences prefs = mContext.getSharedPreferences(
+ ContextualNotificationChannelSlice.PREFS, MODE_PRIVATE);
+ final Set<String> interactedPackages = prefs.getStringSet(
+ ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+
+ final Set<String> newInteractedPackages = new ArraySet<>(interactedPackages);
+ newInteractedPackages.add(currentPackage);
+ prefs.edit().putStringSet(ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES,
+ newInteractedPackages).apply();
+ }
}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
index a75f99a..761755c 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java
@@ -25,6 +25,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.ArrayMap;
@@ -39,6 +42,7 @@
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SubSettings;
+import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
@@ -107,8 +111,12 @@
if (batteryTip.getState() == BatteryTip.StateType.INVISIBLE) {
continue;
}
- final IconCompat icon = IconCompat.createWithResource(mContext,
- batteryTip.getIconId());
+ final Drawable drawable = mContext.getDrawable(batteryTip.getIconId());
+ drawable.setColorFilter(new PorterDuffColorFilter(
+ mContext.getResources().getColor(batteryTip.getIconTintColorId()),
+ PorterDuff.Mode.SRC_IN));
+
+ final IconCompat icon = Utils.createIconWithDrawable(drawable);
final SliceAction primaryAction = SliceAction.createDeeplink(getPrimaryAction(),
icon,
ListBuilder.ICON_IMAGE,
diff --git a/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java
index 2025a06..17cae77 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSlice.java
@@ -16,14 +16,23 @@
package com.android.settings.homepage.contextualcards.slices;
+import static android.content.Context.MODE_PRIVATE;
+
import android.content.Context;
import android.net.Uri;
+import android.util.ArraySet;
import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.SliceBackgroundWorker;
+
+import java.util.Set;
public class ContextualNotificationChannelSlice extends NotificationChannelSlice {
+ public static final String PREFS = "notification_channel_slice_prefs";
+ public static final String PREF_KEY_INTERACTED_PACKAGES = "interacted_packages";
+
public ContextualNotificationChannelSlice(Context context) {
super(context);
}
@@ -37,4 +46,18 @@
protected CharSequence getSubTitle(String packageName, int uid) {
return mContext.getText(R.string.recently_installed_app);
}
+
+ @Override
+ protected boolean isUserInteracted(String packageName) {
+ // Check the package has been interacted on current slice or not.
+ final Set<String> interactedPackages =
+ mContext.getSharedPreferences(PREFS, MODE_PRIVATE)
+ .getStringSet(PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+ return interactedPackages.contains(packageName);
+ }
+
+ @Override
+ public Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
+ return NotificationChannelWorker.class;
+ }
}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
index 0550e7b..07fc899 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSlice.java
@@ -154,16 +154,12 @@
// TODO(b/123065955): Review latency of NotificationChannelSlice
final List<PackageInfo> multiChannelPackages = getMultiChannelPackages(
getRecentlyInstalledPackages());
- final PackageInfo packageInfo = getMaxSentNotificationsPackage(multiChannelPackages);
-
- // Return a header with IsError flag, if package is not found.
- if (packageInfo == null) {
+ mPackageName = getMaxSentNotificationsPackage(multiChannelPackages);
+ if (mPackageName == null) {
+ // Return a header with IsError flag, if package is not found.
return listBuilder.setHeader(getNoSuggestedAppHeader())
.setIsError(true).build();
}
-
- // Save eligible package name and its uid, they will be used in getIntent().
- mPackageName = packageInfo.packageName;
mUid = getApplicationUid(mPackageName);
// Add notification channel header.
@@ -177,7 +173,7 @@
.setPrimaryAction(getPrimarySliceAction(icon, title, getIntent())));
// Add notification channel rows.
- final List<ListBuilder.RowBuilder> rows = getNotificationChannelRows(packageInfo, icon);
+ final List<ListBuilder.RowBuilder> rows = getNotificationChannelRows(icon);
for (ListBuilder.RowBuilder rowBuilder : rows) {
listBuilder.addRow(rowBuilder);
}
@@ -218,6 +214,17 @@
.toIntent();
}
+ /**
+ * Check the package has been interacted by user or not.
+ * Will use to filter package in {@link #getRecentlyInstalledPackages()}.
+ *
+ * @param packageName The app package name.
+ * @return true if the package was interacted, false otherwise.
+ */
+ protected boolean isUserInteracted(String packageName) {
+ return false;
+ }
+
@VisibleForTesting
IconCompat getApplicationIcon(String packageName) {
final Drawable drawable;
@@ -271,8 +278,7 @@
.setPrimaryAction(primarySliceActionForNoSuggestedApp);
}
- private List<ListBuilder.RowBuilder> getNotificationChannelRows(PackageInfo packageInfo,
- IconCompat icon) {
+ private List<ListBuilder.RowBuilder> getNotificationChannelRows(IconCompat icon) {
final List<ListBuilder.RowBuilder> notificationChannelRows = new ArrayList<>();
final List<NotificationChannel> displayableChannels = getDisplayableChannels(mAppRow);
@@ -328,8 +334,9 @@
final List<PackageInfo> installedPackages =
mContext.getPackageManager().getInstalledPackages(0);
for (PackageInfo packageInfo : installedPackages) {
- // Not include system app.
- if (packageInfo.applicationInfo.isSystemApp()) {
+ // Not include system app and interacted app.
+ if (packageInfo.applicationInfo.isSystemApp()
+ || isUserInteracted(packageInfo.packageName)) {
continue;
}
@@ -376,14 +383,14 @@
.collect(Collectors.toList());
}
- private PackageInfo getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
+ private String getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
if (packageInfoList.isEmpty()) {
return null;
}
// Get the package which has sent at least ~10 notifications and not turn off channels.
int maxSentCount = 0;
- PackageInfo maxSentCountPackage = null;
+ String maxSentCountPackage = null;
for (PackageInfo packageInfo : packageInfoList) {
final NotificationBackend.AppRow appRow = mNotificationBackend.loadAppRow(mContext,
mContext.getPackageManager(), packageInfo);
@@ -396,7 +403,7 @@
final int sentCount = appRow.sentByApp.sentCount;
if (sentCount >= MIN_NOTIFICATION_SENT_COUNT && sentCount > maxSentCount) {
maxSentCount = sentCount;
- maxSentCountPackage = packageInfo;
+ maxSentCountPackage = packageInfo.packageName;
mAppRow = appRow;
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java
new file mode 100644
index 0000000..f1d0d59
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorker.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS;
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.net.Uri;
+import android.util.ArraySet;
+
+import com.android.settings.slices.SliceBackgroundWorker;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class NotificationChannelWorker extends SliceBackgroundWorker<Void> {
+
+ public NotificationChannelWorker(Context context, Uri uri) {
+ super(context, uri);
+ }
+
+ @Override
+ protected void onSlicePinned() {
+ }
+
+ @Override
+ protected void onSliceUnpinned() {
+ removeUninstalledPackages();
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ private void removeUninstalledPackages() {
+ final SharedPreferences prefs = getContext().getSharedPreferences(PREFS, MODE_PRIVATE);
+ final Set<String> interactedPackages =
+ prefs.getStringSet(PREF_KEY_INTERACTED_PACKAGES, new ArraySet());
+ if (interactedPackages.isEmpty()) {
+ return;
+ }
+
+ final List<PackageInfo> installedPackageInfos =
+ getContext().getPackageManager().getInstalledPackages(0);
+ final List<String> installedPackages = installedPackageInfos.stream()
+ .map(packageInfo -> packageInfo.packageName)
+ .collect(Collectors.toList());
+ final Set<String> newInteractedPackages = new ArraySet<>();
+ for (String packageName : interactedPackages) {
+ if (installedPackages.contains(packageName)) {
+ newInteractedPackages.add(packageName);
+ }
+ }
+ prefs.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES, newInteractedPackages).apply();
+ }
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 725f087..9898834 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -16,6 +16,8 @@
package com.android.settings.homepage.contextualcards.slices;
+import static android.app.slice.Slice.HINT_ERROR;
+
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
@@ -117,6 +119,14 @@
return;
}
+ if (slice.hasHint(HINT_ERROR)) {
+ Log.w(TAG, "Slice has HINT_ERROR, skipping rendering. uri=" + slice.getUri());
+ mSliceLiveDataMap.get(slice.getUri()).removeObservers(mLifecycleOwner);
+ mContext.getContentResolver().notifyChange(CardContentProvider.REFRESH_CARD_URI,
+ null);
+ return;
+ }
+
switch (holder.getItemViewType()) {
case VIEW_TYPE_DEFERRED_SETUP:
mDeferredSetupCardHelper.bindView(holder, card, slice);
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java
index a9a8346..f7b2bf5 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceFullCardRendererHelper.java
@@ -27,6 +27,7 @@
import com.android.settings.R;
import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -64,6 +65,12 @@
metricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_CONTEXTUAL_CARD_CLICK, log);
+
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(
+ mContext);
+
+ contextualCardFeatureProvider.logNotificationPackage(slice);
});
// Customize slice view for Settings
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index 463d7ae..ae115eb 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
+import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
@@ -49,6 +50,7 @@
private static final String KEY = "mobile_network_list";
private SubscriptionManager mSubscriptionManager;
+ private UserManager mUserManager;
private SubscriptionsChangeListener mChangeListener;
private AddPreference mPreference;
@@ -70,6 +72,7 @@
public MobileNetworkSummaryController(Context context, Lifecycle lifecycle) {
super(context);
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
if (lifecycle != null) {
mChangeListener = new SubscriptionsChangeListener(context, this);
lifecycle.addObserver(this);
@@ -137,6 +140,8 @@
startAddSimFlow();
return true;
});
+ } else {
+ mPreference.setEnabled(false);
}
} else {
// We have one or more existing subscriptions, so we want the plus button if eSIM is
@@ -160,7 +165,7 @@
@Override
public boolean isAvailable() {
- return !Utils.isWifiOnly(mContext);
+ return !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
}
@Override
diff --git a/src/com/android/settings/notification/AudioHelper.java b/src/com/android/settings/notification/AudioHelper.java
index a918d86..d178113 100644
--- a/src/com/android/settings/notification/AudioHelper.java
+++ b/src/com/android/settings/notification/AudioHelper.java
@@ -74,4 +74,8 @@
public int getMaxVolume(int stream) {
return mAudioManager.getStreamMaxVolume(stream);
}
+
+ public int getMinVolume(int stream) {
+ return mAudioManager.getStreamMinVolume(stream);
+ }
}
diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java
index f765694..74ccf59 100644
--- a/src/com/android/settings/notification/RedactionInterstitial.java
+++ b/src/com/android/settings/notification/RedactionInterstitial.java
@@ -123,7 +123,7 @@
mUserId = Utils.getUserIdFromBundle(
getContext(), getActivity().getIntent().getExtras());
if (UserManager.get(getContext()).isManagedProfile(mUserId)) {
- ((TextView) view.findViewById(R.id.message))
+ ((TextView) view.findViewById(R.id.sud_layout_description))
.setText(R.string.lock_screen_notifications_interstitial_message_profile);
mShowAllButton.setText(R.string.lock_screen_notifications_summary_show_profile);
mRedactSensitiveButton
diff --git a/src/com/android/settings/notification/RemoteVolumePreferenceController.java b/src/com/android/settings/notification/RemoteVolumePreferenceController.java
index b455465..816d80f 100644
--- a/src/com/android/settings/notification/RemoteVolumePreferenceController.java
+++ b/src/com/android/settings/notification/RemoteVolumePreferenceController.java
@@ -43,7 +43,6 @@
@VisibleForTesting
static final int REMOTE_VOLUME = 100;
- private MediaSessionManager mMediaSessionManager;
private MediaSessions mMediaSessions;
@VisibleForTesting
MediaSession.Token mActiveToken;
@@ -86,28 +85,39 @@
public RemoteVolumePreferenceController(Context context) {
super(context, KEY_REMOTE_VOLUME);
- mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
mMediaSessions = new MediaSessions(context, Looper.getMainLooper(), mCallbacks);
+ updateToken(getActiveRemoteToken(mContext));
}
@Override
public int getAvailabilityStatus() {
- final List<MediaController> controllers = mMediaSessionManager.getActiveSessions(null);
+ // Always return true to make it indexed in database
+ return AVAILABLE_UNSEARCHABLE;
+ }
+
+ /**
+ * Return {@link android.media.session.MediaSession.Token} for active remote token, or
+ * {@code null} if there is no active remote token.
+ */
+ public static MediaSession.Token getActiveRemoteToken(Context context) {
+ final MediaSessionManager sessionManager = context.getSystemService(
+ MediaSessionManager.class);
+ final List<MediaController> controllers = sessionManager.getActiveSessions(null);
for (MediaController mediaController : controllers) {
final MediaController.PlaybackInfo pi = mediaController.getPlaybackInfo();
if (isRemote(pi)) {
- updateToken(mediaController.getSessionToken());
- return AVAILABLE;
+ return mediaController.getSessionToken();
}
}
// No active remote media at this point
- return CONDITIONALLY_UNAVAILABLE;
+ return null;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreference.setVisible(mActiveToken != null);
if (mMediaController != null) {
updatePreference(mPreference, mActiveToken, mMediaController.getPlaybackInfo());
}
@@ -150,7 +160,7 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
if (mPreference != null) {
return mPreference.getMax();
}
@@ -162,6 +172,14 @@
}
@Override
+ public int getMin() {
+ if (mPreference != null) {
+ return mPreference.getMin();
+ }
+ return 0;
+ }
+
+ @Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(), KEY_REMOTE_VOLUME);
}
diff --git a/src/com/android/settings/notification/VolumeSeekBarPreference.java b/src/com/android/settings/notification/VolumeSeekBarPreference.java
index 7f36791..92b3cae 100644
--- a/src/com/android/settings/notification/VolumeSeekBarPreference.java
+++ b/src/com/android/settings/notification/VolumeSeekBarPreference.java
@@ -80,11 +80,6 @@
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
- @Override
- public boolean isSelectable() {
- return false;
- }
-
public void setStream(int stream) {
mStream = stream;
setMax(mAudioManager.getStreamMaxVolume(mStream));
diff --git a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
index fff9aaf..f7bf75f 100644
--- a/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
+++ b/src/com/android/settings/notification/VolumeSeekBarPreferenceController.java
@@ -92,13 +92,21 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
if (mPreference != null) {
return mPreference.getMax();
}
return mHelper.getMaxVolume(getAudioStream());
}
+ @Override
+ public int getMin() {
+ if (mPreference != null) {
+ return mPreference.getMin();
+ }
+ return mHelper.getMinVolume(getAudioStream());
+ }
+
protected abstract int getAudioStream();
protected abstract int getMuteIcon();
diff --git a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
index 4829a28..3a9bcb7 100644
--- a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
@@ -33,11 +33,12 @@
public class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController
implements PreferenceControllerMixin {
+ public static final String KEY = "zen_mode_toggle";
+
private static final String TAG = "EnableZenModeButton";
- protected static final String KEY = "zen_mode_settings_button_container";
+ private final FragmentManager mFragment;
private Button mZenButtonOn;
private Button mZenButtonOff;
- private FragmentManager mFragment;
public ZenModeButtonPreferenceController(Context context, Lifecycle lifecycle, FragmentManager
fragment) {
@@ -60,13 +61,13 @@
super.updateState(preference);
if (null == mZenButtonOn) {
- mZenButtonOn = (Button) ((LayoutPreference) preference)
+ mZenButtonOn = ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_on_button);
updateZenButtonOnClickListener();
}
if (null == mZenButtonOff) {
- mZenButtonOff = (Button) ((LayoutPreference) preference)
+ mZenButtonOff = ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_off_button);
mZenButtonOff.setOnClickListener(v -> {
mMetricsFeatureProvider.action(mContext,
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 9360a33..f35c649 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -328,7 +328,6 @@
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
keys.add(ZenModeDurationPreferenceController.KEY);
- keys.add(ZenModeButtonPreferenceController.KEY);
return keys;
}
diff --git a/src/com/android/settings/notification/ZenModeSliceBuilder.java b/src/com/android/settings/notification/ZenModeSliceBuilder.java
index e8b181a..9e88cea 100644
--- a/src/com/android/settings/notification/ZenModeSliceBuilder.java
+++ b/src/com/android/settings/notification/ZenModeSliceBuilder.java
@@ -18,8 +18,6 @@
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
-import static com.android.settings.notification.ZenModeSoundSettingsPreferenceController.ZEN_MODE_KEY;
-
import android.annotation.ColorInt;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -47,6 +45,8 @@
private static final String TAG = "ZenModeSliceBuilder";
+ private static final String ZEN_MODE_SLICE_KEY = ZenModeButtonPreferenceController.KEY;
+
/**
* Action notifying a change on the Zen Mode Slice.
*/
@@ -78,7 +78,8 @@
final PendingIntent primaryAction = getPrimaryAction(context);
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction,
(IconCompat) null /* icon */, ListBuilder.ICON_IMAGE, title);
- final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, null /* actionTitle */,
+ final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
+ null /* actionTitle */,
isZenModeEnabled);
return new ListBuilder(context, CustomSliceRegistry.ZEN_MODE_SLICE_URI,
@@ -110,10 +111,10 @@
}
public static Intent getIntent(Context context) {
- final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build();
+ final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_SLICE_KEY).build();
final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString();
return SliceBuilderUtils.buildSearchResultPageIntent(context,
- ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle,
+ ZenModeSettings.class.getName(), ZEN_MODE_SLICE_KEY, screenTitle,
SettingsEnums.NOTIFICATION_ZEN_MODE)
.setClassName(context.getPackageName(), SubSettings.class.getName())
.setData(contentUri);
diff --git a/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceController.java b/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceController.java
deleted file mode 100644
index 842c49d..0000000
--- a/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceController.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 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.notification;
-
-import android.content.Context;
-
-public class ZenModeSoundSettingsPreferenceController extends ZenModePreferenceController {
-
- public static final String ZEN_MODE_KEY = "zen_mode";
-
- public ZenModeSoundSettingsPreferenceController(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return AVAILABLE;
- }
-}
diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java
index f1391dc..173461c 100644
--- a/src/com/android/settings/panel/PanelFragment.java
+++ b/src/com/android/settings/panel/PanelFragment.java
@@ -16,12 +16,20 @@
package com.android.settings.panel;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.app.settings.SettingsEnums;
-import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.TextView;
@@ -29,8 +37,12 @@
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.SliceMetadata;
+import androidx.slice.widget.SliceLiveData;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
@@ -39,10 +51,24 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.android.setupdesign.DividerItemDecoration;
+import java.util.ArrayList;
+import java.util.List;
+
public class PanelFragment extends Fragment {
private static final String TAG = "PanelFragment";
+ /**
+ * Duration of the animation entering or exiting the screen, in milliseconds.
+ */
+ private static final int DURATION_ANIMATE_PANEL_MS = 250;
+
+ /**
+ * Duration of timeout waiting for Slice data to bind, in milliseconds.
+ */
+ private static final int DURATION_SLICE_BINDING_TIMEOUT_MS = 250;
+
+ private View mLayoutView;
private TextView mTitleView;
private Button mSeeMoreButton;
private Button mDoneButton;
@@ -50,21 +76,42 @@
private PanelContent mPanel;
private MetricsFeatureProvider mMetricsProvider;
+ private String mPanelClosedKey;
+
+ private final List<LiveData<Slice>> mSliceLiveData = new ArrayList<>();
@VisibleForTesting
- PanelSlicesAdapter mAdapter;
+ PanelSlicesLoaderCountdownLatch mPanelSlicesLoaderCountdownLatch;
+
+ private ViewTreeObserver.OnPreDrawListener mOnPreDrawListener = () -> {
+ return false;
+ };
+
+ private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ animateIn();
+ if (mPanelSlices != null) {
+ mPanelSlices.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ }
+ };
+
+ private PanelSlicesAdapter mAdapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
- final View view = inflater.inflate(R.layout.panel_layout, container, false);
- mPanelSlices = view.findViewById(R.id.panel_parent_layout);
- mSeeMoreButton = view.findViewById(R.id.see_more);
- mDoneButton = view.findViewById(R.id.done);
- mTitleView = view.findViewById(R.id.panel_title);
+ mLayoutView = inflater.inflate(R.layout.panel_layout, container, false);
+
+ mPanelSlices = mLayoutView.findViewById(R.id.panel_parent_layout);
+ mSeeMoreButton = mLayoutView.findViewById(R.id.see_more);
+ mDoneButton = mLayoutView.findViewById(R.id.done);
+ mTitleView = mLayoutView.findViewById(R.id.panel_title);
final Bundle arguments = getArguments();
final String panelType =
@@ -80,6 +127,24 @@
.getPanel(activity, panelType, mediaPackageName);
mMetricsProvider = FeatureFactory.getFactory(activity).getMetricsFeatureProvider();
+
+ mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
+
+ // Add predraw listener to remove the animation and while we wait for Slices to load.
+ mLayoutView.getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
+
+ // Start loading Slices. When finished, the Panel will animate in.
+ loadAllSlices();
+
+ mTitleView.setText(mPanel.getTitle());
+ mSeeMoreButton.setOnClickListener(getSeeMoreListener());
+ mDoneButton.setOnClickListener(getCloseListener());
+
+ // If getSeeMoreIntent() is null, hide the mSeeMoreButton.
+ if (mPanel.getSeeMoreIntent() == null) {
+ mSeeMoreButton.setVisibility(View.GONE);
+ }
+
// Log panel opened.
mMetricsProvider.action(
0 /* attribution */,
@@ -88,38 +153,136 @@
callingPackageName,
0 /* value */);
- mAdapter = new PanelSlicesAdapter(this, mPanel);
+ return mLayoutView;
+ }
- mPanelSlices.setHasFixedSize(true);
- mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
- mPanelSlices.setAdapter(mAdapter);
+ private void loadAllSlices() {
+ mSliceLiveData.clear();
+ final List<Uri> sliceUris = mPanel.getSlices();
+ mPanelSlicesLoaderCountdownLatch = new PanelSlicesLoaderCountdownLatch(sliceUris.size());
- DividerItemDecoration itemDecoration = new DividerItemDecoration(getActivity());
- itemDecoration.setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
- mPanelSlices.addItemDecoration(itemDecoration);
+ for (Uri uri : sliceUris) {
+ final LiveData<Slice> sliceLiveData = SliceLiveData.fromUri(getActivity(), uri);
- mTitleView.setText(mPanel.getTitle());
+ // Add slice first to make it in order. Will remove it later if there's an error.
+ mSliceLiveData.add(sliceLiveData);
- mSeeMoreButton.setOnClickListener(getSeeMoreListener());
- mDoneButton.setOnClickListener(getCloseListener());
+ sliceLiveData.observe(getViewLifecycleOwner(), slice -> {
+ // If the Slice has already loaded, do nothing.
+ if (mPanelSlicesLoaderCountdownLatch.isSliceLoaded(uri)) {
+ return;
+ }
- //If getSeeMoreIntent() is null, hide the mSeeMoreButton.
- if (mPanel.getSeeMoreIntent() == null) {
- mSeeMoreButton.setVisibility(View.GONE);
+ /**
+ * Watching for the {@link Slice} to load.
+ * <p>
+ * If the Slice comes back {@code null} or with the Error attribute, remove the
+ * Slice data from the list, and mark the Slice as loaded.
+ * <p>
+ * If the Slice has come back fully loaded, then mark the Slice as loaded. No
+ * other actions required since we already have the Slice data in the list.
+ * <p>
+ * If the Slice does not match the above condition, we will still want to mark
+ * it as loaded after 250ms timeout to avoid delay showing up the panel for
+ * too long. Since we are still having the Slice data in the list, the Slice
+ * will show up later once it is loaded.
+ */
+ final SliceMetadata metadata = SliceMetadata.from(getActivity(), slice);
+ if (slice == null || metadata.isErrorSlice()) {
+ mSliceLiveData.remove(sliceLiveData);
+ mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
+ } else if (metadata.getLoadingState() == SliceMetadata.LOADED_ALL) {
+ mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
+ } else {
+ Handler handler = new Handler();
+ handler.postDelayed(() -> {
+ mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
+ loadPanelWhenReady();
+ }, DURATION_SLICE_BINDING_TIMEOUT_MS);
+ }
+
+ loadPanelWhenReady();
+ });
+ }
+ }
+
+ /**
+ * When all of the Slices have loaded for the first time, then we can setup the
+ * {@link RecyclerView}.
+ * <p>
+ * When the Recyclerview has been laid out, we can begin the animation with the
+ * {@link mOnGlobalLayoutListener}, which calls {@link #animateIn()}.
+ */
+ private void loadPanelWhenReady() {
+ if (mPanelSlicesLoaderCountdownLatch.isPanelReadyToLoad()) {
+ mAdapter = new PanelSlicesAdapter(
+ this, mSliceLiveData, mPanel.getMetricsCategory());
+ mPanelSlices.setAdapter(mAdapter);
+ mPanelSlices.getViewTreeObserver()
+ .addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+
+ DividerItemDecoration itemDecoration = new DividerItemDecoration(getActivity());
+ itemDecoration
+ .setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
+ mPanelSlices.addItemDecoration(itemDecoration);
+ }
+ }
+
+ /**
+ * Animate a Panel onto the screen.
+ * <p>
+ * Takes the entire panel and animates in from behind the navigation bar.
+ * <p>
+ * Relies on the Panel being having a fixed height to begin the animation.
+ */
+ private void animateIn() {
+ final View panelContent = mLayoutView.findViewById(R.id.panel_container);
+ final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView, panelContent.getHeight(),
+ 0.0f, new DecelerateInterpolator());
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(0.0f, 1.0f);
+ animatorSet.play(animator);
+ animatorSet.start();
+ // Remove the predraw listeners on the Panel.
+ mLayoutView.getViewTreeObserver().removeOnPreDrawListener(mOnPreDrawListener);
+ }
+
+ /**
+ * Build an {@link AnimatorSet} to bring the Panel, {@param parentView}in our out of the screen,
+ * based on the positional parameters {@param startY}, {@param endY} and at the rate set by the
+ * {@param interpolator}.
+ */
+ @NonNull
+ private static AnimatorSet buildAnimatorSet(@NonNull View parentView, float startY, float endY,
+ @NonNull Interpolator interpolator) {
+ final View sheet = parentView.findViewById(R.id.panel_container);
+ final AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.setDuration(DURATION_ANIMATE_PANEL_MS);
+ animatorSet.setInterpolator(interpolator);
+ animatorSet.playTogether(ObjectAnimator.ofFloat(sheet, View.TRANSLATION_Y, startY, endY));
+ return animatorSet;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ if (TextUtils.isEmpty(mPanelClosedKey)) {
+ mPanelClosedKey = PanelClosedKeys.KEY_OTHERS;
}
- return view;
+ mMetricsProvider.action(
+ 0 /* attribution */,
+ SettingsEnums.PAGE_HIDE,
+ mPanel.getMetricsCategory(),
+ mPanelClosedKey,
+ 0 /* value */);
}
@VisibleForTesting
View.OnClickListener getSeeMoreListener() {
return (v) -> {
- mMetricsProvider.action(
- 0 /* attribution */,
- SettingsEnums.PAGE_HIDE ,
- mPanel.getMetricsCategory(),
- PanelClosedKeys.KEY_SEE_MORE,
- 0 /* value */);
+ mPanelClosedKey = PanelClosedKeys.KEY_SEE_MORE;
final FragmentActivity activity = getActivity();
activity.startActivityForResult(mPanel.getSeeMoreIntent(), 0);
activity.finish();
@@ -129,12 +292,7 @@
@VisibleForTesting
View.OnClickListener getCloseListener() {
return (v) -> {
- mMetricsProvider.action(
- 0 /* attribution */,
- SettingsEnums.PAGE_HIDE,
- mPanel.getMetricsCategory(),
- PanelClosedKeys.KEY_DONE,
- 0 /* value */);
+ mPanelClosedKey = PanelClosedKeys.KEY_DONE;
getActivity().finish();
};
}
diff --git a/src/com/android/settings/panel/PanelLoggingContract.java b/src/com/android/settings/panel/PanelLoggingContract.java
index e149186..e6e3012 100644
--- a/src/com/android/settings/panel/PanelLoggingContract.java
+++ b/src/com/android/settings/panel/PanelLoggingContract.java
@@ -39,8 +39,9 @@
String KEY_DONE = "done";
/**
- * The user clicked outside the dialog, closing the Panel.
+ * The user closed the panel by other ways, for example: clicked outside of dialog, tapping
+ * on back button, etc.
*/
- String KEY_CLICKED_OUT = "clicked_out";
+ String KEY_OTHERS = "others";
}
}
diff --git a/src/com/android/settings/panel/PanelSlicesAdapter.java b/src/com/android/settings/panel/PanelSlicesAdapter.java
index 0eec534..e244413 100644
--- a/src/com/android/settings/panel/PanelSlicesAdapter.java
+++ b/src/com/android/settings/panel/PanelSlicesAdapter.java
@@ -20,7 +20,6 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -30,13 +29,13 @@
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.Slice;
-import androidx.slice.widget.SliceLiveData;
import androidx.slice.widget.SliceView;
import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.google.android.setupdesign.DividerItemDecoration;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -45,14 +44,15 @@
public class PanelSlicesAdapter
extends RecyclerView.Adapter<PanelSlicesAdapter.SliceRowViewHolder> {
- private final List<Uri> mSliceUris;
+ private final List<LiveData<Slice>> mSliceLiveData;
+ private final int mMetricsCategory;
private final PanelFragment mPanelFragment;
- private final PanelContent mPanelContent;
- public PanelSlicesAdapter(PanelFragment fragment, PanelContent panel) {
+ public PanelSlicesAdapter(
+ PanelFragment fragment, List<LiveData<Slice>> sliceLiveData, int metricsCategory) {
mPanelFragment = fragment;
- mSliceUris = panel.getSlices();
- mPanelContent = panel;
+ mSliceLiveData = new ArrayList<>(sliceLiveData);
+ mMetricsCategory = metricsCategory;
}
@NonNull
@@ -62,67 +62,60 @@
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.panel_slice_row, viewGroup, false);
- return new SliceRowViewHolder(view, mPanelContent);
+ return new SliceRowViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SliceRowViewHolder sliceRowViewHolder, int position) {
- sliceRowViewHolder.onBind(mPanelFragment, mSliceUris.get(position));
+ sliceRowViewHolder.onBind(mSliceLiveData.get(position));
}
@Override
public int getItemCount() {
- return mSliceUris.size();
+ return mSliceLiveData.size();
}
@VisibleForTesting
- List<Uri> getData() {
- return mSliceUris;
+ List<LiveData<Slice>> getData() {
+ return mSliceLiveData;
}
/**
* ViewHolder for binding Slices to SliceViews.
*/
- public static class SliceRowViewHolder extends RecyclerView.ViewHolder
+ public class SliceRowViewHolder extends RecyclerView.ViewHolder
implements DividerItemDecoration.DividedViewHolder {
- private final PanelContent mPanelContent;
-
private boolean mDividerAllowedAbove = true;
@VisibleForTesting
- LiveData<Slice> sliceLiveData;
-
- @VisibleForTesting
final SliceView sliceView;
- public SliceRowViewHolder(View view, PanelContent panelContent) {
+ public SliceRowViewHolder(View view) {
super(view);
sliceView = view.findViewById(R.id.slice_view);
sliceView.setMode(SliceView.MODE_LARGE);
sliceView.showTitleItems(true);
- mPanelContent = panelContent;
}
- public void onBind(PanelFragment fragment, Uri sliceUri) {
- final Context context = sliceView.getContext();
- sliceLiveData = SliceLiveData.fromUri(context, sliceUri);
- sliceLiveData.observe(fragment.getViewLifecycleOwner(), sliceView);
+ public void onBind(LiveData<Slice> sliceLiveData) {
+ sliceLiveData.observe(mPanelFragment.getViewLifecycleOwner(), sliceView);
// Do not show the divider above media devices switcher slice per request
- if (sliceUri.equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) {
+ final Slice slice = sliceLiveData.getValue();
+ if (slice != null && slice.getUri().equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) {
mDividerAllowedAbove = false;
}
// Log Panel interaction
sliceView.setOnSliceActionListener(
((eventInfo, sliceItem) -> {
- FeatureFactory.getFactory(context)
+ FeatureFactory.getFactory(sliceView.getContext())
.getMetricsFeatureProvider()
.action(0 /* attribution */,
SettingsEnums.ACTION_PANEL_INTERACTION,
- mPanelContent.getMetricsCategory(),
- sliceUri.toString() /* log key */,
+ mMetricsCategory,
+ sliceLiveData.toString() /* log key */,
eventInfo.actionType /* value */);
})
);
diff --git a/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatch.java b/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatch.java
new file mode 100644
index 0000000..6137d6c
--- /dev/null
+++ b/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatch.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.panel;
+
+import android.net.Uri;
+
+import androidx.slice.Slice;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Helper class to isolate the work tracking all of the {@link Slice Slices} being loaded.
+ * <p>
+ * Uses a {@link CountDownLatch} and a {@link Set} of Slices to track how many
+ * Slices have been loaded. A Slice can only be counted as being loaded a single time, even
+ * when they get updated later.
+ * <p>
+ * To use the class, pass the number of expected Slices to load into the constructor. For
+ * every Slice that loads, call {@link #markSliceLoaded(Uri)} with the corresponding
+ * {@link Uri}. Then check if all of the Slices have loaded with
+ * {@link #isPanelReadyToLoad()}, which will return {@code true} the first time after all
+ * Slices have loaded.
+ */
+public class PanelSlicesLoaderCountdownLatch {
+ private final Set<Uri> mLoadedSlices;
+ private final CountDownLatch mCountDownLatch;
+ private boolean slicesReadyToLoad = false;
+
+ public PanelSlicesLoaderCountdownLatch(int countdownSize) {
+ mLoadedSlices = new HashSet<>();
+ mCountDownLatch = new CountDownLatch(countdownSize);
+ }
+
+ /**
+ * Checks if the {@param sliceUri} has been loaded: if not, then decrement the countdown
+ * latch, and if so, then do nothing.
+ */
+ public void markSliceLoaded(Uri sliceUri) {
+ if (mLoadedSlices.contains(sliceUri)) {
+ return;
+ }
+ mLoadedSlices.add(sliceUri);
+ mCountDownLatch.countDown();
+ }
+
+ /**
+ * @return {@code true} if the Slice has already been loaded.
+ */
+ public boolean isSliceLoaded(Uri uri) {
+ return mLoadedSlices.contains(uri);
+ }
+
+ /**
+ * @return {@code true} when all Slices have loaded, and the Panel has not yet been loaded.
+ */
+ public boolean isPanelReadyToLoad() {
+ /**
+ * Use {@link slicesReadyToLoad} to track whether or not the Panel has been loaded. We
+ * only want to animate the Panel a single time.
+ */
+ if ((mCountDownLatch.getCount() == 0) && !slicesReadyToLoad) {
+ slicesReadyToLoad = true;
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 8aee382..eabd715 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -97,21 +97,4 @@
fragmentManager.beginTransaction().add(R.id.main_content, panelFragment).commit();
}
}
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- final PanelContent panelContent = FeatureFactory.getFactory(this)
- .getPanelFeatureProvider()
- .getPanel(this, getIntent().getAction(), null /* Media Package Name */);
- FeatureFactory.getFactory(this)
- .getMetricsFeatureProvider()
- .action(0 /* attribution */,
- SettingsEnums.PAGE_HIDE,
- panelContent.getMetricsCategory(),
- PanelClosedKeys.KEY_CLICKED_OUT,
- 0 /* value */);
- }
- return super.onTouchEvent(event);
- }
}
diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java
index 4ea7fe7..2cbf729 100644
--- a/src/com/android/settings/panel/VolumePanel.java
+++ b/src/com/android/settings/panel/VolumePanel.java
@@ -30,6 +30,7 @@
import android.provider.Settings;
import com.android.settings.R;
+import com.android.settings.notification.RemoteVolumePreferenceController;
import java.util.ArrayList;
import java.util.List;
@@ -54,7 +55,9 @@
@Override
public List<Uri> getSlices() {
final List<Uri> uris = new ArrayList<>();
- uris.add(VOLUME_REMOTE_MEDIA_URI);
+ if (RemoteVolumePreferenceController.getActiveRemoteToken(mContext) != null) {
+ uris.add(VOLUME_REMOTE_MEDIA_URI);
+ }
uris.add(VOLUME_MEDIA_URI);
uris.add(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
uris.add(VOLUME_CALL_URI);
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index 580c7ba..7eb8dc2 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -66,8 +66,8 @@
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricEnrollActivity;
import com.android.settings.biometrics.BiometricEnrollBase;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -76,7 +76,6 @@
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.FooterPreferenceMixinCompat;
-import java.util.Arrays;
import java.util.List;
public class ChooseLockGeneric extends SettingsActivity {
@@ -141,7 +140,7 @@
@VisibleForTesting
static final int CHOOSE_LOCK_REQUEST = 102;
@VisibleForTesting
- static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103;
+ static final int CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST = 103;
@VisibleForTesting
static final int SKIP_FINGERPRINT_REQUEST = 104;
@@ -366,7 +365,7 @@
startActivityForResult(
intent,
mIsSetNewPassword && mHasChallenge
- ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
+ ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
: ENABLE_ENCRYPTION_REQUEST);
} else {
if (mForChangeCredRequiredForBoot) {
@@ -411,9 +410,9 @@
finish();
}
}
- } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
+ } else if (requestCode == CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
&& resultCode == BiometricEnrollBase.RESULT_FINISHED) {
- Intent intent = getFindSensorIntent(getActivity());
+ Intent intent = getBiometricEnrollIntent(getActivity());
if (data != null) {
intent.putExtras(data.getExtras());
}
@@ -438,8 +437,11 @@
}
}
- protected Intent getFindSensorIntent(Context context) {
- return new Intent(context, FingerprintEnrollFindSensor.class);
+ protected Intent getBiometricEnrollIntent(Context context) {
+ final Intent intent =
+ new Intent(context, BiometricEnrollActivity.InternalActivity.class);
+ intent.putExtra(BiometricEnrollActivity.EXTRA_SKIP_INTRO, true);
+ return intent;
}
@Override
@@ -764,7 +766,7 @@
intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
startActivityForResult(intent,
mIsSetNewPassword && mHasChallenge
- ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
+ ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
: CHOOSE_LOCK_REQUEST);
return;
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 16cecc8..21ef720 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -443,7 +443,7 @@
mSkipOrClearButton = mixin.getSecondaryButton();
mNextButton = mixin.getPrimaryButton();
- mMessage = view.findViewById(R.id.message);
+ mMessage = view.findViewById(R.id.sud_layout_description);
if (mForFingerprint) {
mLayout.setIcon(getActivity().getDrawable(R.drawable.ic_fingerprint_header));
} else if (mForFace) {
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index e0974fe..85b9a46 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -520,7 +520,7 @@
mTitleText = view.findViewById(R.id.suc_layout_title);
mHeaderText = (TextView) view.findViewById(R.id.headerText);
mDefaultHeaderColorList = mHeaderText.getTextColors();
- mMessageText = view.findViewById(R.id.message);
+ mMessageText = view.findViewById(R.id.sud_layout_description);
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
mLockPatternView.setOnPatternListener(mChooseNewLockPatternListener);
mLockPatternView.setTactileFeedbackEnabled(
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 6c61967..f2b5a35 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -137,7 +137,7 @@
if (mHeaderTextView == null) {
mHeaderTextView = view.findViewById(R.id.suc_layout_title);
}
- mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
+ mDetailsTextView = (TextView) view.findViewById(R.id.sud_layout_description);
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
|| DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 6d3d6e5..f43ee7f 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -116,7 +116,7 @@
false);
mHeaderTextView = (TextView) view.findViewById(R.id.headerText);
mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern);
- mDetailsTextView = (TextView) view.findViewById(R.id.detailsText);
+ mDetailsTextView = (TextView) view.findViewById(R.id.sud_layout_description);
mErrorTextView = (TextView) view.findViewById(R.id.errorText);
mLeftSpacerLandscape = view.findViewById(R.id.leftSpacer);
mRightSpacerLandscape = view.findViewById(R.id.rightSpacer);
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index 346e771..72b9fa8 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -42,6 +42,7 @@
import com.android.settings.R;
import com.android.settings.SetupEncryptionInterstitial;
import com.android.settings.SetupWizardUtils;
+import com.android.settings.biometrics.BiometricEnrollActivity;
import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor;
import com.android.settings.utils.SettingsDividerItemDecoration;
@@ -229,8 +230,8 @@
}
@Override
- protected Intent getFindSensorIntent(Context context) {
- final Intent intent = new Intent(context, SetupFingerprintEnrollFindSensor.class);
+ protected Intent getBiometricEnrollIntent(Context context) {
+ final Intent intent = getBiometricEnrollIntent(context);
SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
return intent;
}
diff --git a/src/com/android/settings/sim/CallsSimListDialogFragment.java b/src/com/android/settings/sim/CallsSimListDialogFragment.java
new file mode 100644
index 0000000..bb5a003
--- /dev/null
+++ b/src/com/android/settings/sim/CallsSimListDialogFragment.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import android.content.Context;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Specialized version of SimListDialogFragment that fetches a list of SIMs which support calls.
+ */
+public class CallsSimListDialogFragment extends SimListDialogFragment {
+ @Override
+ protected List<SubscriptionInfo> getCurrentSubscriptions() {
+ final Context context = getContext();
+ final SubscriptionManager subscriptionManager = context.getSystemService(
+ SubscriptionManager.class);
+ final TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ final List<PhoneAccountHandle> phoneAccounts =
+ telecomManager.getCallCapablePhoneAccounts();
+ final List<SubscriptionInfo> result = new ArrayList<>();
+
+ if (phoneAccounts == null) {
+ return result;
+ }
+ for (PhoneAccountHandle handle : phoneAccounts) {
+ final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle);
+ final int subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount);
+
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ continue;
+ }
+ result.add(subscriptionManager.getActiveSubscriptionInfo(subId));
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java
new file mode 100644
index 0000000..5b81e62
--- /dev/null
+++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+
+/**
+ * Presents a dialog asking the user if they want to update all services to use a given "preferred"
+ * SIM. Typically this would be used in a case where a device goes from having multiple SIMs down to
+ * only one.
+ */
+public class PreferredSimDialogFragment extends SimDialogFragment implements
+ DialogInterface.OnClickListener {
+ private static final String TAG = "PreferredSimDialogFrag";
+
+ public static PreferredSimDialogFragment newInstance() {
+ final PreferredSimDialogFragment fragment = new PreferredSimDialogFragment();
+ final Bundle args = initArguments(SimDialogActivity.PREFERRED_PICK,
+ R.string.sim_preferred_title);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ final AlertDialog dialog = new AlertDialog.Builder(getContext())
+ .setTitle(getTitleResId())
+ .setPositiveButton(R.string.yes, this)
+ .setNegativeButton(R.string.no, null)
+ .create();
+ updateDialog(dialog);
+ return dialog;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int buttonClicked) {
+ if (buttonClicked != DialogInterface.BUTTON_POSITIVE) {
+ return;
+ }
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
+ final SubscriptionInfo info = getPreferredSubscription();
+ if (info != null) {
+ activity.onSubscriptionSelected(getDialogType(), info.getSubscriptionId());
+ }
+ }
+
+ public SubscriptionInfo getPreferredSubscription() {
+ final Activity activity = getActivity();
+ final int slotId = activity.getIntent().getIntExtra(SimDialogActivity.PREFERRED_SIM,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ return getSubscriptionManager().getActiveSubscriptionInfoForSimSlotIndex(slotId);
+ }
+
+ private void updateDialog(AlertDialog dialog) {
+ final SubscriptionInfo info = getPreferredSubscription();
+ if (info == null) {
+ dismiss();
+ return;
+ }
+ final String message =
+ getContext().getString(R.string.sim_preferred_message, info.getDisplayName());
+ dialog.setMessage(message);
+ }
+
+ @Override
+ public void updateDialog() {
+ updateDialog((AlertDialog) getDialog());
+ }
+
+ @VisibleForTesting
+ protected SubscriptionManager getSubscriptionManager() {
+ return getContext().getSystemService(SubscriptionManager.class);
+ }
+}
diff --git a/src/com/android/settings/sim/SimDialogActivity.java b/src/com/android/settings/sim/SimDialogActivity.java
index 487dace..d721efd 100644
--- a/src/com/android/settings/sim/SimDialogActivity.java
+++ b/src/com/android/settings/sim/SimDialogActivity.java
@@ -16,37 +16,30 @@
package com.android.settings.sim;
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
+import android.content.Intent;
import android.os.Bundle;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
-import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
+import android.util.Log;
import android.widget.Toast;
-import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
import com.android.settings.R;
-import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-public class SimDialogActivity extends Activity {
+/**
+ * This activity provides singleton semantics per dialog type for showing various kinds of
+ * dialogs asking the user to make choices about which SIM to use for various services
+ * (calls, SMS, and data).
+ */
+public class SimDialogActivity extends FragmentActivity {
private static String TAG = "SimDialogActivity";
public static String PREFERRED_SIM = "preferred_sim";
@@ -60,276 +53,118 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final int dialogType = getIntent().getIntExtra(DIALOG_TYPE_KEY, INVALID_PICK);
+ showOrUpdateDialog();
+ }
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ showOrUpdateDialog();
+ }
+
+ private void showOrUpdateDialog() {
+ final int dialogType = getIntent().getIntExtra(DIALOG_TYPE_KEY, INVALID_PICK);
+ final String tag = Integer.toString(dialogType);
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ SimDialogFragment fragment = (SimDialogFragment) fragmentManager.findFragmentByTag(tag);
+
+ if (fragment == null) {
+ fragment = createFragment(dialogType);
+ fragment.show(fragmentManager, tag);
+ } else {
+ fragment.updateDialog();
+ }
+ }
+
+ private SimDialogFragment createFragment(int dialogType) {
+ switch(dialogType) {
+ case DATA_PICK:
+ return SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
+ false /* includeAskEveryTime */);
+ case CALLS_PICK:
+ return CallsSimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_calls,
+ true /* includeAskEveryTime */);
+ case SMS_PICK:
+ return SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_sms,
+ false /* includeAskEveryTime */);
+ case PREFERRED_PICK:
+ if (!getIntent().hasExtra(PREFERRED_SIM)) {
+ throw new IllegalArgumentException("Missing required extra " + PREFERRED_SIM);
+ }
+ return PreferredSimDialogFragment.newInstance();
+ default:
+ throw new IllegalArgumentException( "Invalid dialog type " + dialogType + " sent.");
+ }
+ }
+
+ public void onSubscriptionSelected(int dialogType, int subId) {
+ if (getSupportFragmentManager().findFragmentByTag(Integer.toString(dialogType)) == null) {
+ Log.w(TAG, "onSubscriptionSelected ignored because stored fragment was null");
+ return;
+ }
switch (dialogType) {
case DATA_PICK:
+ setDefaultDataSubId(subId);
+ break;
case CALLS_PICK:
+ setDefaultCallsSubId(subId);
+ break;
case SMS_PICK:
- createDialog(this, dialogType).show();
+ setDefaultSmsSubId(subId);
break;
case PREFERRED_PICK:
- displayPreferredDialog(getIntent().getIntExtra(PREFERRED_SIM, 0));
+ setPreferredSim(subId);
break;
default:
- throw new IllegalArgumentException("Invalid dialog type " + dialogType + " sent.");
- }
-
- }
-
- private void displayPreferredDialog(final int slotId) {
- final Resources res = getResources();
- final Context context = getApplicationContext();
- final SubscriptionInfo sir = SubscriptionManager.from(context)
- .getActiveSubscriptionInfoForSimSlotIndex(slotId);
-
- if (sir != null) {
- AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
- alertDialogBuilder.setTitle(R.string.sim_preferred_title);
- alertDialogBuilder.setMessage(res.getString(
- R.string.sim_preferred_message, sir.getDisplayName()));
-
- alertDialogBuilder.setPositiveButton(R.string.yes, new
- DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- final int subId = sir.getSubscriptionId();
- PhoneAccountHandle phoneAccountHandle =
- subscriptionIdToPhoneAccountHandle(subId);
- setDefaultDataSubId(context, subId);
- setDefaultSmsSubId(context, subId);
- setUserSelectedOutgoingPhoneAccount(phoneAccountHandle);
- finish();
- }
- });
- alertDialogBuilder.setNegativeButton(R.string.no, new
- DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,int id) {
- finish();
- }
- });
-
- alertDialogBuilder.create().show();
- } else {
- finish();
+ throw new IllegalArgumentException(
+ "Invalid dialog type " + dialogType + " sent.");
}
}
- private static void setDefaultDataSubId(final Context context, final int subId) {
- final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
- final TelephonyManager telephonyManager = TelephonyManager.from(context)
- .createForSubscriptionId(subId);
+ public void onFragmentDismissed(SimDialogFragment simDialogFragment) {
+ final List<Fragment> fragments = getSupportFragmentManager().getFragments();
+ if (fragments.size() == 1 && fragments.get(0) == simDialogFragment) {
+ finishAndRemoveTask();
+ }
+ }
+
+ private void setDefaultDataSubId(final int subId) {
+ final SubscriptionManager subscriptionManager = getSystemService(SubscriptionManager.class);
+ final TelephonyManager telephonyManager = getSystemService(
+ TelephonyManager.class).createForSubscriptionId(subId);
subscriptionManager.setDefaultDataSubId(subId);
telephonyManager.setDataEnabled(true);
- Toast.makeText(context, R.string.data_switch_started, Toast.LENGTH_LONG).show();
+ Toast.makeText(this, R.string.data_switch_started, Toast.LENGTH_LONG).show();
}
- private static void setDefaultSmsSubId(final Context context, final int subId) {
- final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
- subscriptionManager.setDefaultSmsSubId(subId);
- }
-
- private void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle phoneAccount) {
- final TelecomManager telecomManager = TelecomManager.from(this);
+ private void setDefaultCallsSubId(final int subId) {
+ final PhoneAccountHandle phoneAccount = subscriptionIdToPhoneAccountHandle(subId);
+ final TelecomManager telecomManager = getSystemService(TelecomManager.class);
telecomManager.setUserSelectedOutgoingPhoneAccount(phoneAccount);
}
+ private void setDefaultSmsSubId(final int subId) {
+ final SubscriptionManager subscriptionManager = getSystemService(SubscriptionManager.class);
+ subscriptionManager.setDefaultSmsSubId(subId);
+ }
+
+ private void setPreferredSim(final int subId) {
+ setDefaultDataSubId(subId);
+ setDefaultSmsSubId(subId);
+ setDefaultCallsSubId(subId);
+ }
+
private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) {
- final TelecomManager telecomManager = TelecomManager.from(this);
- final TelephonyManager telephonyManager = TelephonyManager.from(this);
- final Iterator<PhoneAccountHandle> phoneAccounts =
- telecomManager.getCallCapablePhoneAccounts().listIterator();
+ final TelecomManager telecomManager = getSystemService(TelecomManager.class);
+ final TelephonyManager telephonyManager = getSystemService(TelephonyManager.class);
- while (phoneAccounts.hasNext()) {
- final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next();
- final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
+ for (PhoneAccountHandle handle : telecomManager.getCallCapablePhoneAccounts()) {
+ final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle);
if (subId == telephonyManager.getSubIdForPhoneAccount(phoneAccount)) {
- return phoneAccountHandle;
+ return handle;
}
}
-
return null;
}
-
- public Dialog createDialog(final Context context, final int id) {
- final ArrayList<String> list = new ArrayList<String>();
- final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
- final List<SubscriptionInfo> subInfoList =
- subscriptionManager.getActiveSubscriptionInfoList(true);
- final int selectableSubInfoLength = subInfoList == null ? 0 : subInfoList.size();
-
- final DialogInterface.OnClickListener selectionListener =
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int value) {
-
- final SubscriptionInfo sir;
-
- switch (id) {
- case DATA_PICK:
- sir = subInfoList.get(value);
- setDefaultDataSubId(context, sir.getSubscriptionId());
- break;
- case CALLS_PICK:
- final TelecomManager telecomManager =
- TelecomManager.from(context);
- final List<PhoneAccountHandle> phoneAccountsList =
- telecomManager.getCallCapablePhoneAccounts();
- setUserSelectedOutgoingPhoneAccount(
- value < 1 ? null : phoneAccountsList.get(value - 1));
- break;
- case SMS_PICK:
- sir = subInfoList.get(value);
- setDefaultSmsSubId(context, sir.getSubscriptionId());
- break;
- default:
- throw new IllegalArgumentException("Invalid dialog type "
- + id + " in SIM dialog.");
- }
-
- finish();
- }
- };
-
- Dialog.OnKeyListener keyListener = new Dialog.OnKeyListener() {
- @Override
- public boolean onKey(DialogInterface arg0, int keyCode,
- KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- finish();
- }
- return true;
- }
- };
-
- ArrayList<SubscriptionInfo> callsSubInfoList = new ArrayList<SubscriptionInfo>();
- if (id == CALLS_PICK) {
- final TelecomManager telecomManager = TelecomManager.from(context);
- final TelephonyManager telephonyManager = TelephonyManager.from(context);
- final Iterator<PhoneAccountHandle> phoneAccounts =
- telecomManager.getCallCapablePhoneAccounts().listIterator();
-
- list.add(getResources().getString(R.string.sim_calls_ask_first_prefs_title));
- callsSubInfoList.add(null);
- while (phoneAccounts.hasNext()) {
- final PhoneAccount phoneAccount =
- telecomManager.getPhoneAccount(phoneAccounts.next());
- list.add((String)phoneAccount.getLabel());
- int subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount);
- if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- final SubscriptionInfo sir = SubscriptionManager.from(context)
- .getActiveSubscriptionInfo(subId);
- callsSubInfoList.add(sir);
- } else {
- callsSubInfoList.add(null);
- }
- }
- } else {
- for (int i = 0; i < selectableSubInfoLength; ++i) {
- final SubscriptionInfo sir = subInfoList.get(i);
- CharSequence displayName = sir.getDisplayName();
- if (displayName == null) {
- displayName = "";
- }
- list.add(displayName.toString());
- }
- }
-
- String[] arr = list.toArray(new String[0]);
-
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
-
- ListAdapter adapter = new SelectAccountListAdapter(
- id == CALLS_PICK ? callsSubInfoList : subInfoList,
- builder.getContext(),
- R.layout.select_account_list_item,
- arr, id);
-
- switch (id) {
- case DATA_PICK:
- builder.setTitle(R.string.select_sim_for_data);
- break;
- case CALLS_PICK:
- builder.setTitle(R.string.select_sim_for_calls);
- break;
- case SMS_PICK:
- builder.setTitle(R.string.select_sim_for_sms);
- break;
- default:
- throw new IllegalArgumentException("Invalid dialog type "
- + id + " in SIM dialog.");
- }
-
- Dialog dialog = builder.setAdapter(adapter, selectionListener).create();
- dialog.setOnKeyListener(keyListener);
-
- dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- finish();
- }
- });
-
- return dialog;
-
- }
-
- private class SelectAccountListAdapter extends ArrayAdapter<String> {
- private Context mContext;
- private int mResId;
- private int mDialogId;
- private final float OPACITY = 0.54f;
- private List<SubscriptionInfo> mSubInfoList;
-
- public SelectAccountListAdapter(List<SubscriptionInfo> subInfoList,
- Context context, int resource, String[] arr, int dialogId) {
- super(context, resource, arr);
- mContext = context;
- mResId = resource;
- mDialogId = dialogId;
- mSubInfoList = subInfoList;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View rowView;
- final ViewHolder holder;
-
- if (convertView == null) {
- // Cache views for faster scrolling
- rowView = inflater.inflate(mResId, null);
- holder = new ViewHolder();
- holder.title = (TextView) rowView.findViewById(R.id.title);
- holder.summary = (TextView) rowView.findViewById(R.id.summary);
- holder.icon = (ImageView) rowView.findViewById(R.id.icon);
- rowView.setTag(holder);
- } else {
- rowView = convertView;
- holder = (ViewHolder) rowView.getTag();
- }
-
- final SubscriptionInfo sir = mSubInfoList.get(position);
- if (sir == null) {
- holder.title.setText(getItem(position));
- holder.summary.setText("");
- holder.icon.setImageDrawable(getResources()
- .getDrawable(R.drawable.ic_live_help));
- holder.icon.setAlpha(OPACITY);
- } else {
- holder.title.setText(sir.getDisplayName());
- holder.summary.setText(sir.getNumber());
- holder.icon.setImageBitmap(sir.createIconBitmap(mContext));
- }
- return rowView;
- }
-
- private class ViewHolder {
- TextView title;
- TextView summary;
- ImageView icon;
- }
- }
}
diff --git a/src/com/android/settings/sim/SimDialogFragment.java b/src/com/android/settings/sim/SimDialogFragment.java
new file mode 100644
index 0000000..10815fd
--- /dev/null
+++ b/src/com/android/settings/sim/SimDialogFragment.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+
+/** Common functionality for showing a dialog in SimDialogActivity. */
+public abstract class SimDialogFragment extends DialogFragment {
+ private static final String TAG = "SimDialogFragment";
+
+ private static final String KEY_TITLE_ID = "title_id";
+ private static final String KEY_DIALOG_TYPE = "dialog_type";
+
+ protected static Bundle initArguments(int dialogType, int titleResId) {
+ final Bundle args = new Bundle();
+ args.putInt(KEY_DIALOG_TYPE, dialogType);
+ args.putInt(KEY_TITLE_ID, titleResId);
+ return args;
+ }
+
+ public int getDialogType() {
+ return getArguments().getInt(KEY_DIALOG_TYPE);
+ }
+
+ public int getTitleResId() {
+ return getArguments().getInt(KEY_TITLE_ID);
+ }
+
+ @Override
+ public void onDismiss(@NonNull DialogInterface dialog) {
+ super.onDismiss(dialog);
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
+ if (activity != null && !activity.isFinishing()) {
+ activity.onFragmentDismissed(this);
+ }
+ }
+
+ public abstract void updateDialog();
+}
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
new file mode 100644
index 0000000..f78c4e7
--- /dev/null
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows a dialog consisting of a list of SIMs (aka subscriptions), possibly including an additional
+ * entry indicating "ask me every time".
+ */
+public class SimListDialogFragment extends SimDialogFragment implements
+ DialogInterface.OnClickListener {
+ protected static final String KEY_INCLUDE_ASK_EVERY_TIME = "include_ask_every_time";
+
+ protected SelectSubscriptionAdapter mAdapter;
+ @VisibleForTesting
+ List<SubscriptionInfo> mSubscriptions;
+
+ public static SimListDialogFragment newInstance(int dialogType, int titleResId,
+ boolean includeAskEveryTime) {
+ final SimListDialogFragment fragment = new SimListDialogFragment();
+ final Bundle args = initArguments(dialogType, titleResId);
+ args.putBoolean(KEY_INCLUDE_ASK_EVERY_TIME, includeAskEveryTime);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ mSubscriptions = new ArrayList<>();
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setTitle(getTitleResId());
+
+ mAdapter = new SelectSubscriptionAdapter(builder.getContext(), mSubscriptions);
+
+ setAdapter(builder);
+ final Dialog dialog = builder.create();
+ updateDialog();
+ return dialog;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int selectionIndex) {
+ if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) {
+ int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex);
+ if (subscription != null) {
+ subId = subscription.getSubscriptionId();
+ }
+ final SimDialogActivity activity = (SimDialogActivity) getActivity();
+ activity.onSubscriptionSelected(getDialogType(), subId);
+ }
+ }
+
+ protected List<SubscriptionInfo> getCurrentSubscriptions() {
+ final SubscriptionManager manager = getContext().getSystemService(
+ SubscriptionManager.class);
+ return manager.getActiveSubscriptionInfoList(true);
+ }
+
+ @Override
+ public void updateDialog() {
+ List<SubscriptionInfo> currentSubscriptions = getCurrentSubscriptions();
+ if (currentSubscriptions == null) {
+ dismiss();
+ return;
+ }
+ if (getArguments().getBoolean(KEY_INCLUDE_ASK_EVERY_TIME)) {
+ final List<SubscriptionInfo> tmp = new ArrayList<>(currentSubscriptions.size() + 1);
+ tmp.add(null);
+ tmp.addAll(currentSubscriptions);
+ currentSubscriptions = tmp;
+ }
+ if (currentSubscriptions.equals(mSubscriptions)) {
+ return;
+ }
+ mSubscriptions.clear();
+ mSubscriptions.addAll(currentSubscriptions);
+ mAdapter.notifyDataSetChanged();
+ }
+
+ @VisibleForTesting
+ void setAdapter(AlertDialog.Builder builder) {
+ builder.setAdapter(mAdapter, this);
+ }
+
+ private static class SelectSubscriptionAdapter extends BaseAdapter {
+ private Context mContext;
+ private LayoutInflater mInflater;
+ List<SubscriptionInfo> mSubscriptions;
+
+ public SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions) {
+ mSubscriptions = subscriptions;
+ mContext = context;
+ }
+
+ @Override
+ public int getCount() {
+ return mSubscriptions.size();
+ }
+
+ @Override
+ public SubscriptionInfo getItem(int position) {
+ return mSubscriptions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ final SubscriptionInfo info = mSubscriptions.get(position);
+ if (info == null) {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ return info.getSubscriptionId();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ if (mInflater == null) {
+ mInflater = LayoutInflater.from(parent.getContext());
+ }
+ convertView = mInflater.inflate(R.layout.select_account_list_item, parent, false);
+ }
+ final SubscriptionInfo sub = getItem(position);
+
+ final TextView title = convertView.findViewById(R.id.title);
+ final TextView summary = convertView.findViewById(R.id.summary);
+ final ImageView icon = convertView.findViewById(R.id.icon);
+
+ if (sub == null) {
+ title.setText(R.string.sim_calls_ask_first_prefs_title);
+ summary.setText("");
+ icon.setImageDrawable(mContext.getDrawable(R.drawable.ic_help));
+ icon.setImageTintList(
+ Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
+ } else {
+ title.setText(sub.getDisplayName());
+ summary.setText(sub.getNumber());
+ icon.setImageBitmap(sub.createIconBitmap(mContext));
+
+ }
+ return convertView;
+ }
+ }
+}
diff --git a/src/com/android/settings/sim/SimSelectNotification.java b/src/com/android/settings/sim/SimSelectNotification.java
index a1e942a..3179e6a 100644
--- a/src/com/android/settings/sim/SimSelectNotification.java
+++ b/src/com/android/settings/sim/SimSelectNotification.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -89,7 +90,7 @@
.setColor(context.getColor(R.color.sim_noitification))
.setContentTitle(resources.getString(R.string.sim_notification_title))
.setContentText(resources.getString(R.string.sim_notification_summary));
- Intent resultIntent = new Intent(context, SimSettingsActivity.class);
+ Intent resultIntent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index e400815..dc3324b 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -19,8 +19,6 @@
import static android.provider.SettingsSlicesContract.KEY_LOCATION;
import static android.provider.SettingsSlicesContract.KEY_WIFI;
-import static com.android.settings.notification.ZenModeSoundSettingsPreferenceController.ZEN_MODE_KEY;
-
import android.content.ContentResolver;
import android.net.Uri;
import android.provider.SettingsSlicesContract;
@@ -43,6 +41,7 @@
import com.android.settings.media.MediaOutputIndicatorSlice;
import com.android.settings.media.MediaOutputSlice;
import com.android.settings.network.telephony.MobileDataSlice;
+import com.android.settings.notification.ZenModeButtonPreferenceController;
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
import com.android.settings.wifi.slice.ContextualWifiSlice;
import com.android.settings.wifi.slice.WifiSlice;
@@ -298,7 +297,7 @@
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
- .appendPath(ZEN_MODE_KEY)
+ .appendPath(ZenModeButtonPreferenceController.KEY)
.build();
/**
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index 9926a52..fc3d0cc 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -164,11 +164,12 @@
}
final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
- final int maxSteps = sliderController.getMaxSteps();
- if (newPosition < 0 || newPosition > maxSteps) {
+ final int minValue = sliderController.getMin();
+ final int maxValue = sliderController.getMax();
+ if (newPosition < minValue || newPosition > maxValue) {
throw new IllegalArgumentException(
- "Invalid position passed to Slider controller. Expected between 0 and "
- + maxSteps + " but found " + newPosition);
+ "Invalid position passed to Slider controller. Expected between " + minValue
+ + " and " + maxValue + " but found " + newPosition);
}
sliderController.setSliderPosition(newPosition);
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index 00a82d2..aa76a9e 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -326,7 +326,8 @@
.setTitle(sliceData.getTitle())
.setSubtitle(subtitleText)
.setPrimaryAction(primaryAction)
- .setMax(sliderController.getMaxSteps())
+ .setMax(sliderController.getMax())
+ .setMin(sliderController.getMin())
.setValue(sliderController.getSliderPosition())
.setInputAction(actionIntent))
.setKeywords(keywords)
diff --git a/src/com/android/settings/widget/SeekBarPreference.java b/src/com/android/settings/widget/SeekBarPreference.java
index f4d2aac..44def11 100644
--- a/src/com/android/settings/widget/SeekBarPreference.java
+++ b/src/com/android/settings/widget/SeekBarPreference.java
@@ -93,7 +93,7 @@
@Override
public boolean isSelectable() {
- return false;
+ return isDisabledByAdmin();
}
@Override
diff --git a/src/com/android/settings/widget/TintDrawable.java b/src/com/android/settings/widget/TintDrawable.java
new file mode 100644
index 0000000..13eb121
--- /dev/null
+++ b/src/com/android/settings/widget/TintDrawable.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.drawable.DrawableWrapper;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A Drawable that tints a contained Drawable, overriding the existing tint specified in the
+ * underlying drawable. This class should only be used in XML.
+ *
+ * @attr ref android.R.styleable#DrawableWrapper_drawable
+ * @attr ref R.styleable#TintDrawable_tint
+ */
+public class TintDrawable extends DrawableWrapper {
+ private ColorStateList mTint;
+ private int[] mThemeAttrs;
+
+ /** No-arg constructor used by drawable inflation. */
+ public TintDrawable() {
+ super(null);
+ }
+
+ @Override
+ public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+ @NonNull AttributeSet attrs, @Nullable Theme theme)
+ throws XmlPullParserException, IOException {
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.TintDrawable);
+
+ super.inflate(r, parser, attrs, theme);
+
+ mThemeAttrs = a.extractThemeAttrs();
+ updateStateFromTypedArray(a);
+ a.recycle();
+
+ applyTint();
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ if (mThemeAttrs != null) {
+ final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.TintDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ // Ensure tint is reapplied after applying the theme to ensure this drawables'
+ // tint overrides the underlying drawables' tint.
+ applyTint();
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return (mThemeAttrs != null && mThemeAttrs.length > 0) || super.canApplyTheme();
+ }
+
+ private void updateStateFromTypedArray(@NonNull TypedArray a) {
+ if (a.hasValue(R.styleable.TintDrawable_android_drawable)) {
+ setDrawable(a.getDrawable(R.styleable.TintDrawable_android_drawable));
+ }
+ if (a.hasValue(R.styleable.TintDrawable_android_tint)) {
+ mTint = a.getColorStateList(R.styleable.TintDrawable_android_tint);
+ }
+ }
+
+ private void applyTint() {
+ if (getDrawable() != null && mTint != null) {
+ getDrawable().mutate().setTintList(mTint);
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index fbea824..875f35d 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -16,6 +16,7 @@
package com.android.settings.wifi;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -64,11 +65,21 @@
public static WifiDialog createModal(Context context, WifiDialogListener listener,
AccessPoint accessPoint, int mode) {
return new WifiDialog(context, listener, accessPoint, mode, 0 /* style */,
- mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton*/);
+ mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton */);
+ }
+
+ /**
+ * Creates a WifiDialog with customized style. It displays as a dialog above the current
+ * view.
+ */
+ public static WifiDialog createModal(Context context, WifiDialogListener listener,
+ AccessPoint accessPoint, int mode, @StyleRes int style) {
+ return new WifiDialog(context, listener, accessPoint, mode, style,
+ mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton */);
}
/* package */ WifiDialog(Context context, WifiDialogListener listener, AccessPoint accessPoint,
- int mode, int style, boolean hideSubmitButton) {
+ int mode, @StyleRes int style, boolean hideSubmitButton) {
super(context, style);
mMode = mode;
mListener = listener;
diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java
index 35de66e..8268ecc 100644
--- a/src/com/android/settings/wifi/WifiDialogActivity.java
+++ b/src/com/android/settings/wifi/WifiDialogActivity.java
@@ -28,6 +28,7 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.wifi.dpp.WifiDppUtils;
import com.android.settingslib.wifi.AccessPoint;
@@ -74,8 +75,13 @@
accessPoint = new AccessPoint(this, accessPointState);
}
- mDialog = WifiDialog.createModal(
- this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT);
+ if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
+ mDialog = WifiDialog.createModal(this, this, accessPoint,
+ WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light);
+ } else {
+ mDialog = WifiDialog.createModal(
+ this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT);
+ }
mDialog.show();
mDialog.setOnDismissListener(this);
}
diff --git a/src/com/android/settings/wifi/WifiScanModeActivity.java b/src/com/android/settings/wifi/WifiScanModeActivity.java
index 934e972..5342729 100644
--- a/src/com/android/settings/wifi/WifiScanModeActivity.java
+++ b/src/com/android/settings/wifi/WifiScanModeActivity.java
@@ -25,6 +25,7 @@
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
@@ -132,7 +133,9 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
- .setMessage(getString(R.string.wifi_scan_always_turnon_message, mApp))
+ .setMessage(TextUtils.isEmpty(mApp) ?
+ getString(R.string.wifi_scan_always_turn_on_message_unknown) :
+ getString(R.string.wifi_scan_always_turnon_message, mApp))
.setPositiveButton(R.string.wifi_scan_always_confirm_allow,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 79b6383..238143e 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -71,7 +71,6 @@
import com.android.settings.wifi.WifiDialog.WifiDialogListener;
import com.android.settings.wifi.WifiUtils;
import com.android.settings.wifi.dpp.WifiDppUtils;
-import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -259,9 +258,9 @@
public void onLost(Network network) {
final boolean lostCurrentNetwork = network.equals(mNetwork);
if (lostCurrentNetwork) {
- // If support detail page for saved network, should update as disconnect but not
- // exit. Except for ephemeral network which should not show on saved network list.
- if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext) && !mIsEphemeral) {
+ // Should update as disconnect but not exit. Except for ephemeral network which
+ // should not show on saved network list.
+ if (!mIsEphemeral) {
return;
}
@@ -351,16 +350,12 @@
mLifecycle = lifecycle;
lifecycle.addObserver(this);
- if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)) {
- mWifiTracker = WifiTrackerFactory.create(
- mFragment.getActivity(),
- mWifiListener,
- mLifecycle,
- true /*includeSaved*/,
- true /*includeScans*/);
- } else {
- mWifiTracker = null;
- }
+ mWifiTracker = WifiTrackerFactory.create(
+ mFragment.getActivity(),
+ mWifiListener,
+ mLifecycle,
+ true /*includeSaved*/,
+ true /*includeScans*/);
mConnected = mAccessPoint.isActive();
// When lost the network connection, WifiInfo/NetworkInfo will be clear. So causes we
// could not check if the AccessPoint is ephemeral. Need to cache it in first.
@@ -409,9 +404,7 @@
.setButton3Enabled(true)
.setButton4Text(R.string.share)
.setButton4Icon(R.drawable.ic_qrcode_24dp)
- .setButton4OnClickListener(view -> shareNetwork())
- .setButton4Visible(
- WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mContext, mAccessPoint));
+ .setButton4OnClickListener(view -> shareNetwork());
mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED);
@@ -545,11 +538,6 @@
if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) {
// Once connected, can't get mNetworkInfo immediately, return false and wait for
// next time to update UI.
- if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)) {
- return false;
- }
-
- exitActivity();
return false;
}
@@ -749,20 +737,24 @@
mButtonsPref.setButton1Text(
mIsEphemeral ? R.string.wifi_disconnect_button_text : R.string.forget);
- mButtonsPref.setButton1Visible(canForgetNetwork());
- mButtonsPref.setButton2Visible(canSignIntoNetwork());
- mButtonsPref.setButton3Visible(canConnectNetwork());
- mButtonsPref.setButton4Visible(canShareNetwork());
- mButtonsPref.setVisible(canSignIntoNetwork()
- || canForgetNetwork()
- || canShareNetwork()
- || canConnectNetwork());
+ boolean canForgetNetwork = canForgetNetwork();
+ boolean canSignIntoNetwork = canSignIntoNetwork();
+ boolean canConnectNetwork = canConnectNetwork();
+ boolean canShareNetwork = canShareNetwork();
+
+ mButtonsPref.setButton1Visible(canForgetNetwork);
+ mButtonsPref.setButton2Visible(canSignIntoNetwork);
+ mButtonsPref.setButton3Visible(canConnectNetwork);
+ mButtonsPref.setButton4Visible(canShareNetwork);
+ mButtonsPref.setVisible(canForgetNetwork
+ || canSignIntoNetwork
+ || canConnectNetwork
+ || canShareNetwork);
}
private boolean canConnectNetwork() {
// Display connect button for disconnected AP even not in the range.
- return SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)
- && !mAccessPoint.isActive();
+ return !mAccessPoint.isActive();
}
private void refreshIpLayerInfo() {
@@ -854,7 +846,8 @@
* Returns whether the user can share the network represented by this preference with QR code.
*/
private boolean canShareNetwork() {
- return mAccessPoint.getConfig() != null;
+ return mAccessPoint.getConfig() != null &&
+ WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mContext, mAccessPoint);
}
/**
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 98673d4..4644f12 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -345,6 +345,9 @@
*/
public static boolean isSupportConfiguratorQrCodeScanner(Context context,
AccessPoint accessPoint) {
+ if (accessPoint.isPasspoint()) {
+ return false;
+ }
return isSupportWifiDpp(context, accessPoint.getSecurity());
}
@@ -356,6 +359,9 @@
*/
public static boolean isSupportConfiguratorQrCodeGenerator(Context context,
AccessPoint accessPoint) {
+ if (accessPoint.isPasspoint()) {
+ return false;
+ }
return isSupportZxing(context, accessPoint.getSecurity());
}
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
index 40e6e56..82c6028 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
@@ -92,7 +92,7 @@
@Override
public boolean onPreferenceClick(Preference preference) {
if (mHost != null) {
- mHost.showWifiDialog((AccessPointPreference) preference);
+ mHost.showWifiPage((AccessPointPreference) preference);
}
return false;
}
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
index 3f600e6..4daf7da 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
@@ -41,12 +41,10 @@
/**
* UI to manage saved networks/access points.
*/
-public class SavedAccessPointsWifiSettings extends DashboardFragment
- implements WifiDialog.WifiDialogListener, DialogInterface.OnCancelListener {
+public class SavedAccessPointsWifiSettings extends DashboardFragment {
private static final String TAG = "SavedAccessPoints";
- private WifiManager mWifiManager;
private Bundle mAccessPointSavedState;
private AccessPoint mSelectedAccessPoint;
@@ -71,8 +69,6 @@
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mWifiManager = (WifiManager) getContext()
- .getApplicationContext().getSystemService(Context.WIFI_SERVICE);
use(SavedAccessPointsPreferenceController.class)
.setHost(this);
use(SubscribedAccessPointsPreferenceController.class)
@@ -90,7 +86,7 @@
}
}
- public void showWifiDialog(@Nullable AccessPointPreference accessPoint) {
+ public void showWifiPage(@Nullable AccessPointPreference accessPoint) {
removeDialog(WifiSettings.WIFI_DIALOG_ID);
if (accessPoint != null) {
@@ -102,52 +98,18 @@
mAccessPointSavedState = null;
}
- if (usingDetailsFragment(getContext())) {
- if (mSelectedAccessPoint == null) {
- mSelectedAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
- }
- final Bundle savedState = new Bundle();
- mSelectedAccessPoint.saveWifiState(savedState);
-
- new SubSettingLauncher(getContext())
- .setTitleText(mSelectedAccessPoint.getTitle())
- .setDestination(WifiNetworkDetailsFragment.class.getName())
- .setArguments(savedState)
- .setSourceMetricsCategory(getMetricsCategory())
- .launch();
- } else {
- showDialog(WifiSettings.WIFI_DIALOG_ID);
+ if (mSelectedAccessPoint == null) {
+ mSelectedAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
}
- }
+ final Bundle savedState = new Bundle();
+ mSelectedAccessPoint.saveWifiState(savedState);
- @Override
- public Dialog onCreateDialog(int dialogId) {
- switch (dialogId) {
- case WifiSettings.WIFI_DIALOG_ID:
- // Modify network
- if (mSelectedAccessPoint == null) {
- // Restore AP from save state
- mSelectedAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
- // Reset the saved access point data
- mAccessPointSavedState = null;
- }
- final WifiDialog dialog = WifiDialog.createModal(
- getActivity(), this, mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW);
- dialog.setOnCancelListener(this);
-
- return dialog;
- }
- return super.onCreateDialog(dialogId);
- }
-
- @Override
- public int getDialogMetricsCategory(int dialogId) {
- switch (dialogId) {
- case WifiSettings.WIFI_DIALOG_ID:
- return SettingsEnums.DIALOG_WIFI_SAVED_AP_EDIT;
- default:
- return 0;
- }
+ new SubSettingLauncher(getContext())
+ .setTitleText(mSelectedAccessPoint.getTitle())
+ .setDestination(WifiNetworkDetailsFragment.class.getName())
+ .setArguments(savedState)
+ .setSourceMetricsCategory(getMetricsCategory())
+ .launch();
}
@Override
@@ -162,45 +124,6 @@
}
}
- @Override
- public void onForget(WifiDialog dialog) {
- if (mSelectedAccessPoint != null) {
- if (mSelectedAccessPoint.isPasspointConfig()) {
- try {
- mWifiManager.removePasspointConfiguration(
- mSelectedAccessPoint.getPasspointFqdn());
- } catch (RuntimeException e) {
- Log.e(TAG, "Failed to remove Passpoint configuration for "
- + mSelectedAccessPoint.getConfigName());
- }
- if (isSubscriptionsFeatureEnabled()) {
- use(SubscribedAccessPointsPreferenceController.class)
- .postRefreshSubscribedAccessPoints();
- } else {
- use(SavedAccessPointsPreferenceController.class)
- .postRefreshSavedAccessPoints();
- }
- } else {
- // both onSuccess/onFailure will call postRefreshSavedAccessPoints
- mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId,
- use(SavedAccessPointsPreferenceController.class));
- }
- mSelectedAccessPoint = null;
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- mSelectedAccessPoint = null;
- }
-
- /**
- * Checks if showing WifiNetworkDetailsFragment when clicking saved network item.
- */
- public static boolean usingDetailsFragment(Context context) {
- return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN);
- }
-
boolean isSubscriptionsFeatureEnabled() {
return FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.MOBILE_NETWORK_V2)
&& FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2);
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
index 8d31c82..048999a 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
@@ -91,7 +91,7 @@
@Override
public boolean onPreferenceClick(Preference preference) {
if (mHost != null) {
- mHost.showWifiDialog((AccessPointPreference) preference);
+ mHost.showWifiPage((AccessPointPreference) preference);
}
return false;
}
diff --git a/tests/robotests/src/com/android/settings/MasterClearConfirmTest.java b/tests/robotests/src/com/android/settings/MasterClearConfirmTest.java
index 0c6903a..822eb3c 100644
--- a/tests/robotests/src/com/android/settings/MasterClearConfirmTest.java
+++ b/tests/robotests/src/com/android/settings/MasterClearConfirmTest.java
@@ -47,7 +47,7 @@
masterClearConfirm.setSubtitle();
assertThat(((TextView) masterClearConfirm.mContentView
- .findViewById(R.id.master_clear_confirm)).getText())
+ .findViewById(R.id.sud_layout_description)).getText())
.isEqualTo(mActivity.getString(R.string.master_clear_final_desc_esim));
}
@@ -61,7 +61,7 @@
masterClearConfirm.setSubtitle();
assertThat(((TextView) masterClearConfirm.mContentView
- .findViewById(R.id.master_clear_confirm)).getText())
+ .findViewById(R.id.sud_layout_description)).getText())
.isEqualTo(mActivity.getString(R.string.master_clear_final_desc));
}
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 0cc9dc4..a07ffb9 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -154,19 +154,6 @@
assertThat(preference.getSummary()).isEqualTo(mContext.getResources().getString(resId));
}
- @Test
- public void testDarkUIModePreferenceSummary_shouldUpdateSummary() {
- final Preference darkUIModePreference = new Preference(mContext);
- final DarkUIPreferenceController mController;
- doReturn(darkUIModePreference).when(mSettings).findPreference(
- DARK_UI_MODE_PREFERENCE);
- mController = new DarkUIPreferenceController(mContext, DARK_UI_MODE_PREFERENCE);
- final String darkUIModeDescription = modeToDescription(mUiModeManager.getNightMode());
- darkUIModePreference.setSummary(mController.getSummary());
-
- assertThat(darkUIModePreference.getSummary()).isEqualTo(darkUIModeDescription);
- }
-
private String modeToDescription(int mode) {
String[] values = mContext.getResources().getStringArray(R.array.dark_ui_mode_entries);
switch (mode) {
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index 27c3e7d..58b1408 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -19,17 +19,14 @@
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static com.android.settings.applications.manageapplications.AppFilterRegistry
- .FILTER_APPS_ALL;
-import static com.android.settings.applications.manageapplications.ManageApplications
- .LIST_TYPE_MAIN;
-import static com.android.settings.applications.manageapplications.ManageApplications
- .LIST_TYPE_NOTIFICATION;
+import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
+import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -172,7 +169,7 @@
when(searchMenu.getActionView()).thenReturn(searchView);
when(mMenu.findItem(R.id.search_app_list_menu)).thenReturn(searchMenu);
when(mMenu.add(anyInt() /* groupId */, anyInt() /* itemId */, anyInt() /* order */,
- anyInt() /* titleRes */)).thenReturn(helpMenu);
+ anyInt() /* titleRes */)).thenReturn(helpMenu);
doReturn("Test").when(mFragment).getText(anyInt() /* resId */);
doNothing().when(mFragment).updateOptionsMenu();
@@ -182,9 +179,27 @@
}
@Test
+ public void onCreateOptionsMenu_hasExpandSearchFlag_shouldExpandSearchView() {
+ final SearchView searchView = mock(SearchView.class);
+ final MenuItem searchMenu = mock(MenuItem.class);
+ final MenuItem helpMenu = mock(MenuItem.class);
+ when(searchMenu.getActionView()).thenReturn(searchView);
+ when(mMenu.findItem(R.id.search_app_list_menu)).thenReturn(searchMenu);
+ when(mMenu.add(anyInt() /* groupId */, anyInt() /* itemId */, anyInt() /* order */,
+ anyInt() /* titleRes */)).thenReturn(helpMenu);
+ doReturn("Test").when(mFragment).getText(anyInt() /* resId */);
+ doNothing().when(mFragment).updateOptionsMenu();
+
+ mFragment.mExpandSearch = true;
+ mFragment.onCreateOptionsMenu(mMenu, mock(MenuInflater.class));
+
+ verify(searchMenu).expandActionView();
+ }
+
+ @Test
public void onQueryTextChange_shouldFilterSearchInApplicationsAdapter() {
final ManageApplications.ApplicationsAdapter adapter =
- mock(ManageApplications.ApplicationsAdapter.class);
+ mock(ManageApplications.ApplicationsAdapter.class);
final String query = "Test App";
ReflectionHelpers.setField(mFragment, "mApplications", adapter);
@@ -289,13 +304,13 @@
when(listContainer.getVisibility()).thenReturn(View.VISIBLE);
ReflectionHelpers.setField(mFragment, "mListContainer", listContainer);
ReflectionHelpers.setField(
- mFragment, "mFilterAdapter", mock(ManageApplications.FilterSpinnerAdapter.class));
+ mFragment, "mFilterAdapter", mock(ManageApplications.FilterSpinnerAdapter.class));
final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>();
appList.add(mock(ApplicationsState.AppEntry.class));
final ManageApplications.ApplicationsAdapter adapter =
- spy(new ManageApplications.ApplicationsAdapter(mState, mFragment,
- AppFilterRegistry.getInstance().get(FILTER_APPS_ALL),
- null /* savedInstanceState */));
+ spy(new ManageApplications.ApplicationsAdapter(mState, mFragment,
+ AppFilterRegistry.getInstance().get(FILTER_APPS_ALL),
+ null /* savedInstanceState */));
adapter.onRebuildComplete(appList);
@@ -365,7 +380,7 @@
ReflectionHelpers.setField(holder, "itemView", mock(View.class));
ManageApplications.ApplicationsAdapter adapter =
new ManageApplications.ApplicationsAdapter(mState,
- mFragment, mock(AppFilterItem.class),
+ mFragment, mock(AppFilterItem.class),
mock(Bundle.class));
final ArrayList<ApplicationsState.AppEntry> appList = new ArrayList<>();
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
@@ -399,8 +414,8 @@
@Test
public void applicationsAdapter_filterSearch_emptyQuery_shouldShowFullList() {
final ManageApplications.ApplicationsAdapter adapter =
- new ManageApplications.ApplicationsAdapter(
- mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
@@ -412,8 +427,8 @@
@Test
public void applicationsAdapter_filterSearch_noMatch_shouldShowEmptyList() {
final ManageApplications.ApplicationsAdapter adapter =
- new ManageApplications.ApplicationsAdapter(
- mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
@@ -425,8 +440,8 @@
@Test
public void applicationsAdapter_filterSearch_shouldShowMatchedItemsOnly() {
final ManageApplications.ApplicationsAdapter adapter =
- new ManageApplications.ApplicationsAdapter(
- mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
+ new ManageApplications.ApplicationsAdapter(
+ mState, mFragment, mock(AppFilterItem.class), Bundle.EMPTY);
final String[] appNames = {"Apricot", "Banana", "Cantaloupe", "Fig", "Mango"};
ReflectionHelpers.setField(adapter, "mOriginalEntries", getTestAppList(appNames));
diff --git a/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java
index 1d8d028..669aabb 100644
--- a/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/backup/BackupInactivePreferenceControllerTest.java
@@ -31,8 +31,10 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import static com.android.settings.backup.UserBackupSettingsActivityTest.ShadowBackupSettingsHelper;
+
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowPrivacySettingsUtils.class})
+@Config(shadows = {ShadowPrivacySettingsUtils.class, ShadowBackupSettingsHelper.class})
public class BackupInactivePreferenceControllerTest {
private Context mContext;
private BackupInactivePreferenceController mController;
@@ -48,18 +50,32 @@
@After
public void tearDown() {
ShadowPrivacySettingsUtils.reset();
+ ShadowBackupSettingsHelper.reset();
}
@Test
- public void getAvailabilityStatus_isnotInvisibleKey_shouldBeAvailable() {
+ public void getAvailabilityStatus_isnotInvisibleKey_showBackup_shouldBeAvailable() {
ShadowPrivacySettingsUtils.setIsInvisibleKey(false);
+ ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
+
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
+ public void getAvailabilityStatus_isnotInvisibleKey_dontShowBackup_shouldBeUnsearchable() {
+ ShadowPrivacySettingsUtils.setIsInvisibleKey(false);
+ ShadowBackupSettingsHelper.showBackupSettingsForUser = false;
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE_UNSEARCHABLE);
+ }
+
+ @Test
public void getAvailabilityStatus_isInvisibleKey_shouldBeDisabledUnsupported() {
ShadowPrivacySettingsUtils.setIsInvisibleKey(true);
+ ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
+
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
}
diff --git a/tests/robotests/src/com/android/settings/backup/UserBackupSettingsActivityTest.java b/tests/robotests/src/com/android/settings/backup/UserBackupSettingsActivityTest.java
index 19a6051..9c5a11a 100644
--- a/tests/robotests/src/com/android/settings/backup/UserBackupSettingsActivityTest.java
+++ b/tests/robotests/src/com/android/settings/backup/UserBackupSettingsActivityTest.java
@@ -29,7 +29,6 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.UserHandle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -53,8 +52,7 @@
import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {UserBackupSettingsActivityTest.ShadowBackupSettingsHelper.class,
- UserBackupSettingsActivityTest.ShadowUserHandle.class})
+@Config(shadows = {UserBackupSettingsActivityTest.ShadowBackupSettingsHelper.class})
public class UserBackupSettingsActivityTest {
private ActivityController<UserBackupSettingsActivity> mActivityController;
private UserBackupSettingsActivity mActivity;
@@ -85,7 +83,7 @@
@After
public void resetShadows() {
- ShadowUserHandle.reset();
+ ShadowBackupSettingsHelper.reset();
}
@Test
@@ -125,7 +123,9 @@
}
@Test
- public void getNonIndexableKeys_SystemUser() {
+ public void getNonIndexableKeys_whenShowBackupSettings() {
+ ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
+
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(
mApplication, true)).isNotEmpty();
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
@@ -133,17 +133,24 @@
}
@Test
- public void getNonIndexableKeys_NonSystemUser() {
- ShadowUserHandle.setUid(1); // Non-SYSTEM user.
+ public void getNonIndexableKeys_whenDontShowBackupSettings() {
+ ShadowBackupSettingsHelper.showBackupSettingsForUser = false;
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(
mApplication, true)).isNotEmpty();
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
- mApplication)).isEmpty();
+ mApplication)).contains("Backup");
}
@Implements(BackupSettingsHelper.class)
public static class ShadowBackupSettingsHelper {
+ static boolean showBackupSettingsForUser = true;
+
+ @Implementation
+ public boolean showBackupSettingsForUser() {
+ return showBackupSettingsForUser;
+ }
+
@Implementation
protected Intent getIntentForBackupSettings() {
return mIntent;
@@ -153,24 +160,10 @@
protected boolean isBackupProvidedByManufacturer() {
return mIsBackupProvidedByOEM;
}
- }
-
- @Implements(UserHandle.class)
- public static class ShadowUserHandle {
- private static int sUid = 0; // SYSTEM by default
-
- public static void setUid(int uid) {
- sUid = uid;
- }
-
- @Implementation
- protected static int myUserId() {
- return sUid;
- }
@Resetter
public static void reset() {
- sUid = 0;
+ showBackupSettingsForUser = true;
}
}
}
diff --git a/tests/robotests/src/com/android/settings/core/SettingsSliderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/SettingsSliderPreferenceControllerTest.java
index ba9cd5d..a04ec37 100644
--- a/tests/robotests/src/com/android/settings/core/SettingsSliderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/core/SettingsSliderPreferenceControllerTest.java
@@ -41,7 +41,8 @@
"key");
mPreference.setContinuousUpdates(true);
- mPreference.setMax(mSliderController.getMaxSteps());
+ mPreference.setMin(mSliderController.getMin());
+ mPreference.setMax(mSliderController.getMax());
}
@Test
@@ -89,11 +90,16 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
return MAX_STEPS;
}
@Override
+ public int getMin() {
+ return 0;
+ }
+
+ @Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
diff --git a/tests/robotests/src/com/android/settings/core/SliderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/SliderPreferenceControllerTest.java
index dbe7a14..ab0d9f5 100644
--- a/tests/robotests/src/com/android/settings/core/SliderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/core/SliderPreferenceControllerTest.java
@@ -88,11 +88,16 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
return MAX_STEPS;
}
@Override
+ public int getMin() {
+ return 0;
+ }
+
+ @Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index 7d042ce..9aa1c6f 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -18,22 +18,32 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
+import android.app.Activity;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
import android.widget.Spinner;
+import androidx.fragment.app.FragmentActivity;
+import androidx.preference.PreferenceManager;
+
+import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.AppItem;
import com.android.settingslib.NetworkPolicyEditor;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
@@ -45,15 +55,14 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
-import androidx.fragment.app.FragmentActivity;
-import androidx.preference.PreferenceManager;
-
@RunWith(RobolectricTestRunner.class)
public class DataUsageListTest {
@@ -61,18 +70,21 @@
private CellDataPreference.DataStateListener mListener;
@Mock
private TemplatePreference.NetworkServices mNetworkServices;
- @Mock
- private Context mContext;
+
+ private Activity mActivity;
private DataUsageList mDataUsageList;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
+ final ActivityController<Activity> mActivityController =
+ Robolectric.buildActivity(Activity.class);
+ mActivity = spy(mActivityController.get());
mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class);
mDataUsageList = spy(DataUsageList.class);
- doReturn(mContext).when(mDataUsageList).getContext();
+ doReturn(mActivity).when(mDataUsageList).getContext();
ReflectionHelpers.setField(mDataUsageList, "mDataStateListener", mListener);
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
}
@@ -86,11 +98,11 @@
mDataUsageList.onResume();
- verify(mListener).setListener(true, mDataUsageList.mSubId, mContext);
+ verify(mListener).setListener(true, mDataUsageList.mSubId, mActivity);
mDataUsageList.onPause();
- verify(mListener).setListener(false, mDataUsageList.mSubId, mContext);
+ verify(mListener).setListener(false, mDataUsageList.mSubId, mActivity);
}
@Test
@@ -140,7 +152,7 @@
final List<NetworkCycleChartData> data = new ArrayList<>();
final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
builder.setStartTime(startTime)
- .setEndTime(endTime);
+ .setEndTime(endTime);
data.add(builder.build());
ReflectionHelpers.setField(mDataUsageList, "mCycleData", data);
final Spinner spinner = mock(Spinner.class);
@@ -150,14 +162,58 @@
mDataUsageList.startAppDataUsage(new AppItem());
- verify(mContext).startActivity(intent.capture());
+ verify(mActivity).startActivity(intent.capture());
final Bundle arguments =
- intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+ intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(endTime);
final ArrayList<Long> cycles =
- (ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
+ (ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
assertThat(cycles).hasSize(2);
assertThat(cycles.get(0)).isEqualTo(endTime);
assertThat(cycles.get(1)).isEqualTo(startTime);
}
+
+ @Test
+ public void onViewCreated_shouldHideCycleSpinner() {
+ final View view = new View(mActivity);
+ final View header = getHeader();
+ final Spinner spinner = getSpinner(header);
+ spinner.setVisibility(View.VISIBLE);
+ doReturn(header).when(mDataUsageList).setPinnedHeaderView(anyInt());
+ doReturn(view).when(mDataUsageList).getView();
+
+ mDataUsageList.onViewCreated(view, null);
+
+ assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
+ final LoadingViewController loadingViewController = mock(LoadingViewController.class);
+ mDataUsageList.mLoadingViewController = loadingViewController;
+ final Spinner spinner = getSpinner(getHeader());
+ spinner.setVisibility(View.INVISIBLE);
+ mDataUsageList.mCycleSpinner = spinner;
+ assertThat(spinner.getVisibility()).isEqualTo(View.INVISIBLE);
+ doNothing().when(mDataUsageList).updatePolicy();
+
+ mDataUsageList.mNetworkCycleDataCallbacks.onLoadFinished(null, null);
+
+ assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ private View getHeader() {
+ final View rootView = LayoutInflater.from(mActivity)
+ .inflate(R.layout.preference_list_fragment, null, false);
+ final FrameLayout pinnedHeader = rootView.findViewById(R.id.pinned_header);
+ final View header = mActivity.getLayoutInflater()
+ .inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
+
+ return header;
+ }
+
+ private Spinner getSpinner(View header) {
+ final Spinner spinner = header.findViewById(R.id.filter_spinner);
+ return spinner;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
index d426e7a..9adb1ad 100644
--- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
@@ -20,15 +20,21 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import com.android.settings.R;
+import com.android.settingslib.RestrictedPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -42,6 +48,9 @@
private AdaptiveSleepPreferenceController mController;
private ContentResolver mContentResolver;
+ @Mock
+ private PackageManager mPackageManager;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -49,6 +58,10 @@
mContext = RuntimeEnvironment.application;
mContentResolver = mContext.getContentResolver();
mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY);
+
+
+ when(mPackageManager.checkPermission(any(), any())).thenReturn(
+ PackageManager.PERMISSION_GRANTED);
}
@Test
@@ -114,4 +127,24 @@
new AdaptiveSleepPreferenceController(mContext, "any_key");
assertThat(controller.isSliceable()).isTrue();
}
+
+ @Test
+ public void isChecked_returnsFalseWhenNotSufficientPermissions() {
+ when(mPackageManager.checkPermission(any(), any())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ mController.setChecked(true);
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isEnabled_returnsFalseWhenNotSufficientPermissions() {
+ when(mPackageManager.checkPermission(any(), any())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ mController.setChecked(true);
+ final RestrictedPreference mPreference = new RestrictedPreference(mContext);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/display/DarkUIInfoDialogFragmentTest.java b/tests/robotests/src/com/android/settings/display/DarkUIInfoDialogFragmentTest.java
new file mode 100644
index 0000000..7a8bded
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/DarkUIInfoDialogFragmentTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class DarkUIInfoDialogFragmentTest {
+ private DarkUIInfoDialogFragment mFragment;
+ @Mock
+ private DialogInterface dialog;
+
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mFragment = spy(new DarkUIInfoDialogFragment());
+ }
+
+ @Test
+ public void dialogDismissedOnConfirmation() {
+ doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
+ SharedPreferences prefs = RuntimeEnvironment.application.getSharedPreferences(
+ DarkUIPreferenceController.DARK_MODE_PREFS,
+ Context.MODE_PRIVATE);
+ assertThat(prefs.getBoolean(DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN, false))
+ .isFalse();
+ mFragment.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
+ verify(dialog, times(1)).dismiss();
+ assertThat(prefs.getBoolean(DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN, false))
+ .isTrue();
+
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/DarkUISettingsRadioButtonsControllerTest.java b/tests/robotests/src/com/android/settings/display/DarkUISettingsRadioButtonsControllerTest.java
deleted file mode 100644
index 76142a4..0000000
--- a/tests/robotests/src/com/android/settings/display/DarkUISettingsRadioButtonsControllerTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.android.settings.display;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
-
-import android.app.UiModeManager;
-import android.content.Context;
-import androidx.preference.Preference;
-import com.android.settings.R;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class DarkUISettingsRadioButtonsControllerTest {
-
- @Mock
- private UiModeManager mUiModeManager;
- @Mock
- private Preference mFooter;
- private Context mContext;
- private DarkUISettingsRadioButtonsController mController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = new DarkUISettingsRadioButtonsController(mContext, mFooter);
- mController.mManager = mUiModeManager;
- }
-
- @Test
- public void footerUpdatesCorrectly() {
- doReturn(UiModeManager.MODE_NIGHT_YES).when(mUiModeManager).getNightMode();
- mController.updateFooter();
- verify(mFooter).setSummary(eq(R.string.dark_ui_settings_dark_summary));
-
- doReturn(UiModeManager.MODE_NIGHT_NO).when(mUiModeManager).getNightMode();
- mController.updateFooter();
- verify(mFooter).setSummary(eq(R.string.dark_ui_settings_light_summary));
- }
-
- public int getCurrentMode() {
- final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
- return uiModeManager.getNightMode();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java
index 85eeacc..ccb2bf6 100644
--- a/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/gestures/PreventRingingSwitchPreferenceControllerTest.java
@@ -16,6 +16,10 @@
package com.android.settings.gestures;
+import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
+import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
+import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -43,6 +47,9 @@
@RunWith(RobolectricTestRunner.class)
public class PreventRingingSwitchPreferenceControllerTest {
+
+ private static final int UNKNOWN = -1;
+
private Context mContext;
private Resources mResources;
private PreventRingingSwitchPreferenceController mController;
@@ -76,35 +83,88 @@
}
@Test
- public void testOn_updateState_hushOff() {
+ public void updateState_hushOff_uncheck() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
- Settings.Secure.VOLUME_HUSH_OFF);
+ VOLUME_HUSH_OFF);
+
mController.updateState(mPreference);
+
verify(mController.mSwitch, times(1)).setChecked(false);
}
@Test
- public void testOn_updateState_hushVibrate() {
+ public void updateState_hushVibrate_setChecked() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
- Settings.Secure.VOLUME_HUSH_VIBRATE);
+ VOLUME_HUSH_VIBRATE);
+
mController.updateState(mPreference);
+
verify(mController.mSwitch, times(1)).setChecked(true);
}
@Test
- public void testOn_updateState_hushMute() {
+ public void updateState_hushMute_setChecked() {
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
- Settings.Secure.VOLUME_HUSH_MUTE);
+ VOLUME_HUSH_MUTE);
+
mController.updateState(mPreference);
+
verify(mController.mSwitch, times(1)).setChecked(true);
}
@Test
+ public void onSwitchChanged_wasHushOff_checked_returnHushVibrate() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ VOLUME_HUSH_OFF);
+
+ mController.onSwitchChanged(null, true);
+
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_VIBRATE);
+ }
+
+ @Test
+ public void onSwitchChanged_wasHushMute_unchecked_returnHushOff() {
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ VOLUME_HUSH_MUTE);
+
+ mController.onSwitchChanged(null, false);
+
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_OFF);
+ }
+
+ @Test
+ public void onSwitchChanged_wasHushMute_checked_returnHushMute() {
+ // this is the case for the page open
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ VOLUME_HUSH_MUTE);
+
+ mController.onSwitchChanged(null, true);
+
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_MUTE);
+ }
+
+ @Test
+ public void onSwitchChanged_wasHushVibrate_checked_returnHushVibrate() {
+ // this is the case for the page open
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
+ VOLUME_HUSH_VIBRATE);
+
+ mController.onSwitchChanged(null, true);
+
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_VIBRATE);
+ }
+
+ @Test
public void testPreferenceClickListenerAttached() {
PreferenceScreen preferenceScreen = mock(PreferenceScreen.class);
LayoutPreference mLayoutPreference = mock(LayoutPreference.class);
when(preferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
mLayoutPreference);
+
mController.displayPreference(preferenceScreen);
verify(mLayoutPreference, times(1))
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
new file mode 100644
index 0000000..e380636
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.homepage.contextualcards;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS;
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES;
+import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI;
+import static com.android.settings.slices.CustomSliceRegistry.FLASHLIGHT_SLICE_URI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.ArraySet;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.applications.AppInfoBase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Set;
+
+@RunWith(RobolectricTestRunner.class)
+public class ContextualCardFeatureProviderImplTest {
+
+ private Context mContext;
+ private ContextualCardFeatureProviderImpl mImpl;
+ private SharedPreferences mSharedPreferences;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mImpl = new ContextualCardFeatureProviderImpl(mContext);
+ mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE);
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @After
+ public void tearDown() {
+ removeInteractedPackageFromSharedPreference();
+ }
+
+ @Test
+ public void logNotificationPackage_isContextualNotificationChannel_shouldLogPackage() {
+ final String packageName = "com.android.test.app";
+ final Slice slice = buildSlice(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, packageName);
+
+ mImpl.logNotificationPackage(slice);
+
+ final Set<String> interactedPackages = mSharedPreferences.getStringSet(
+ PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+ assertThat(interactedPackages.contains(packageName)).isTrue();
+ }
+
+ @Test
+ public void logNotificationPackage_isNotContextualNotificationChannel_shouldNotLogPackage() {
+ final String packageName = "com.android.test.app";
+ final Slice slice = buildSlice(FLASHLIGHT_SLICE_URI, packageName);
+
+ mImpl.logNotificationPackage(slice);
+
+ final Set<String> interactedPackages = mSharedPreferences.getStringSet(
+ PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+ assertThat(interactedPackages.contains(packageName)).isFalse();
+ }
+
+ private Slice buildSlice(Uri sliceUri, String packageName) {
+ final Bundle args = new Bundle();
+ args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName);
+ final Intent intent = new Intent("action");
+ intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
+
+ final PendingIntent pendingIntent = spy(
+ PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */));
+ doReturn(intent).when(pendingIntent).getIntent();
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.empty_icon);
+ final SliceAction action = SliceAction.createDeeplink(pendingIntent, icon,
+ ListBuilder.SMALL_IMAGE, "title");
+
+ return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
+ .addRow(new ListBuilder.RowBuilder()
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setTitle("title")
+ .setPrimaryAction(action))
+ .build();
+ }
+
+ private void removeInteractedPackageFromSharedPreference() {
+ if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) {
+ mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply();
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
index 1027cf1..dcfba42 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java
@@ -18,7 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
+import android.net.Uri;
import androidx.slice.Slice;
import androidx.slice.SliceMetadata;
@@ -26,11 +30,13 @@
import androidx.slice.widget.SliceLiveData;
import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
+import com.android.settings.slices.SliceBackgroundWorker;
import org.junit.After;
import org.junit.Before;
@@ -48,6 +54,10 @@
import java.util.List;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+})
public class BatteryFixSliceTest {
private Context mContext;
@@ -66,13 +76,11 @@
@After
public void tearDown() {
ShadowBatteryTipLoader.reset();
+ ShadowSliceBackgroundWorker.reset();
+ ShadowEarlyWarningTip.reset();
}
@Test
- @Config(shadows = {
- ShadowBatteryStatsHelperLoader.class,
- ShadowBatteryTipLoader.class
- })
public void updateBatteryTipAvailabilityCache_hasImportantTip_shouldReturnTrue() {
final List<BatteryTip> tips = new ArrayList<>();
tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false, ""));
@@ -85,10 +93,6 @@
}
@Test
- @Config(shadows = {
- ShadowBatteryStatsHelperLoader.class,
- ShadowBatteryTipLoader.class
- })
public void getSlice_unimportantSlice_shouldSkip() {
final List<BatteryTip> tips = new ArrayList<>();
tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false, ""));
@@ -101,6 +105,28 @@
assertThat(SliceMetadata.from(mContext, slice).isErrorSlice()).isTrue();
}
+ @Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowEarlyWarningTip.class,
+ BatteryFixSliceTest.ShadowSliceBackgroundWorker.class
+ })
+ public void getSlice_hasImportantTip_shouldTintIcon() {
+ final List<BatteryTip> tips = new ArrayList<>();
+ tips.add(new EarlyWarningTip(BatteryTip.StateType.NEW, false));
+ // Create fake cache data
+ ShadowBatteryTipLoader.setBatteryTips(tips);
+ BatteryFixSlice.updateBatteryTipAvailabilityCache(mContext);
+ // Create fake background worker data
+ BatteryFixSlice.BatteryTipWorker batteryTipWorker = mock(
+ BatteryFixSlice.BatteryTipWorker.class);
+ when(batteryTipWorker.getResults()).thenReturn(tips);
+ ShadowSliceBackgroundWorker.setBatteryTipWorkerWorker(batteryTipWorker);
+
+ final Slice slice = mSlice.getSlice();
+
+ assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue();
+ }
+
@Implements(BatteryStatsHelperLoader.class)
public static class ShadowBatteryStatsHelperLoader {
@@ -129,4 +155,45 @@
sBatteryTips = tips;
}
}
+
+ @Implements(SliceBackgroundWorker.class)
+ public static class ShadowSliceBackgroundWorker {
+
+ private static BatteryFixSlice.BatteryTipWorker sBatteryTipWorkerWorker;
+
+ @Resetter
+ public static void reset() {
+ sBatteryTipWorkerWorker = null;
+ }
+
+ @Implementation
+ protected static <T extends SliceBackgroundWorker> T getInstance(Uri uri) {
+ return (T) sBatteryTipWorkerWorker;
+ }
+
+ public static void setBatteryTipWorkerWorker(BatteryFixSlice.BatteryTipWorker worker) {
+ sBatteryTipWorkerWorker = worker;
+ }
+ }
+
+ @Implements(EarlyWarningTip.class)
+ public static class ShadowEarlyWarningTip {
+
+ private static boolean mIsGetIconTintColorIdCalled;
+
+ @Resetter
+ public static void reset() {
+ mIsGetIconTintColorIdCalled = false;
+ }
+
+ @Implementation
+ protected int getIconTintColorId() {
+ mIsGetIconTintColorIdCalled = true;
+ return R.color.battery_bad_color_light;
+ }
+
+ public static boolean isIconTintColorIdCalled() {
+ return mIsGetIconTintColorIdCalled;
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java
index f2b87be..8541a30 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualNotificationChannelSliceTest.java
@@ -16,30 +16,49 @@
package com.android.settings.homepage.contextualcards.slices;
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS;
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.content.SharedPreferences;
import android.net.Uri;
+import android.util.ArraySet;
import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.Set;
+
@RunWith(RobolectricTestRunner.class)
public class ContextualNotificationChannelSliceTest {
+ private static final String PACKAGE_NAME = "package_name";
+
private Context mContext;
private ContextualNotificationChannelSlice mNotificationChannelSlice;
+ private SharedPreferences mSharedPreferences;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mNotificationChannelSlice = new ContextualNotificationChannelSlice(mContext);
+ mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() {
+ removeInteractedPackageFromSharedPreference();
}
@Test
@@ -55,4 +74,34 @@
assertThat(subTitle).isEqualTo(mContext.getText(R.string.recently_installed_app));
}
+
+ @Test
+ public void isUserInteracted_hasInteractedPackage_shouldBeTrue() {
+ addInteractedPackageToSharedPreference();
+
+ final boolean isInteracted = mNotificationChannelSlice.isUserInteracted(PACKAGE_NAME);
+
+ assertThat(isInteracted).isTrue();
+ }
+
+ @Test
+ public void isUserInteracted_noInteractedPackage_shouldBeFalse() {
+ final boolean isInteracted = mNotificationChannelSlice.isUserInteracted(PACKAGE_NAME);
+
+ assertThat(isInteracted).isFalse();
+ }
+
+ private void addInteractedPackageToSharedPreference() {
+ final Set<String> interactedPackages = new ArraySet<>();
+ interactedPackages.add(PACKAGE_NAME);
+
+ mSharedPreferences.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES,
+ interactedPackages).apply();
+ }
+
+ private void removeInteractedPackageFromSharedPreference() {
+ if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) {
+ mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply();
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java
index 12513f6..81f5797 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelSliceTest.java
@@ -26,7 +26,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.NotificationChannel;
@@ -299,6 +298,21 @@
assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app));
}
+ @Test
+ @Config(shadows = ShadowRestrictedLockUtilsInternal.class)
+ public void getSlice_isInteractedPackage_shouldHaveNoSuggestedAppTitle() {
+ addMockPackageToPackageManager(true /* isRecentlyInstalled */,
+ ApplicationInfo.FLAG_INSTALLED);
+ mockNotificationBackend(CHANNEL_COUNT, NOTIFICATION_COUNT, false /* banned */,
+ false /* isChannelBlocked */);
+ doReturn(true).when(mNotificationChannelSlice).isUserInteracted(any(String.class));
+
+ final Slice slice = mNotificationChannelSlice.getSlice();
+
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+ assertThat(metadata.getTitle()).isEqualTo(mContext.getString(R.string.no_suggested_app));
+ }
+
private void addMockPackageToPackageManager(boolean isRecentlyInstalled, int flags) {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.name = APP_LABEL;
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java
new file mode 100644
index 0000000..6ac8b70
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/NotificationChannelWorkerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREFS;
+import static com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice.PREF_KEY_INTERACTED_PACKAGES;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.net.Uri;
+import android.util.ArraySet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowPackageManager;
+
+import java.util.Set;
+
+@RunWith(RobolectricTestRunner.class)
+public class NotificationChannelWorkerTest {
+ private static final Uri URI = Uri.parse("content://com.android.settings.slices/test");
+ private static final String PACKAGE_NAME = "com.test.notification.channel.slice";
+
+ private Context mContext;
+ private NotificationChannelWorker mNotificationChannelWorker;
+ private ShadowPackageManager mPackageManager;
+ private SharedPreferences mSharedPreferences;
+
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mNotificationChannelWorker = new NotificationChannelWorker(mContext, URI);
+
+ // Shadow PackageManager to add mock package.
+ mPackageManager = shadowOf(mContext.getPackageManager());
+
+ mSharedPreferences = mContext.getSharedPreferences(PREFS, MODE_PRIVATE);
+ addInteractedPackageToSharedPreference();
+ }
+
+ @After
+ public void tearDown() {
+ mPackageManager.removePackage(PACKAGE_NAME);
+ removeInteractedPackageFromSharedPreference();
+ }
+
+ @Test
+ public void onSliceUnpinned_interactedPackageIsUninstalled_shouldRemovePackage() {
+ mNotificationChannelWorker.onSliceUnpinned();
+
+ final Set<String> interactedPackages = mSharedPreferences.getStringSet(
+ PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+ assertThat(interactedPackages.contains(PACKAGE_NAME)).isFalse();
+ }
+
+ @Test
+ public void onSliceUnpinned_interactedPackageIsInstalled_shouldKeepPackage() {
+ mockInteractedPackageAsInstalled();
+
+ mNotificationChannelWorker.onSliceUnpinned();
+
+ final Set<String> interactedPackages = mSharedPreferences.getStringSet(
+ PREF_KEY_INTERACTED_PACKAGES, new ArraySet<>());
+ assertThat(interactedPackages.contains(PACKAGE_NAME)).isTrue();
+ }
+
+ private void mockInteractedPackageAsInstalled() {
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = PACKAGE_NAME;
+ mPackageManager.addPackage(packageInfo);
+ }
+
+ private void addInteractedPackageToSharedPreference() {
+ final Set<String> interactedPackages = new ArraySet<>();
+ interactedPackages.add(PACKAGE_NAME);
+
+ mSharedPreferences.edit().putStringSet(PREF_KEY_INTERACTED_PACKAGES,
+ interactedPackages).apply();
+ }
+
+ private void removeInteractedPackageFromSharedPreference() {
+ if (mSharedPreferences.contains(PREF_KEY_INTERACTED_PACKAGES)) {
+ mSharedPreferences.edit().remove(PREF_KEY_INTERACTED_PACKAGES).apply();
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 8bcf8b6..b8ba63c 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.os.UserManager;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
@@ -65,6 +66,8 @@
private EuiccManager mEuiccManager;
@Mock
private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private UserManager mUserManager;
private AddPreference mPreference;
private Context mContext;
@@ -76,6 +79,7 @@
mContext = spy(Robolectric.setupActivity(Activity.class));
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("");
when(mEuiccManager.isEnabled()).thenReturn(true);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.EUICC_PROVISIONED, 1);
@@ -97,10 +101,23 @@
final ConnectivityManager cm = mock(ConnectivityManager.class);
when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
+ when(mUserManager.isAdminUser()).thenReturn(true);
+
assertThat(mController.isAvailable()).isFalse();
}
@Test
+ public void isAvailable_secondaryUser_notAvailable() {
+ final ConnectivityManager cm = mock(ConnectivityManager.class);
+ when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
+ when(mUserManager.isAdminUser()).thenReturn(false);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+
+ @Test
public void getSummary_noSubscriptions_correctSummaryAndClickHandler() {
mController.displayPreference(mPreferenceScreen);
mController.onResume();
@@ -283,6 +300,18 @@
}
@Test
+ public void onResume_noSubscriptionEsimDisabled_isDisabled() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
+ when(mEuiccManager.isEnabled()).thenReturn(false);
+ mController.displayPreference(mPreferenceScreen);
+
+ mController.onResume();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOn_isDisabled() {
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
diff --git a/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
index 3126cdf..de00189 100644
--- a/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/AdjustVolumeRestrictedPreferenceControllerTest.java
@@ -121,7 +121,12 @@
}
@Override
- public int getMaxSteps() {
+ public int getMax() {
+ return 0;
+ }
+
+ @Override
+ public int getMin() {
return 0;
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/RemoteVolumePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RemoteVolumePreferenceControllerTest.java
index 1e68de5..175599a 100644
--- a/tests/robotests/src/com/android/settings/notification/RemoteVolumePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RemoteVolumePreferenceControllerTest.java
@@ -29,10 +29,12 @@
import android.media.session.MediaSessionManager;
import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -50,9 +52,9 @@
private MediaSessionManager mMediaSessionManager;
@Mock
private MediaController mMediaController;
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ISessionController mStub;
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ISessionController mStub2;
private MediaSession.Token mToken;
private MediaSession.Token mToken2;
@@ -78,22 +80,30 @@
mPlaybackInfo = new MediaController.PlaybackInfo(
MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, 0, MAX_POS, CURRENT_POS, null);
when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getSessionToken()).thenReturn(mToken);
}
@Test
- public void isAvailable_containRemoteMedia_returnTrue() {
+ public void getActiveRemoteToken_containRemoteMedia_returnToken() {
when(mMediaController.getPlaybackInfo()).thenReturn(
new MediaController.PlaybackInfo(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
0, 0, 0, null));
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getActiveRemoteToken(mContext)).isEqualTo(mToken);
}
@Test
- public void isAvailable_noRemoteMedia_returnFalse() {
+ public void getActiveRemoteToken_noRemoteMedia_returnNull() {
when(mMediaController.getPlaybackInfo()).thenReturn(
new MediaController.PlaybackInfo(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
0, 0, 0, null));
- assertThat(mController.isAvailable()).isFalse();
+ assertThat(mController.getActiveRemoteToken(mContext)).isNull();
+ }
+
+ @Test
+ public void isAvailable_returnAvailableUnsearchable() {
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE_UNSEARCHABLE);
}
@Test
@@ -122,17 +132,31 @@
}
@Test
- public void getMaxSteps_controllerNull_returnZero() {
+ public void getMinValue_controllerNull_returnZero() {
mController.mMediaController = null;
- assertThat(mController.getMaxSteps()).isEqualTo(0);
+ assertThat(mController.getMin()).isEqualTo(0);
}
@Test
- public void getMaxSteps_controllerExists_returnValue() {
+ public void getMinValue_controllerExists_returnValue() {
mController.mMediaController = mMediaController;
- assertThat(mController.getMaxSteps()).isEqualTo(MAX_POS);
+ assertThat(mController.getMin()).isEqualTo(0);
+ }
+
+ @Test
+ public void getMaxValue_controllerNull_returnZero() {
+ mController.mMediaController = null;
+
+ assertThat(mController.getMax()).isEqualTo(0);
+ }
+
+ @Test
+ public void getMaxValue_controllerExists_returnValue() {
+ mController.mMediaController = mMediaController;
+
+ assertThat(mController.getMax()).isEqualTo(MAX_POS);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
index a9e74b7..2d54c38 100644
--- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceControllerTest.java
@@ -106,8 +106,10 @@
public void sliderMethods_handleNullPreference() {
when(mHelper.getStreamVolume(mController.getAudioStream())).thenReturn(4);
when(mHelper.getMaxVolume(mController.getAudioStream())).thenReturn(10);
+ when(mHelper.getMinVolume(mController.getAudioStream())).thenReturn(1);
- assertThat(mController.getMaxSteps()).isEqualTo(10);
+ assertThat(mController.getMax()).isEqualTo(10);
+ assertThat(mController.getMin()).isEqualTo(1);
assertThat(mController.getSliderPosition()).isEqualTo(4);
mController.setSliderPosition(9);
@@ -123,11 +125,19 @@
}
@Test
- public void getMaxSteps_passesAlongValue() {
+ public void getMaxValue_passesAlongValue() {
when(mPreference.getMax()).thenReturn(6);
mController.displayPreference(mScreen);
- assertThat(mController.getMaxSteps()).isEqualTo(6);
+ assertThat(mController.getMax()).isEqualTo(6);
+ }
+
+ @Test
+ public void getMinValue_passesAlongValue() {
+ when(mPreference.getMin()).thenReturn(1);
+ mController.displayPreference(mScreen);
+
+ assertThat(mController.getMin()).isEqualTo(1);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceControllerTest.java
deleted file mode 100644
index a08a4d7..0000000
--- a/tests/robotests/src/com/android/settings/notification/ZenModeSoundSettingsPreferenceControllerTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 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.notification;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class ZenModeSoundSettingsPreferenceControllerTest {
-
- private Context mContext;
- private ZenModeSoundSettingsPreferenceController mController;
- private static final String KEY_ZEN_MODE = "zen_mode";
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = new ZenModeSoundSettingsPreferenceController(mContext, KEY_ZEN_MODE);
- }
-
- @Test
- public void getAvailabilityStatus_available() {
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
index be8d8bc..fd2e806 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
@@ -26,6 +26,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -81,12 +82,16 @@
}
@Test
- public void onCreateView_adapterGetsDataset() {
+ public void onCreateView_countdownLatch_setup() {
mPanelFragment.onCreateView(LayoutInflater.from(mContext),
new LinearLayout(mContext), null);
- PanelSlicesAdapter adapter = mPanelFragment.mAdapter;
+ PanelSlicesLoaderCountdownLatch countdownLatch =
+ mPanelFragment.mPanelSlicesLoaderCountdownLatch;
+ for (Uri sliecUri: mFakePanelContent.getSlices()) {
+ countdownLatch.markSliceLoaded(sliecUri);
+ }
- assertThat(adapter.getData()).containsAllIn(mFakePanelContent.getSlices());
+ assertThat(countdownLatch.isPanelReadyToLoad()).isTrue();
}
@Test
@@ -100,6 +105,16 @@
}
@Test
+ public void onDestroy_logCloseEvent() {
+ mPanelFragment.onDestroy();
+ verify(mFakeFeatureFactory.metricsFeatureProvider).action(
+ 0,
+ SettingsEnums.PAGE_VISIBLE,
+ mFakePanelContent.getMetricsCategory(),
+ any(String.class),
+ 0); }
+
+ @Test
public void panelSeeMoreClick_logsCloseEvent() {
final View.OnClickListener listener = mPanelFragment.getSeeMoreListener();
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
index 9795b55..14a7db9 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
@@ -23,41 +23,53 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
-import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.content.Intent;
import android.net.Uri;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+
import com.android.settings.R;
+import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-
import org.junit.Test;
-
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class PanelSlicesAdapterTest {
+ private static final Uri DATA_URI = CustomSliceRegistry.DATA_USAGE_SLICE_URI;
+
private Context mContext;
private PanelFragment mPanelFragment;
- private FakePanelContent mFakePanelContent;
- private FakeFeatureFactory mFakeFeatureFactory;
private PanelFeatureProvider mPanelFeatureProvider;
+ private FakeFeatureFactory mFakeFeatureFactory;
+ private FakePanelContent mFakePanelContent;
+ private List<LiveData<Slice>> mData = new ArrayList<>();
+
+ @Mock
+ private LiveData<Slice> mLiveData;
+
+ private Slice mSlice;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
@@ -76,12 +88,22 @@
.get()
.getSupportFragmentManager()
.findFragmentById(R.id.main_content));
+
+ }
+
+ private void constructTestLiveData(Uri uri) {
+ // Create a slice to return for the LiveData
+ mSlice = spy(new Slice());
+ doReturn(uri).when(mSlice).getUri();
+ when(mLiveData.getValue()).thenReturn(mSlice);
+ mData.add(mLiveData);
}
@Test
public void onCreateViewHolder_returnsSliceRowViewHolder() {
+ constructTestLiveData(DATA_URI);
final PanelSlicesAdapter adapter =
- new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
+ new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
final ViewGroup view = new FrameLayout(mContext);
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
adapter.onCreateViewHolder(view, 0);
@@ -90,23 +112,10 @@
}
@Test
- public void onBindViewHolder_bindsSlice() {
- final PanelSlicesAdapter adapter =
- new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
- final int position = 0;
- final ViewGroup view = new FrameLayout(mContext);
- final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
- adapter.onCreateViewHolder(view, 0 /* view type*/);
-
- adapter.onBindViewHolder(viewHolder, position);
-
- assertThat(viewHolder.sliceLiveData).isNotNull();
- }
-
- @Test
public void nonMediaOutputIndicatorSlice_shouldAllowDividerAboveAndBelow() {
+ constructTestLiveData(DATA_URI);
final PanelSlicesAdapter adapter =
- new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
+ new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
final int position = 0;
final ViewGroup view = new FrameLayout(mContext);
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
@@ -120,32 +129,10 @@
@Test
public void mediaOutputIndicatorSlice_shouldNotAllowDividerAbove() {
- PanelContent mediaOutputIndicatorSlicePanelContent = new PanelContent() {
- @Override
- public CharSequence getTitle() {
- return "title";
- }
-
- @Override
- public List<Uri> getSlices() {
- return Arrays.asList(
- MEDIA_OUTPUT_INDICATOR_SLICE_URI
- );
- }
-
- @Override
- public Intent getSeeMoreIntent() {
- return new Intent();
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.TESTING;
- }
- };
+ constructTestLiveData(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
final PanelSlicesAdapter adapter =
- new PanelSlicesAdapter(mPanelFragment, mediaOutputIndicatorSlicePanelContent);
+ new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
final int position = 0;
final ViewGroup view = new FrameLayout(mContext);
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatchTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatchTest.java
new file mode 100644
index 0000000..dd8a91f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesLoaderCountdownLatchTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.settings.panel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.net.Uri;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class PanelSlicesLoaderCountdownLatchTest {
+
+ private Context mContext;
+ private PanelSlicesLoaderCountdownLatch mSliceCountdownLatch;
+
+ private static final Uri[] URIS = new Uri[] {
+ Uri.parse("content://testUri"),
+ Uri.parse("content://wowUri"),
+ Uri.parse("content://boxTurtle")
+ };
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mSliceCountdownLatch = new PanelSlicesLoaderCountdownLatch(URIS.length);
+ }
+
+
+ @Test
+ public void hasLoaded_newObject_returnsFalse() {
+ assertThat(mSliceCountdownLatch.isSliceLoaded(URIS[0])).isFalse();
+ }
+
+ @Test
+ public void hasLoaded_markSliceLoaded_returnsTrue() {
+ mSliceCountdownLatch.markSliceLoaded(URIS[0]);
+
+ assertThat(mSliceCountdownLatch.isSliceLoaded(URIS[0])).isTrue();
+ }
+
+ @Test
+ public void markSliceLoaded_onlyCountsDownUniqueUris() {
+ for (int i = 0; i < URIS.length; i++) {
+ mSliceCountdownLatch.markSliceLoaded(URIS[0]);
+ }
+
+ assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isFalse();
+ }
+
+ @Test
+ public void areSlicesReadyToLoad_allSlicesLoaded_returnsTrue() {
+ for (int i = 0; i < URIS.length; i++) {
+ mSliceCountdownLatch.markSliceLoaded(URIS[i]);
+ }
+
+ assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isTrue();
+ }
+
+ @Test
+ public void areSlicesReadyToLoad_onlyReturnsTrueOnce() {
+ for (int i = 0; i < URIS.length; i++) {
+ mSliceCountdownLatch.markSliceLoaded(URIS[i]);
+ }
+
+ // Verify that it returns true once
+ assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isTrue();
+ // Verify the second call returns false without external state change
+ assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isFalse();
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index 1d5c3c2..fa15aa0 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -99,7 +99,7 @@
0,
SettingsEnums.PAGE_HIDE,
SettingsEnums.TESTING,
- PanelLoggingContract.PanelClosedKeys.KEY_CLICKED_OUT,
+ PanelLoggingContract.PanelClosedKeys.KEY_OTHERS,
0
);
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index a1db12c..c692f55 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -224,7 +224,7 @@
initActivity(null);
mFragment.onActivityResult(
- ChooseLockGenericFragment.CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST,
+ ChooseLockGenericFragment.CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST,
BiometricEnrollBase.RESULT_FINISHED, null /* data */);
assertThat(mActivity.isFinishing()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java
new file mode 100644
index 0000000..0b85c37
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import static com.android.settings.sim.SimDialogActivity.PREFERRED_PICK;
+import static com.android.settings.sim.SimDialogActivity.PREFERRED_SIM;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.DialogInterface;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class PreferredSimDialogFragmentTest extends
+ SimDialogFragmentTestBase<PreferredSimDialogFragment> {
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ setDialogType(PREFERRED_PICK);
+ mFragment = spy(PreferredSimDialogFragment.newInstance());
+ doReturn(mSubscriptionManager).when(mFragment).getSubscriptionManager();
+ }
+
+ @Test
+ public void onCreateDialog_noSims_dismissed() {
+ when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt()))
+ .thenReturn(null);
+ mIntent.putExtra(PREFERRED_SIM, 0);
+ startDialog();
+ verify(mFragment).dismiss();
+ }
+
+ @Test
+ public void onCreateDialog_oneSimWrongSlotArgument_dismissed() {
+ when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1)).thenReturn(null);
+ mIntent.putExtra(PREFERRED_SIM, 1);
+ startDialog();
+ verify(mFragment).dismiss();
+ }
+
+ @Test
+ public void onCreateDialog_twoSimsSelectFirst_correctMessage() {
+ mIntent.putExtra(PREFERRED_SIM, 0);
+
+ final AlertDialog alertDialog = startDialog();
+ final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
+ final String message = (String) shadowDialog.getMessage();
+ assertThat(message).contains(SIM1_NAME);
+ assertThat(message).doesNotContain(SIM2_NAME);
+ }
+
+ @Test
+ public void onCreateDialog_twoSimsSelectSecond_correctMessage() {
+ mIntent.putExtra(PREFERRED_SIM, 1);
+
+ final AlertDialog alertDialog = startDialog();
+ final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
+ final String message = (String) shadowDialog.getMessage();
+ assertThat(message).contains(SIM2_NAME);
+ assertThat(message).doesNotContain(SIM1_NAME);
+ }
+
+ @Test
+ public void onClick_yesClicked_callsOnSubscriptionSelected() {
+ mIntent.putExtra(PREFERRED_SIM, 0);
+
+ final AlertDialog alertDialog = startDialog();
+
+ final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
+ doReturn(activity).when(mFragment).getActivity();
+ doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
+
+ mFragment.onClick(alertDialog, DialogInterface.BUTTON_POSITIVE);
+ verify(activity).onSubscriptionSelected(PREFERRED_PICK, SIM1_ID);
+ }
+
+ @Test
+ public void onClick_noClicked_doesNotCallOnSubscriptionSelected() {
+ mIntent.putExtra(PREFERRED_SIM, 0);
+
+ final AlertDialog alertDialog = startDialog();
+
+ final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
+ doReturn(activity).when(mFragment).getActivity();
+ doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
+
+ mFragment.onClick(alertDialog, DialogInterface.BUTTON_NEGATIVE);
+ verify(activity, never()).onSubscriptionSelected(anyInt(), anyInt());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/sim/SimDialogFragmentTestBase.java b/tests/robotests/src/com/android/settings/sim/SimDialogFragmentTestBase.java
new file mode 100644
index 0000000..904b831
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/sim/SimDialogFragmentTestBase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import static com.android.settings.sim.SimDialogActivity.DIALOG_TYPE_KEY;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.shadows.androidx.fragment.FragmentController;
+
+public abstract class SimDialogFragmentTestBase<T extends SimDialogFragment> {
+ protected static final int SIM1_ID = 111;
+ protected static final int SIM2_ID = 222;
+ protected static final String SIM1_NAME = "sim111";
+ protected static final String SIM2_NAME = "sim222";
+
+ @Mock
+ protected SubscriptionManager mSubscriptionManager;
+ @Mock
+ protected SubscriptionInfo mSim1;
+ @Mock
+ protected SubscriptionInfo mSim2;
+
+ protected T mFragment;
+ protected Intent mIntent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mIntent = new Intent();
+
+ when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(0)).thenReturn(mSim1);
+ when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1)).thenReturn(mSim2);
+
+ when(mSim1.getSubscriptionId()).thenReturn(SIM1_ID);
+ when(mSim1.getDisplayName()).thenReturn(SIM1_NAME);
+ when(mSim2.getSubscriptionId()).thenReturn(SIM2_ID);
+ when(mSim2.getDisplayName()).thenReturn(SIM2_NAME);
+ }
+
+ protected void setDialogType(int dialogType) {
+ mIntent.putExtra(DIALOG_TYPE_KEY, dialogType);
+ }
+
+ protected AlertDialog startDialog() {
+ final FragmentController controller = FragmentController.of(mFragment,
+ SimDialogActivity.class, mIntent);
+ controller.create(0 /* containerViewId */, null /* bundle */).start().visible();
+ return ShadowAlertDialogCompat.getLatestAlertDialog();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java
new file mode 100644
index 0000000..2b33ebe
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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.sim;
+
+import static com.android.settings.sim.SimDialogActivity.DATA_PICK;
+import static com.android.settings.sim.SimDialogActivity.SMS_PICK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.SubscriptionManager;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowAlertDialogCompat.class)
+public class SimListDialogFragmentTest extends SimDialogFragmentTestBase<SimListDialogFragment> {
+
+ @Test
+ public void onCreateDialog_noSubscriptions_dismissed() {
+ final int dialogType = DATA_PICK;
+ setDialogType(dialogType);
+ mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
+ false /* includeAskEveryTime */));
+ doReturn(null).when(mFragment).getCurrentSubscriptions();
+ startDialog();
+ verify(mFragment).dismiss();
+ }
+
+ @Test
+ public void onCreateDialog_twoSubscriptionsNoAskEveryTime_twoSubsForDisplay() {
+ final int dialogType = DATA_PICK;
+ setDialogType(dialogType);
+ mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
+ false /* includeAskEveryTime */));
+ doReturn(Arrays.asList(mSim1, mSim2)).when(mFragment).getCurrentSubscriptions();
+ // Avoid problems robolectric has with our real adapter.
+ doNothing().when(mFragment).setAdapter(any());
+ final AlertDialog alertDialog = startDialog();
+ assertThat(mFragment.mSubscriptions).hasSize(2);
+
+ final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
+ doReturn(activity).when(mFragment).getActivity();
+ doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
+
+ mFragment.onClick(alertDialog, 1);
+ verify(activity).onSubscriptionSelected(dialogType, SIM2_ID);
+ }
+
+ @Test
+ public void onCreateDialog_twoSubscriptionsAskEveryTime_threeSubsForDisplay() {
+ final int dialogType = SMS_PICK;
+ setDialogType(dialogType);
+ mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_sms,
+ true /* includeAskEveryTime */));
+ doReturn(Arrays.asList(mSim1, mSim2)).when(mFragment).getCurrentSubscriptions();
+ // Avoid problems robolectric has with our real adapter.
+ doNothing().when(mFragment).setAdapter(any());
+ final AlertDialog alertDialog = startDialog();
+ assertThat(mFragment.mSubscriptions).hasSize(3);
+ assertThat(mFragment.mSubscriptions.get(0)).isNull();
+
+ final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
+ doReturn(activity).when(mFragment).getActivity();
+ doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
+
+ mFragment.onClick(alertDialog, 0);
+ verify(activity).onSubscriptionSelected(dialogType,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
index 1ea324d..4e62b03 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBroadcastReceiverTest.java
@@ -191,8 +191,8 @@
.build();
final ContentResolver resolver = mock(ContentResolver.class);
doReturn(resolver).when(mContext).getContentResolver();
- final int position = FakeSliderController.MAX_STEPS - 1;
- final int oldPosition = FakeSliderController.MAX_STEPS;
+ final int position = FakeSliderController.MAX_VALUE - 1;
+ final int oldPosition = FakeSliderController.MAX_VALUE;
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
insertSpecialCase(FakeSliderController.class, key);
@@ -310,8 +310,8 @@
// Insert Fake Slider into Database
final String key = "key";
- final int position = FakeSliderController.MAX_STEPS - 1;
- final int oldPosition = FakeSliderController.MAX_STEPS;
+ final int position = FakeSliderController.MAX_VALUE - 1;
+ final int oldPosition = FakeSliderController.MAX_VALUE;
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
insertSpecialCase(FakeSliderController.class, key);
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
index 9e65913..da9cd63 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeSliderController.java
@@ -25,7 +25,7 @@
public static final String AVAILABILITY_KEY = "fake_slider_availability_key";
- public static final int MAX_STEPS = 9;
+ public static final int MAX_VALUE = 9;
private static final String SETTING_KEY = "fake_slider_key";
@@ -44,8 +44,13 @@
}
@Override
- public int getMaxSteps() {
- return MAX_STEPS;
+ public int getMax() {
+ return MAX_VALUE;
+ }
+
+ @Override
+ public int getMin() {
+ return 0;
}
@Override
diff --git a/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java
index a675e02..0a1d5d8 100644
--- a/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/SeekBarPreferenceTest.java
@@ -18,12 +18,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.os.Parcelable;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -39,9 +43,10 @@
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mSeekBarPreference = new SeekBarPreference(mContext);
+ mSeekBarPreference = spy(new SeekBarPreference(mContext));
mSeekBarPreference.setMax(MAX);
mSeekBarPreference.setMin(MIN);
mSeekBarPreference.setProgress(PROGRESS);
@@ -59,4 +64,18 @@
assertThat(preference.getMin()).isEqualTo(MIN);
assertThat(preference.getProgress()).isEqualTo(PROGRESS);
}
+
+ @Test
+ public void isSelectable_disabledByAdmin_returnTrue() {
+ when(mSeekBarPreference.isDisabledByAdmin()).thenReturn(true);
+
+ assertThat(mSeekBarPreference.isSelectable()).isTrue();
+ }
+
+ @Test
+ public void isSelectable_notDisabledByAdmin_returnFalse() {
+ when(mSeekBarPreference.isDisabledByAdmin()).thenReturn(false);
+
+ assertThat(mSeekBarPreference.isSelectable()).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
index d7f8ef8..41d1bbe 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
@@ -23,10 +23,13 @@
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
+import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowWifiManager;
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -72,7 +75,7 @@
}
@Test
- public void onSubmit_shouldNotConnectToNetwork_whenConnectForCallerIsFalse() {
+ public void onSubmit_whenConnectForCallerIsFalse_shouldNotConnectToNetwork() {
WifiDialogActivity activity =
Robolectric.buildActivity(
WifiDialogActivity.class,
@@ -88,4 +91,24 @@
assertThat(ShadowWifiManager.get().savedWifiConfig).isNull();
}
+
+ @Test
+ public void onSubmit_whenLaunchInSetupFlow_shouldBeLightThemeForWifiDialog() {
+ WifiDialogActivity activity =
+ Robolectric.buildActivity(
+ WifiDialogActivity.class,
+ new Intent()
+ .putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false)
+ .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true)
+ .putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true))
+ .setup().get();
+ WifiDialog dialog = (WifiDialog) ShadowAlertDialogCompat.getLatestAlertDialog();
+
+ assertThat(dialog).isNotNull();
+
+ activity.onSubmit(dialog);
+
+ assertThat(dialog.getContext().getThemeResId())
+ .isEqualTo(R.style.SuwAlertDialogThemeCompat_Light);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
index 4ce29aa..ed9b851 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
@@ -4,6 +4,7 @@
import android.content.Context;
+import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.wifi.WifiDialog.WifiDialogListener;
import com.android.settingslib.wifi.AccessPoint;
@@ -41,4 +42,16 @@
assertThat(modal.getContext().getThemeResId())
.isEqualTo(wifiDialog.getContext().getThemeResId());
}
+
+ @Test
+ public void createModal_whenSetTheme_shouldBeCustomizedTheme() {
+ WifiDialog modal = WifiDialog.createModal(mContext, mListener, mockAccessPoint,
+ WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light);
+
+ WifiDialog wifiDialog = new WifiDialog(mContext, mListener, mockAccessPoint,
+ WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light,
+ false /* hideSubmitButton */);
+ assertThat(modal.getContext().getThemeResId())
+ .isEqualTo(wifiDialog.getContext().getThemeResId());
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 223e81b..2acfc4a 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -289,17 +289,9 @@
when(mockIconInjector.getIcon(anyInt())).thenReturn(new ColorDrawable());
setupMockedPreferenceScreen();
-
- // Disable saved network detail page feature for this test
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, false);
- when(mockAccessPoint.isActive()).thenReturn(true);
-
- mController = newWifiDetailPreferenceController();
}
private void setUpForConnectedNetwork() {
- // Enable saved network detail page feature for this test
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true);
when(mockAccessPoint.isActive()).thenReturn(true);
ArrayList list = new ArrayList<>();
list.add(mockAccessPoint);
@@ -312,8 +304,6 @@
}
private void setUpForDisconnectedNetwork() {
- // Enable saved network detail page feature for this test
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true);
when(mockAccessPoint.isActive()).thenReturn(false);
ArrayList list = new ArrayList<>();
list.add(mockAccessPoint);
@@ -326,8 +316,6 @@
}
private void setUpForNotInRangeNetwork() {
- // Enable saved network detail page feature for this test
- FeatureFlagUtils.setEnabled(mContext, FeatureFlags.WIFI_DETAILS_SAVED_SCREEN, true);
when(mockAccessPoint.isActive()).thenReturn(false);
ArrayList list = new ArrayList<>();
list.add(mockAccessPoint);
@@ -397,6 +385,7 @@
@Test
public void isAvailable_shouldAlwaysReturnTrue() {
+ setUpForConnectedNetwork();
mController.displayPreference(mockScreen);
assertThat(mController.isAvailable()).isTrue();
@@ -404,19 +393,13 @@
@Test
public void securityPreference_stringShouldBeSet() {
+ setUpForConnectedNetwork();
displayAndResume();
verify(mockSecurityPref).setSummary(SECURITY);
}
@Test
- public void latestWifiInfo_shouldBeFetchedInDisplayPreference() {
- displayAndResume();
-
- verify(mockWifiManager, times(1)).getConnectionInfo();
- }
-
- @Test
public void latestWifiInfo_shouldBeFetchedInDisplayPreferenceForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -444,13 +427,6 @@
}
@Test
- public void latestNetworkInfo_shouldBeFetchedInDisplayPreference() {
- displayAndResume();
-
- verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
- }
-
- @Test
public void latestNetworkInfo_shouldBeFetchedInDisplayPreferenceForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -479,6 +455,7 @@
@Test
public void networkCallback_shouldBeRegisteredOnResume() {
+ setUpForConnectedNetwork();
displayAndResume();
verify(mockConnectivityManager, times(1)).registerNetworkCallback(
@@ -487,6 +464,7 @@
@Test
public void networkCallback_shouldBeUnregisteredOnPause() {
+ setUpForConnectedNetwork();
displayAndResume();
mController.onPause();
@@ -495,15 +473,6 @@
}
@Test
- public void entityHeader_shouldHaveIconSet() {
- Drawable expectedIcon = mockIconInjector.getIcon(LEVEL);
-
- displayAndResume();
-
- verify(mockHeaderController).setIcon(expectedIcon);
- }
-
- @Test
public void entityHeader_shouldHaveIconSetForConnectedNetwork() {
setUpForConnectedNetwork();
Drawable expectedIcon = mockIconInjector.getIcon(LEVEL);
@@ -534,6 +503,7 @@
@Test
public void entityHeader_shouldHaveLabelSetToTitle() {
+ setUpForConnectedNetwork();
String label = "title";
when(mockAccessPoint.getTitle()).thenReturn(label);
@@ -544,6 +514,7 @@
@Test
public void entityHeader_shouldHaveSummarySet() {
+ setUpForConnectedNetwork();
String summary = "summary";
when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
@@ -553,13 +524,6 @@
}
@Test
- public void signalStrengthPref_shouldHaveIconSet() {
- displayAndResume();
-
- verify(mockSignalStrengthPref).setIcon(any(Drawable.class));
- }
-
- @Test
public void signalStrengthPref_shouldHaveIconSetForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -587,16 +551,6 @@
}
@Test
- public void signalStrengthPref_shouldHaveDetailTextSet() {
- String expectedStrength =
- mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL];
-
- displayAndResume();
-
- verify(mockSignalStrengthPref).setSummary(expectedStrength);
- }
-
- @Test
public void signalStrengthPref_shouldHaveDetailTextSetForConnectedNetwork() {
setUpForConnectedNetwork();
String expectedStrength =
@@ -628,16 +582,8 @@
}
@Test
- public void linkSpeedPref_shouldHaveDetailTextSet() {
- String expectedLinkSpeed = mContext.getString(R.string.tx_link_speed, TX_LINK_SPEED);
-
- displayAndResume();
-
- verify(mockTxLinkSpeedPref).setSummary(expectedLinkSpeed);
- }
-
- @Test
public void linkSpeedPref_shouldNotShowIfNotSet() {
+ setUpForConnectedNetwork();
when(mockWifiInfo.getTxLinkSpeedMbps()).thenReturn(WifiInfo.LINK_SPEED_UNKNOWN);
displayAndResume();
@@ -677,16 +623,8 @@
}
@Test
- public void rxLinkSpeedPref_shouldHaveDetailTextSet() {
- String expectedLinkSpeed = mContext.getString(R.string.rx_link_speed, RX_LINK_SPEED);
-
- displayAndResume();
-
- verify(mockRxLinkSpeedPref).setSummary(expectedLinkSpeed);
- }
-
- @Test
public void rxLinkSpeedPref_shouldNotShowIfNotSet() {
+ setUpForConnectedNetwork();
when(mockWifiInfo.getRxLinkSpeedMbps()).thenReturn(WifiInfo.LINK_SPEED_UNKNOWN);
displayAndResume();
@@ -726,41 +664,32 @@
}
@Test
- public void ssidPref_shouldHaveDetailTextSet() {
+ public void ssidPref_shouldHaveDetailTextSetForPasspointR1() {
+ setUpForConnectedNetwork();
when(mockAccessPoint.isPasspoint()).thenReturn(true);
when(mockAccessPoint.isOsuProvider()).thenReturn(false);
displayAndResume();
verify(mockSsidPref, times(1)).setSummary(SSID);
-
- when(mockAccessPoint.isPasspoint()).thenReturn(false);
- when(mockAccessPoint.isOsuProvider()).thenReturn(true);
-
- displayAndResume();
-
- verify(mockSsidPref, times(2)).setSummary(SSID);
+ verify(mockSsidPref, times(1)).setVisible(true);
}
@Test
- public void ssidPref_shouldShowIfPasspointOrOsu() {
- when(mockAccessPoint.isPasspoint()).thenReturn(true);
- when(mockAccessPoint.isOsuProvider()).thenReturn(false);
-
- displayAndResume();
-
- verify(mockSsidPref, times(1)).setVisible(true);
-
+ public void ssidPref_shouldHaveDetailTextSetForPasspointR2() {
+ setUpForConnectedNetwork();
when(mockAccessPoint.isPasspoint()).thenReturn(false);
when(mockAccessPoint.isOsuProvider()).thenReturn(true);
displayAndResume();
- verify(mockSsidPref, times(2)).setVisible(true);
+ verify(mockSsidPref, times(1)).setSummary(SSID);
+ verify(mockSsidPref, times(1)).setVisible(true);
}
@Test
public void ssidPref_shouldNotShowIfNotPasspoint() {
+ setUpForConnectedNetwork();
when(mockAccessPoint.isPasspoint()).thenReturn(false);
when(mockAccessPoint.isOsuProvider()).thenReturn(false);
@@ -770,13 +699,6 @@
}
@Test
- public void macAddressPref_shouldHaveDetailTextSet() {
- displayAndResume();
-
- verify(mockMacAddressPref).setSummary(MAC_ADDRESS);
- }
-
- @Test
public void macAddressPref_shouldVisibleForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -813,15 +735,6 @@
}
@Test
- public void ipAddressPref_shouldHaveDetailTextSet() {
- mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
-
- displayAndResume();
-
- verify(mockIpAddressPref).setSummary(Constants.IPV4_ADDR.getAddress().getHostAddress());
- }
-
- @Test
public void ipAddressPref_shouldHaveDetailTextSetForConnectedNetwork() {
setUpForConnectedNetwork();
mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
@@ -842,18 +755,6 @@
}
@Test
- public void gatewayAndSubnet_shouldHaveDetailTextSet() {
- mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
- mLinkProperties.addRoute(Constants.IPV4_DEFAULT);
- mLinkProperties.addRoute(Constants.IPV4_SUBNET);
-
- displayAndResume();
-
- verify(mockSubnetPref).setSummary("255.255.255.128");
- verify(mockGatewayPref).setSummary("192.0.2.127");
- }
-
- @Test
public void gatewayAndSubnet_shouldHaveDetailTextSetForConnectedNetwork() {
setUpForConnectedNetwork();
mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
@@ -877,20 +778,6 @@
}
@Test
- public void dnsServersPref_shouldHaveDetailTextSet() throws UnknownHostException {
- mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 4, 4}));
- mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 8, 8}));
- mLinkProperties.addDnsServer(Constants.IPV6_DNS);
-
- displayAndResume();
-
- verify(mockDnsPref).setSummary(
- "8.8.4.4\n" +
- "8.8.8.8\n" +
- Constants.IPV6_DNS.getHostAddress());
- }
-
- @Test
public void dnsServersPref_shouldHaveDetailTextSetForConnectedNetwork()
throws UnknownHostException {
setUpForConnectedNetwork();
@@ -918,20 +805,7 @@
}
@Test
- public void noCurrentNetwork_shouldFinishActivity() {
- // If WifiManager#getCurrentNetwork() returns null, then the network is neither connected
- // nor connecting and WifiStateMachine has not reached L2ConnectedState.
- when(mockWifiManager.getCurrentNetwork()).thenReturn(null);
-
- displayAndResume();
-
- verify(mockActivity).finish();
- }
-
- @Test
public void noCurrentNetwork_shouldNotFinishActivityForConnectedNetwork() {
- // For new feature for display detail page for saved network for disconnected network,
- // mNetwork may be null, do finish activity
setUpForConnectedNetwork();
when(mockWifiManager.getCurrentNetwork()).thenReturn(null);
@@ -942,6 +816,7 @@
@Test
public void noLinkProperties_allIpDetailsHidden() {
+ setUpForConnectedNetwork();
when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null);
reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref, mockDnsPref);
@@ -1009,6 +884,7 @@
@Test
public void onLinkPropertiesChanged_updatesFields() {
+ setUpForConnectedNetwork();
displayAndResume();
InOrder inOrder = inOrder(mockIpAddressPref, mockGatewayPref, mockSubnetPref,
@@ -1065,6 +941,7 @@
@Test
public void onCapabilitiesChanged_callsRefreshIfNecessary() {
+ setUpForConnectedNetwork();
NetworkCapabilities nc = makeNetworkCapabilities();
when(mockConnectivityManager.getNetworkCapabilities(mockNetwork))
.thenReturn(new NetworkCapabilities(nc));
@@ -1115,10 +992,11 @@
}
@Test
- public void canForgetNetwork_noNetwork() {
+ public void canForgetNetwork_shouldInvisibleIfWithoutConfiguration() {
+ setUpForConnectedNetwork();
when(mockAccessPoint.getConfig()).thenReturn(null);
-
mController = newWifiDetailPreferenceController();
+
displayAndResume();
verify(mockButtonsPref).setButton1Visible(false);
@@ -1126,6 +1004,7 @@
@Test
public void canForgetNetwork_ephemeral() {
+ setUpForConnectedNetwork();
when(mockWifiInfo.isEphemeral()).thenReturn(true);
when(mockAccessPoint.getConfig()).thenReturn(null);
@@ -1136,6 +1015,7 @@
@Test
public void canForgetNetwork_saved() {
+ setUpForConnectedNetwork();
displayAndResume();
verify(mockButtonsPref).setButton1Visible(true);
@@ -1143,6 +1023,7 @@
@Test
public void canForgetNetwork_lockedDown() {
+ setUpForConnectedNetwork();
lockDownNetwork();
displayAndResume();
@@ -1151,7 +1032,8 @@
}
@Test
- public void canShareNetwork_noNetwork() {
+ public void canShareNetwork_shouldInvisibleIfWithoutConfiguration() {
+ setUpForConnectedNetwork();
when(mockAccessPoint.getConfig()).thenReturn(null);
displayAndResume();
@@ -1161,11 +1043,13 @@
@Test
public void canModifyNetwork_saved() {
+ setUpForConnectedNetwork();
assertThat(mController.canModifyNetwork()).isTrue();
}
@Test
public void canModifyNetwork_lockedDown() {
+ setUpForConnectedNetwork();
lockDownNetwork();
assertThat(mController.canModifyNetwork()).isFalse();
@@ -1196,6 +1080,7 @@
@Test
public void forgetNetwork_ephemeral() {
+ setUpForConnectedNetwork();
String ssid = "ssid";
when(mockWifiInfo.isEphemeral()).thenReturn(true);
when(mockWifiInfo.getSSID()).thenReturn(ssid);
@@ -1210,6 +1095,7 @@
@Test
public void forgetNetwork_saved() {
+ setUpForConnectedNetwork();
mockWifiConfig.networkId = 5;
mController.displayPreference(mockScreen);
@@ -1222,6 +1108,7 @@
@Test
public void forgetNetwork_v1_Passpoint() {
+ setUpForConnectedNetwork();
FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false);
mockWifiConfig.networkId = 5;
@@ -1237,6 +1124,7 @@
@Test
public void forgetNetwork_PasspointV2_shouldShowDialog() {
+ setUpForConnectedNetwork();
final WifiDetailPreferenceController spyController = spy(mController);
mockWifiConfig.networkId = 5;
@@ -1254,6 +1142,8 @@
@Test
public void networkStateChangedIntent_shouldRefetchInfo() {
+ setUpForConnectedNetwork();
+
displayAndResume();
verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
@@ -1268,6 +1158,7 @@
@Test
public void networkStateChangedIntent_shouldRefetchInfoForConnectedNetwork() {
setUpForConnectedNetwork();
+
displayAndResume();
verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
@@ -1281,6 +1172,8 @@
@Test
public void rssiChangedIntent_shouldRefetchInfo() {
+ setUpForConnectedNetwork();
+
displayAndResume();
verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
@@ -1307,16 +1200,6 @@
}
@Test
- public void networkDisconnectedState_shouldFinishActivity() {
- displayAndResume();
-
- when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(null);
- mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION));
-
- verify(mockActivity).finish();
- }
-
- @Test
public void networkDisconnectedState_shouldNotFinishActivityForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -1329,15 +1212,6 @@
}
@Test
- public void networkOnLost_shouldFinishActivity() {
- displayAndResume();
-
- mCallbackCaptor.getValue().onLost(mockNetwork);
-
- verify(mockActivity).finish();
- }
-
- @Test
public void networkOnLost_shouldNotFinishActivityForConnectedNetwork() {
setUpForConnectedNetwork();
@@ -1350,6 +1224,7 @@
@Test
public void ipv6AddressPref_shouldHaveHostAddressTextSet() {
+ setUpForConnectedNetwork();
mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL);
mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL1);
mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2);
@@ -1366,6 +1241,7 @@
@Test
public void ipv6AddressPref_shouldNotBeSelectable() {
+ setUpForConnectedNetwork();
mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2);
displayAndResume();
@@ -1375,6 +1251,8 @@
@Test
public void captivePortal_shouldShowSignInButton() {
+ setUpForConnectedNetwork();
+
InOrder inOrder = inOrder(mockButtonsPref);
displayAndResume();
@@ -1396,6 +1274,8 @@
@Test
public void testSignInButton_shouldStartCaptivePortalApp() {
+ setUpForConnectedNetwork();
+
displayAndResume();
ArgumentCaptor<OnClickListener> captor = ArgumentCaptor.forClass(OnClickListener.class);
@@ -1428,23 +1308,25 @@
}
@Test
- public void testRefreshRssiViews_shouldNotUpdateIfLevelIsSame() {
+ public void testRefreshRssiViews_shouldNotUpdateIfLevelIsSameForConnectedNetwork() {
+ setUpForConnectedNetwork();
displayAndResume();
mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION));
- verify(mockAccessPoint, times(2)).getLevel();
+ verify(mockAccessPoint, times(3)).getLevel();
verify(mockIconInjector, times(1)).getIcon(anyInt());
}
@Test
- public void testRefreshRssiViews_shouldUpdateOnLevelChange() {
+ public void testRefreshRssiViews_shouldUpdateOnLevelChangeForConnectedNetwork() {
+ setUpForConnectedNetwork();
displayAndResume();
when(mockAccessPoint.getLevel()).thenReturn(0);
mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION));
- verify(mockAccessPoint, times(2)).getLevel();
+ verify(mockAccessPoint, times(4)).getLevel();
verify(mockIconInjector, times(2)).getIcon(anyInt());
}
@@ -1462,6 +1344,26 @@
@Test
public void testRedrawIconForHeader_shouldEnlarge() {
+ setUpForConnectedNetwork();
+ ArgumentCaptor<BitmapDrawable> drawableCaptor =
+ ArgumentCaptor.forClass(BitmapDrawable.class);
+ Drawable original = mContext.getDrawable(Utils.getWifiIconResource(LEVEL)).mutate();
+ when(mockIconInjector.getIcon(anyInt())).thenReturn(original);
+
+ displayAndResume();
+
+ verify(mockHeaderController, times(1)).setIcon(drawableCaptor.capture());
+
+ int expectedSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.wifi_detail_page_header_image_size);
+ BitmapDrawable icon = drawableCaptor.getValue();
+ assertThat(icon.getMinimumWidth()).isEqualTo(expectedSize);
+ assertThat(icon.getMinimumHeight()).isEqualTo(expectedSize);
+ }
+
+ @Test
+ public void testRedrawIconForHeader_shouldEnlargeForDisconnectedNetwork() {
+ setUpForDisconnectedNetwork();
ArgumentCaptor<BitmapDrawable> drawableCaptor =
ArgumentCaptor.forClass(BitmapDrawable.class);
Drawable original = mContext.getDrawable(Utils.getWifiIconResource(LEVEL)).mutate();
@@ -1480,6 +1382,7 @@
@Test
public void testRedrawIconForHeader_shouldNotEnlargeIfNotVectorDrawable() {
+ setUpForConnectedNetwork();
ArgumentCaptor<ColorDrawable> drawableCaptor =
ArgumentCaptor.forClass(ColorDrawable.class);
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
index 746456e..cda4005 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
@@ -17,47 +17,23 @@
package com.android.settings.wifi.savedaccesspoints;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
-import com.android.settings.core.FeatureFlags;
-import com.android.settings.development.featureflags.FeatureFlagPersistent;
-import com.android.settings.wifi.WifiConfigController;
-import com.android.settings.wifi.WifiDialog;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.wifi.AccessPoint;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class SavedAccessPointsWifiSettingsTest {
@Mock
- private WifiManager mWifiManager;
- @Mock
- private WifiDialog mWifiDialog;
- @Mock
- private WifiConfigController mConfigController;
- @Mock
- private WifiConfiguration mWifiConfiguration;
- @Mock
- private AccessPoint mAccessPoint;
- @Mock
private SubscribedAccessPointsPreferenceController mSubscribedApController;
@Mock
private SavedAccessPointsPreferenceController mSavedApController;
@@ -73,45 +49,6 @@
.use(SubscribedAccessPointsPreferenceController.class);
doReturn(mSavedApController).when(mSettings)
.use(SavedAccessPointsPreferenceController.class);
-
- ReflectionHelpers.setField(mSettings, "mWifiManager", mWifiManager);
-
- when(mWifiDialog.getController()).thenReturn(mConfigController);
- when(mConfigController.getConfig()).thenReturn(mWifiConfiguration);
- }
-
- @Test
- public void onForget_isPasspointConfig_shouldRefreshAPList() {
- FeatureFlagPersistent.setEnabled(RuntimeEnvironment.application,
- FeatureFlags.NETWORK_INTERNET_V2, false);
- when(mAccessPoint.isPasspointConfig()).thenReturn(true);
- ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
-
- mSettings.onForget(null);
-
- verify(mSavedApController).postRefreshSavedAccessPoints();
- }
-
- @Test
- public void onForget_isPasspointConfig_shouldRefreshSubscribedAPList() {
- FeatureFlagPersistent.setEnabled(RuntimeEnvironment.application,
- FeatureFlags.NETWORK_INTERNET_V2, true);
- when(mAccessPoint.isPasspointConfig()).thenReturn(true);
- ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
-
- mSettings.onForget(null);
-
- verify(mSubscribedApController).postRefreshSubscribedAccessPoints();
- }
-
- @Test
- public void onForget_shouldInvokeForgetApi() {
- ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
- when(mAccessPoint.getConfig()).thenReturn(mWifiConfiguration);
-
- mSettings.onForget(mWifiDialog);
-
- verify(mWifiManager).forget(mWifiConfiguration.networkId, mSavedApController);
}
@Test