Merge "Use SettingsRobolectricTestRunner in settings app"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d3acd13..c1e0c60 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -307,7 +307,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.wifi.SavedAccessPointsWifiSettings" />
+ android:value="com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
@@ -574,6 +574,12 @@
android:value="true" />
</activity>
+ <activity android:name=".localepicker.LocalePickerWithRegionActivity"
+ android:excludeFromRecents="true"
+ android:configChanges="orientation|keyboardHidden|screenSize"
+ android:exported="false">
+ </activity>
+
<activity
android:name=".Settings$LanguageAndInputSettingsActivity"
android:label="@string/language_settings"
diff --git a/res/drawable-hdpi/lock_anim_0.png b/res/drawable-hdpi/lock_anim_0.png
deleted file mode 100644
index 08732e4..0000000
--- a/res/drawable-hdpi/lock_anim_0.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_1.png b/res/drawable-hdpi/lock_anim_1.png
deleted file mode 100644
index 74a0628..0000000
--- a/res/drawable-hdpi/lock_anim_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_10.png b/res/drawable-hdpi/lock_anim_10.png
deleted file mode 100644
index adb981d..0000000
--- a/res/drawable-hdpi/lock_anim_10.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_11.png b/res/drawable-hdpi/lock_anim_11.png
deleted file mode 100644
index f8976a2..0000000
--- a/res/drawable-hdpi/lock_anim_11.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_12.png b/res/drawable-hdpi/lock_anim_12.png
deleted file mode 100644
index 3ccdc85..0000000
--- a/res/drawable-hdpi/lock_anim_12.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_13.png b/res/drawable-hdpi/lock_anim_13.png
deleted file mode 100644
index ccd38d5..0000000
--- a/res/drawable-hdpi/lock_anim_13.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_14.png b/res/drawable-hdpi/lock_anim_14.png
deleted file mode 100644
index 2f40d9e..0000000
--- a/res/drawable-hdpi/lock_anim_14.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_2.png b/res/drawable-hdpi/lock_anim_2.png
deleted file mode 100644
index 495b2da..0000000
--- a/res/drawable-hdpi/lock_anim_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_3.png b/res/drawable-hdpi/lock_anim_3.png
deleted file mode 100644
index fa37813..0000000
--- a/res/drawable-hdpi/lock_anim_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_4.png b/res/drawable-hdpi/lock_anim_4.png
deleted file mode 100644
index 8201fd9..0000000
--- a/res/drawable-hdpi/lock_anim_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_5.png b/res/drawable-hdpi/lock_anim_5.png
deleted file mode 100644
index b08932d..0000000
--- a/res/drawable-hdpi/lock_anim_5.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_6.png b/res/drawable-hdpi/lock_anim_6.png
deleted file mode 100644
index dac09e1..0000000
--- a/res/drawable-hdpi/lock_anim_6.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_7.png b/res/drawable-hdpi/lock_anim_7.png
deleted file mode 100644
index f06c9d6..0000000
--- a/res/drawable-hdpi/lock_anim_7.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_8.png b/res/drawable-hdpi/lock_anim_8.png
deleted file mode 100644
index 07f7e34..0000000
--- a/res/drawable-hdpi/lock_anim_8.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/lock_anim_9.png b/res/drawable-hdpi/lock_anim_9.png
deleted file mode 100644
index 551bafa..0000000
--- a/res/drawable-hdpi/lock_anim_9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_0.png b/res/drawable-mdpi/lock_anim_0.png
deleted file mode 100644
index afdda8b..0000000
--- a/res/drawable-mdpi/lock_anim_0.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_1.png b/res/drawable-mdpi/lock_anim_1.png
deleted file mode 100644
index 6cae8e5..0000000
--- a/res/drawable-mdpi/lock_anim_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_10.png b/res/drawable-mdpi/lock_anim_10.png
deleted file mode 100644
index 5de840e..0000000
--- a/res/drawable-mdpi/lock_anim_10.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_11.png b/res/drawable-mdpi/lock_anim_11.png
deleted file mode 100644
index 35db815..0000000
--- a/res/drawable-mdpi/lock_anim_11.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_12.png b/res/drawable-mdpi/lock_anim_12.png
deleted file mode 100644
index 8778d98..0000000
--- a/res/drawable-mdpi/lock_anim_12.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_13.png b/res/drawable-mdpi/lock_anim_13.png
deleted file mode 100644
index d0b8cf0..0000000
--- a/res/drawable-mdpi/lock_anim_13.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_14.png b/res/drawable-mdpi/lock_anim_14.png
deleted file mode 100644
index ea1aa31..0000000
--- a/res/drawable-mdpi/lock_anim_14.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_2.png b/res/drawable-mdpi/lock_anim_2.png
deleted file mode 100644
index 0542b1d..0000000
--- a/res/drawable-mdpi/lock_anim_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_3.png b/res/drawable-mdpi/lock_anim_3.png
deleted file mode 100644
index 7e2ba9a..0000000
--- a/res/drawable-mdpi/lock_anim_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_4.png b/res/drawable-mdpi/lock_anim_4.png
deleted file mode 100644
index a3ca629..0000000
--- a/res/drawable-mdpi/lock_anim_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_5.png b/res/drawable-mdpi/lock_anim_5.png
deleted file mode 100644
index 17e3839..0000000
--- a/res/drawable-mdpi/lock_anim_5.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_6.png b/res/drawable-mdpi/lock_anim_6.png
deleted file mode 100644
index 90205a6..0000000
--- a/res/drawable-mdpi/lock_anim_6.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_7.png b/res/drawable-mdpi/lock_anim_7.png
deleted file mode 100644
index 1d94a47..0000000
--- a/res/drawable-mdpi/lock_anim_7.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_8.png b/res/drawable-mdpi/lock_anim_8.png
deleted file mode 100644
index af7cd28..0000000
--- a/res/drawable-mdpi/lock_anim_8.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/lock_anim_9.png b/res/drawable-mdpi/lock_anim_9.png
deleted file mode 100644
index d401624..0000000
--- a/res/drawable-mdpi/lock_anim_9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_0.png b/res/drawable-xhdpi/lock_anim_0.png
deleted file mode 100644
index 5e8e6dc..0000000
--- a/res/drawable-xhdpi/lock_anim_0.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_1.png b/res/drawable-xhdpi/lock_anim_1.png
deleted file mode 100644
index 96fbd03..0000000
--- a/res/drawable-xhdpi/lock_anim_1.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_10.png b/res/drawable-xhdpi/lock_anim_10.png
deleted file mode 100644
index e2e83b1..0000000
--- a/res/drawable-xhdpi/lock_anim_10.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_11.png b/res/drawable-xhdpi/lock_anim_11.png
deleted file mode 100644
index 68de396..0000000
--- a/res/drawable-xhdpi/lock_anim_11.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_12.png b/res/drawable-xhdpi/lock_anim_12.png
deleted file mode 100644
index 11e51c7..0000000
--- a/res/drawable-xhdpi/lock_anim_12.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_13.png b/res/drawable-xhdpi/lock_anim_13.png
deleted file mode 100644
index 86a6115..0000000
--- a/res/drawable-xhdpi/lock_anim_13.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_14.png b/res/drawable-xhdpi/lock_anim_14.png
deleted file mode 100644
index 5bff2fa..0000000
--- a/res/drawable-xhdpi/lock_anim_14.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_2.png b/res/drawable-xhdpi/lock_anim_2.png
deleted file mode 100644
index 68e59c8..0000000
--- a/res/drawable-xhdpi/lock_anim_2.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_3.png b/res/drawable-xhdpi/lock_anim_3.png
deleted file mode 100644
index 16272ed..0000000
--- a/res/drawable-xhdpi/lock_anim_3.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_4.png b/res/drawable-xhdpi/lock_anim_4.png
deleted file mode 100644
index af6fbc4..0000000
--- a/res/drawable-xhdpi/lock_anim_4.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_5.png b/res/drawable-xhdpi/lock_anim_5.png
deleted file mode 100644
index 1e631b5..0000000
--- a/res/drawable-xhdpi/lock_anim_5.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_6.png b/res/drawable-xhdpi/lock_anim_6.png
deleted file mode 100644
index 93fcf39..0000000
--- a/res/drawable-xhdpi/lock_anim_6.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_7.png b/res/drawable-xhdpi/lock_anim_7.png
deleted file mode 100644
index b5c5277..0000000
--- a/res/drawable-xhdpi/lock_anim_7.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_8.png b/res/drawable-xhdpi/lock_anim_8.png
deleted file mode 100644
index bcaec0d..0000000
--- a/res/drawable-xhdpi/lock_anim_8.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/lock_anim_9.png b/res/drawable-xhdpi/lock_anim_9.png
deleted file mode 100644
index c481d1a..0000000
--- a/res/drawable-xhdpi/lock_anim_9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/ic_menu_add_inset.xml b/res/drawable/ic_menu_add_inset.xml
deleted file mode 100644
index a4f0a65..0000000
--- a/res/drawable/ic_menu_add_inset.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="5dp">
- <vector
- 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="M19.0,13.0l-6.0,0.0l0.0,6.0l-2.0,0.0l0.0,-6.0L5.0,13.0l0.0,-2.0l6.0,0.0L11.0,5.0l2.0,0.0l0.0,6.0l6.0,0.0l0.0,2.0z"/>
- </vector>
-</inset>
diff --git a/res/drawable/lock_anim.xml b/res/drawable/lock_anim.xml
deleted file mode 100644
index 8ec31a6..0000000
--- a/res/drawable/lock_anim.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, 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.
-*/
--->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="false">
- <item android:drawable="@drawable/lock_anim_0" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_1" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_2" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_3" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_4" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_5" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_6" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_7" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_8" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_9" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_10" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_11" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_12" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_13" android:duration="200" />
- <item android:drawable="@drawable/lock_anim_14" android:duration="200" />
-</animation-list>
diff --git a/res/layout/preference_list_fragment.xml b/res/layout/preference_list_fragment.xml
index eeea9c4..852ef6d 100644
--- a/res/layout/preference_list_fragment.xml
+++ b/res/layout/preference_list_fragment.xml
@@ -37,19 +37,6 @@
android:paddingStart="@dimen/settings_side_margin"
android:paddingEnd="@dimen/settings_side_margin">
- <ListView android:id="@+id/backup_list"
- style="@style/PreferenceFragmentListSinglePane"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingTop="@dimen/dashboard_padding_top"
- android:paddingBottom="@dimen/dashboard_padding_bottom"
- android:scrollbarStyle="@*android:integer/preference_fragment_scrollbarStyle"
- android:clipToPadding="false"
- android:drawSelectorOnTop="false"
- android:elevation="@dimen/dashboard_category_elevation"
- android:visibility="gone"
- android:scrollbarAlwaysDrawVerticalTrack="true" />
-
<include layout="@layout/loading_container" />
</FrameLayout>
@@ -74,8 +61,7 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentStart="true"
- android:text="@*android:string/back_button_label"
- />
+ android:text="@*android:string/back_button_label" />
<LinearLayout
android:orientation="horizontal"
@@ -89,16 +75,14 @@
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@*android:string/skip_button_label"
- android:visibility="gone"
- />
+ android:visibility="gone" />
<Button android:id="@+id/next_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
- android:text="@*android:string/next_button_label"
- />
+ android:text="@*android:string/next_button_label" />
</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 02d3182..2341728 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -97,9 +97,6 @@
<dimen name="dashboard_category_padding_start">0dp</dimen>
<dimen name="dashboard_category_padding_end">0dp</dimen>
- <!-- Dashboard category panel elevation -->
- <dimen name="dashboard_category_elevation">2dp</dimen>
-
<!-- Dashboard tile minimum height -->
<dimen name="dashboard_tile_minimum_height">72dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9d9c67b..41b3a80 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -588,9 +588,6 @@
<!-- Title for the locale picker activity -->
<string name="language_picker_title">Languages</string>
- <!-- Title for the language selection screen [CHAR LIMIT=25] -->
- <string name="pref_title_lang_selection">Language preferences</string>
-
<!-- Menu item in the locale menu. Will remove the selected locales. [CHAR LIMIT=30] -->
<string name="locale_remove_menu">Remove</string>
@@ -2115,8 +2112,6 @@
<string name="wifi_forget_dialog_message">All passwords for this network will be deleted</string>
<!-- Wi-Fi Advanced Settings --> <skip />
- <!-- Wi-Fi settings screen, Saved networks, settings section. This is a header shown above Saved networks wifi settings. [CHAR LIMIT=30] -->
- <string name="wifi_saved_access_points_titlebar">Saved networks</string>
<!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates the number of networks a user has saved. -->
<plurals name="wifi_saved_access_points_summary">
<item quantity="one">1 network</item>
@@ -4925,11 +4920,6 @@
<!-- Title for the screen usage in power use UI [CHAR_LIMIT=60] -->
<string name="device_screen_usage">Screen usage since full charge</string>
- <!-- Title for the screen consumption in power use UI(i.e. Screen consumption: 30% of battery usage) [CHAR_LIMIT=40] -->
- <string name="device_screen_consumption">Screen consumption</string>
- <!-- Title for the cellular network in power use UI(i.e. Mobile network scanning: 30% of battery usage) [CHAR_LIMIT=40] -->
- <string name="device_cellular_network">Mobile network scanning</string>
-
<!-- Label for list of apps using battery in power use UI. Note: ^1 should be used in all translations[CHAR_LIMIT=120] -->
<string name="power_usage_list_summary">Battery usage since full charge</string>
<!-- Temp string used to debug new battery estimates [DO NOT TRANSLATE] -->
@@ -5953,8 +5943,8 @@
<!-- Activity title for network data usage summary. [CHAR LIMIT=25] -->
<string name="data_usage_summary_title">Data usage</string>
- <!-- Activity title for Appk data usage summary. [CHAR LIMIT=25] -->
- <string name="data_usage_app_summary_title">App data usage</string>
+ <!-- Activity title Mobile data & WI-FI summary. [CHAR LIMIT=25] -->
+ <string name="data_usage_app_summary_title">Mobile data & Wi\u2011Fi</string>
<!-- Message about carrier data accounting. [CHAR LIMIT=100] -->
<string name="data_usage_accounting">Carrier data accounting may differ from your device.</string>
<!-- Title for app usage. [CHAR LIMIT=40] -->
@@ -6905,6 +6895,8 @@
<string name="app_and_notification_dashboard_title">Apps & notifications</string>
<!-- Summary for Apps & Notification settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
<string name="app_and_notification_dashboard_summary">Permissions, default apps</string>
+ <!-- Toast text for notification settings in the work profile. This is shown when an app in the work profile attempts to open notification settings. [CHAR LIMIT=NONE] -->
+ <string name="notification_settings_work_profile">Notification access is not available for apps in the work profile.</string>
<!-- Title for setting tile leading to account settings [CHAR LIMIT=40]-->
<string name="account_dashboard_title">Accounts</string>
<!-- Summary for account settings tiles when there is no accounts on device [CHAR LIMIT=NONE]-->
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 2674d2f..d54f111 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -46,7 +46,7 @@
<item name="preferenceBackgroundColor">@drawable/preference_background</item>
<!-- For all androidx version of AlertDialogs -->
- <item name="alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert</item>
+ <item name="alertDialogTheme">@style/Theme.AlertDialog</item>
<item name="*android:lockPatternStyle">@style/LockPatternStyle.Setup</item>
@@ -106,11 +106,15 @@
<item name="android:windowSoftInputMode">adjustResize</item>
</style>
- <style name="Theme.AlertDialog" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog.Alert">
+ <style name="Theme.AlertDialog" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
<item name="android:windowSoftInputMode">adjustResize</item>
<!-- Redefine the ActionBar style for contentInsetStart -->
<item name="android:actionBarStyle">@style/Theme.ActionBar</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="Theme.ConfirmDeviceCredentials" parent="Theme.SubSettings">
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index 9d77e86..684d032 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -63,7 +63,7 @@
<Preference
android:key="data_settings"
- android:title="@string/data_usage_summary_title"
+ android:title="@string/data_usage_app_summary_title"
android:summary="@string/summary_placeholder"
settings:controller="com.android.settings.applications.appinfo.AppDataUsagePreferenceController" />
diff --git a/res/xml/wifi_display_saved_access_points.xml b/res/xml/wifi_display_saved_access_points.xml
index 81fb701..98b4dec 100644
--- a/res/xml/wifi_display_saved_access_points.xml
+++ b/res/xml/wifi_display_saved_access_points.xml
@@ -14,7 +14,15 @@
limitations under the License.
-->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/wifi_saved_access_points_titlebar">
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="saved_access_points"
+ android:title="@string/wifi_saved_access_points_label">
+
+ <PreferenceCategory
+ android:key="saved_access_points_category"
+ android:layout="@layout/preference_category_no_label"
+ settings:controller="com.android.settings.wifi.savedaccesspoints.SavedAccessPointsPreferenceController"/>
</PreferenceScreen>
diff --git a/res/xml/wifi_settings.xml b/res/xml/wifi_settings.xml
index 52aadcf..4ca9284 100644
--- a/res/xml/wifi_settings.xml
+++ b/res/xml/wifi_settings.xml
@@ -39,6 +39,6 @@
<Preference
android:key="saved_networks"
android:title="@string/wifi_saved_access_points_label"
- android:fragment="com.android.settings.wifi.SavedAccessPointsWifiSettings" />
+ android:fragment="com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings" />
</PreferenceCategory>
</PreferenceScreen>
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 55ec159..9d5f96f 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -389,9 +389,7 @@
*/
public static UserHandle getManagedProfile(UserManager userManager) {
List<UserHandle> userProfiles = userManager.getUserProfiles();
- final int count = userProfiles.size();
- for (int i = 0; i < count; i++) {
- final UserHandle profile = userProfiles.get(i);
+ for (UserHandle profile : userProfiles) {
if (profile.getIdentifier() == userManager.getUserHandle()) {
continue;
}
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index b910130..22cff3e 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -633,8 +633,14 @@
mCategoryToPrefCategoryMap.get(CATEGORY_DISPLAY);
experimentalCategory.removePreference(mToggleInversionPreference);
experimentalCategory.removePreference(mDisplayDaltonizerPreferenceScreen);
- mToggleInversionPreference.setOrder(mToggleLargePointerIconPreference.getOrder());
- mDisplayDaltonizerPreferenceScreen.setOrder(mToggleInversionPreference.getOrder());
+ mDisplayDaltonizerPreferenceScreen.setOrder(
+ mDisplayMagnificationPreferenceScreen.getOrder() + 1);
+ mToggleInversionPreference.setOrder(
+ mDisplayDaltonizerPreferenceScreen.getOrder() + 1);
+ mToggleLargePointerIconPreference.setOrder(
+ mToggleInversionPreference.getOrder() + 1);
+ mToggleDisableAnimationsPreference.setOrder(
+ mToggleLargePointerIconPreference.getOrder() + 1);
mToggleInversionPreference.setSummary(R.string.summary_empty);
displayCategory.addPreference(mToggleInversionPreference);
displayCategory.addPreference(mDisplayDaltonizerPreferenceScreen);
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java b/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java
index d0493e9..3838d29 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.applications.DefaultAppInfo;
@@ -43,11 +44,13 @@
public abstract class DefaultAppPickerFragment extends RadioButtonPickerFragment {
protected PackageManager mPm;
+ protected BatteryUtils mBatteryUtils;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPm = context.getPackageManager();
+ mBatteryUtils = BatteryUtils.getInstance(context);
}
@Override
diff --git a/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java b/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
index e462ab8..0bda2ec 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
@@ -80,6 +80,7 @@
@Override
protected boolean setDefaultKey(String key) {
if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, getDefaultKey())) {
+ mBatteryUtils.clearForceAppStandby(key);
return mDefaultKeyUpdater.setDefaultDialerApplication(getContext(), key, mUserId);
}
return false;
diff --git a/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java b/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
index 91f9caf..b5a2880 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
@@ -16,6 +16,7 @@
package com.android.settings.applications.defaultapps;
+import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -25,6 +26,7 @@
import com.android.internal.telephony.SmsApplication;
import com.android.settings.R;
import com.android.settings.Utils;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settingslib.applications.DefaultAppInfo;
import com.android.settingslib.widget.CandidateInfo;
@@ -74,6 +76,7 @@
protected boolean setDefaultKey(String key) {
if (!TextUtils.isEmpty(key) && !TextUtils.equals(key, getDefaultKey())) {
mDefaultKeyUpdater.setDefaultApplication(getContext(), key);
+ mBatteryUtils.clearForceAppStandby(key);
return true;
}
return false;
diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
index 6e0f915..0475734 100644
--- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
+++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java
@@ -455,10 +455,7 @@
void unrestrictAppIfPossible(BatteryUtils batteryUtils) {
// Unrestrict admin app if it is already been restricted
final String packageName = mDeviceAdmin.getComponent().getPackageName();
- final int uid = batteryUtils.getPackageUid(packageName);
- if (batteryUtils.isForceAppStandbyEnabled(uid, packageName)) {
- batteryUtils.setForceAppStandby(uid, packageName, AppOpsManager.MODE_ALLOWED);
- }
+ batteryUtils.clearForceAppStandby(packageName);
}
void continueRemoveAction(CharSequence msg) {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 1569ff0..219c92c 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -38,7 +38,6 @@
import com.android.settings.applications.ProcessStatsSummary;
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.applications.UsageAccessDetails;
-import com.android.settings.applications.specialaccess.vrlistener.VrListenerSettings;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
@@ -50,6 +49,7 @@
import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings;
import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails;
import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureSettings;
+import com.android.settings.applications.specialaccess.vrlistener.VrListenerSettings;
import com.android.settings.backup.PrivacySettings;
import com.android.settings.backup.ToggleBackupSettingFragment;
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
@@ -127,12 +127,12 @@
import com.android.settings.webview.WebViewAppPicker;
import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.wifi.ConfigureWifiSettings;
-import com.android.settings.wifi.SavedAccessPointsWifiSettings;
import com.android.settings.wifi.WifiAPITest;
import com.android.settings.wifi.WifiInfo;
import com.android.settings.wifi.WifiSettings;
import com.android.settings.wifi.calling.WifiCallingSettings;
import com.android.settings.wifi.p2p.WifiP2pSettings;
+import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
import com.android.settings.wifi.tether.WifiTetherSettings;
public class SettingsGateway {
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index f92f8ad..9e920c4 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -407,6 +407,16 @@
packageName) == AppOpsManager.MODE_IGNORED;
}
+ public boolean clearForceAppStandby(String packageName) {
+ final int uid = getPackageUid(packageName);
+ if (uid != UID_NULL && isForceAppStandbyEnabled(uid, packageName)) {
+ setForceAppStandby(uid, packageName, AppOpsManager.MODE_ALLOWED);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public void initBatteryStatsHelper(BatteryStatsHelper statsHelper, Bundle bundle,
UserManager userManager) {
statsHelper.create(bundle);
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
index 22c90e3..4bd8cd7 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
@@ -40,6 +40,7 @@
private static final String KEY_HIGH_USAGE_PERIOD_MS = "high_usage_period_ms";
private static final String KEY_HIGH_USAGE_BATTERY_DRAINING = "high_usage_battery_draining";
private static final String KEY_APP_RESTRICTION_ENABLED = "app_restriction_enabled";
+ private static final String KEY_APP_RESTRICTION_ACTIVE_HOUR = "app_restriction_active_hour";
private static final String KEY_REDUCED_BATTERY_ENABLED = "reduced_battery_enabled";
private static final String KEY_REDUCED_BATTERY_PERCENT = "reduced_battery_percent";
private static final String KEY_LOW_BATTERY_ENABLED = "low_battery_enabled";
@@ -119,6 +120,15 @@
public final boolean appRestrictionEnabled;
/**
+ * Period(hour) to show anomaly apps. If it is 24 hours, it means only show anomaly apps
+ * happened in last 24 hours.
+ *
+ * @see Settings.Global#BATTERY_TIP_CONSTANTS
+ * @see #KEY_APP_RESTRICTION_ACTIVE_HOUR
+ */
+ public final int appRestrictionActiveHour;
+
+ /**
* {@code true} if reduced battery tip is enabled
*
* @see Settings.Global#BATTERY_TIP_CONSTANTS
@@ -228,6 +238,7 @@
Duration.ofHours(2).toMillis());
highUsageBatteryDraining = mParser.getInt(KEY_HIGH_USAGE_BATTERY_DRAINING, 25);
appRestrictionEnabled = mParser.getBoolean(KEY_APP_RESTRICTION_ENABLED, true);
+ appRestrictionActiveHour = mParser.getInt(KEY_APP_RESTRICTION_ACTIVE_HOUR, 24);
reducedBatteryEnabled = mParser.getBoolean(KEY_REDUCED_BATTERY_ENABLED, false);
reducedBatteryPercent = mParser.getInt(KEY_REDUCED_BATTERY_PERCENT, 50);
lowBatteryEnabled = mParser.getBoolean(KEY_LOW_BATTERY_ENABLED, true);
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
index dfb7f97..8debf6b 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
@@ -136,8 +136,8 @@
final List<AppInfo> highUsageApps = BatteryDatabaseManager.getInstance(context)
.queryAllAnomalies(timeAfterMs, AnomalyDatabaseHelper.State.NEW);
// Remove it if it doesn't have label or been restricted
- highUsageApps.removeIf(
- new AppLabelPredicate(context).or(new AppRestrictionPredicate(context)));
+ highUsageApps.removeIf(AppLabelPredicate.getInstance(context)
+ .or(AppRestrictionPredicate.getInstance(context)));
return highUsageApps;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
index bda0073..e6c0837 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import androidx.annotation.VisibleForTesting;
@@ -53,8 +54,8 @@
mContext = context;
mPolicy = policy;
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
- mAppRestrictionPredicate = new AppRestrictionPredicate(context);
- mAppLabelPredicate = new AppLabelPredicate(context);
+ mAppRestrictionPredicate = AppRestrictionPredicate.getInstance(context);
+ mAppLabelPredicate = AppLabelPredicate.getInstance(context);
}
@Override
@@ -63,8 +64,8 @@
return getFakeData();
}
if (mPolicy.appRestrictionEnabled) {
- // TODO(b/80192137): hook up the query timestamp to server side
- final long oneDayBeforeMs = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS;
+ final long oneDayBeforeMs = System.currentTimeMillis()
+ - TimeUnit.HOURS.toMillis(mPolicy.appRestrictionActiveHour);
final List<AppInfo> highUsageApps = BatteryTipUtils.detectAnomalies(mContext,
oneDayBeforeMs);
if (!highUsageApps.isEmpty()) {
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/AppLabelPredicate.java b/src/com/android/settings/fuelgauge/batterytip/tips/AppLabelPredicate.java
index 13a2452..1444b12 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/AppLabelPredicate.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/AppLabelPredicate.java
@@ -16,7 +16,6 @@
package com.android.settings.fuelgauge.batterytip.tips;
-import android.app.AppOpsManager;
import android.content.Context;
import com.android.settings.Utils;
@@ -28,12 +27,20 @@
* {@link Predicate} for {@link AppInfo} to check whether it has label
*/
public class AppLabelPredicate implements Predicate<AppInfo> {
- private Context mContext;
- private AppOpsManager mAppOpsManager;
- public AppLabelPredicate(Context context) {
+ private static AppLabelPredicate sInstance;
+ private Context mContext;
+
+ public static AppLabelPredicate getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new AppLabelPredicate(context.getApplicationContext());
+ }
+
+ return sInstance;
+ }
+
+ private AppLabelPredicate(Context context) {
mContext = context;
- mAppOpsManager = context.getSystemService(AppOpsManager.class);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/AppRestrictionPredicate.java b/src/com/android/settings/fuelgauge/batterytip/tips/AppRestrictionPredicate.java
index 3650fe3..43a4d90 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/AppRestrictionPredicate.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/AppRestrictionPredicate.java
@@ -27,9 +27,19 @@
* {@link Predicate} for {@link AppInfo} to check whether it is restricted.
*/
public class AppRestrictionPredicate implements Predicate<AppInfo> {
+
+ private static AppRestrictionPredicate sInstance;
private AppOpsManager mAppOpsManager;
- public AppRestrictionPredicate(Context context) {
+ public static AppRestrictionPredicate getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new AppRestrictionPredicate(context.getApplicationContext());
+ }
+
+ return sInstance;
+ }
+
+ private AppRestrictionPredicate(Context context) {
mAppOpsManager = context.getSystemService(AppOpsManager.class);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
index 8a2d86d..0d91c74 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
@@ -112,7 +112,7 @@
super.sanityCheck(context);
// Set it invisible if there is no valid app
- mRestrictAppList.removeIf(new AppLabelPredicate(context));
+ mRestrictAppList.removeIf(AppLabelPredicate.getInstance(context));
if (mRestrictAppList.isEmpty()) {
mState = StateType.INVISIBLE;
}
diff --git a/src/com/android/settings/language/PhoneLanguagePreferenceController.java b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
index 0f9b419..8045fc0 100644
--- a/src/com/android/settings/language/PhoneLanguagePreferenceController.java
+++ b/src/com/android/settings/language/PhoneLanguagePreferenceController.java
@@ -75,7 +75,7 @@
new SubSettingLauncher(mContext)
.setDestination(LocaleListEditor.class.getName())
.setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_LANGUAGE_CATEGORY)
- .setTitleRes(R.string.pref_title_lang_selection)
+ .setTitleRes(R.string.language_picker_title)
.launch();
return true;
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 87c19dd..cbcb1eb 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -18,8 +18,10 @@
import static android.os.UserManager.DISALLOW_CONFIG_LOCALE;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
import android.os.LocaleList;
import android.view.LayoutInflater;
@@ -40,18 +42,18 @@
import java.util.List;
import java.util.Locale;
-import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
/**
* Drag-and-drop editor for the user-ordered locale lists.
*/
-public class LocaleListEditor extends RestrictedSettingsFragment
- implements LocalePickerWithRegion.LocaleSelectedListener {
+public class LocaleListEditor extends RestrictedSettingsFragment {
+ protected static final String INTENT_LOCALE_KEY = "localeInfo";
private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
private static final String CFGKEY_REMOVE_DIALOG = "showingLocaleRemoveDialog";
private static final int MENU_ID_REMOVE = Menu.FIRST + 1;
+ private static final int REQUEST_LOCALE_PICKER = 0;
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -150,6 +152,19 @@
return super.onOptionsItemSelected(menuItem);
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK
+ && data != null) {
+ final LocaleStore.LocaleInfo locale =
+ (LocaleStore.LocaleInfo) data.getSerializableExtra(
+ INTENT_LOCALE_KEY);
+ mAdapter.addLocale(locale);
+ updateVisibilityOfRemoveMenu();
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
private void setRemoveMode(boolean mRemoveMode) {
this.mRemoveMode = mRemoveMode;
mAdapter.setRemoveMode(mRemoveMode);
@@ -267,24 +282,13 @@
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
- getContext(), LocaleListEditor.this, false /* translate only */);
- getFragmentManager()
- .beginTransaction()
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
- .replace(getId(), selector)
- .addToBackStack("localeListEditor")
- .commit();
+ final Intent intent = new Intent(getActivity(),
+ LocalePickerWithRegionActivity.class);
+ startActivityForResult(intent, REQUEST_LOCALE_PICKER);
}
});
}
- @Override
- public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
- mAdapter.addLocale(locale);
- updateVisibilityOfRemoveMenu();
- }
-
// Hide the "Remove" menu if there is only one locale in the list, show it otherwise
// This is called when the menu is first created, and then one add / remove locale
private void updateVisibilityOfRemoveMenu() {
diff --git a/src/com/android/settings/localepicker/LocalePickerWithRegion.java b/src/com/android/settings/localepicker/LocalePickerWithRegion.java
deleted file mode 100644
index e8a91bc..0000000
--- a/src/com/android/settings/localepicker/LocalePickerWithRegion.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.localepicker;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.text.TextUtils;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.SearchView;
-
-import com.android.internal.R;
-import com.android.internal.app.LocaleHelper;
-import com.android.internal.app.LocalePicker;
-import com.android.internal.app.LocaleStore;
-import com.android.internal.app.SuggestedLocaleAdapter;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.fragment.app.ListFragment;
-
-/**
- * A two-step locale picker. It shows a language, then a country.
- *
- * <p>It shows suggestions at the top, then the rest of the locales.
- * Allows the user to search for locales using both their native name and their name in the
- * default locale.</p>
- */
-public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
- private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
-
- private SuggestedLocaleAdapter mAdapter;
- private LocaleSelectedListener mListener;
- private Set<LocaleStore.LocaleInfo> mLocaleList;
- private LocaleStore.LocaleInfo mParentLocale;
- private boolean mTranslatedOnly = false;
- private SearchView mSearchView = null;
- private CharSequence mPreviousSearch = null;
- private boolean mPreviousSearchHadFocus = false;
- private int mFirstVisiblePosition = 0;
- private int mTopDistance = 0;
-
- /**
- * Other classes can register to be notified when a locale was selected.
- *
- * <p>This is the mechanism to "return" the result of the selection.</p>
- */
- public interface LocaleSelectedListener {
- /**
- * The classes that want to retrieve the locale picked should implement this method.
- * @param locale the locale picked.
- */
- void onLocaleSelected(LocaleStore.LocaleInfo locale);
- }
-
- private static LocalePickerWithRegion createCountryPicker(Context context,
- LocaleSelectedListener listener, LocaleStore.LocaleInfo parent,
- boolean translatedOnly) {
- LocalePickerWithRegion
- localePicker = new LocalePickerWithRegion();
- boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
- translatedOnly);
- return shouldShowTheList ? localePicker : null;
- }
-
- public static LocalePickerWithRegion createLanguagePicker(Context context,
- LocaleSelectedListener listener, boolean translatedOnly) {
- LocalePickerWithRegion
- localePicker = new LocalePickerWithRegion();
- localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
- return localePicker;
- }
-
- /**
- * Sets the listener and initializes the locale list.
- *
- * <p>Returns true if we need to show the list, false if not.</p>
- *
- * <p>Can return false because of an error, trying to show a list of countries,
- * but no parent locale was provided.</p>
- *
- * <p>It can also return false if the caller tries to show the list in country mode and
- * there is only one country available (i.e. Japanese => Japan).
- * In this case we don't even show the list, we call the listener with that locale,
- * "pretending" it was selected, and return false.</p>
- */
- private boolean setListener(Context context, LocaleSelectedListener listener,
- LocaleStore.LocaleInfo parent, boolean translatedOnly) {
- this.mParentLocale = parent;
- this.mListener = listener;
- this.mTranslatedOnly = translatedOnly;
- setRetainInstance(true);
-
- final HashSet<String> langTagsToIgnore = new HashSet<>();
- if (!translatedOnly) {
- final LocaleList userLocales = LocalePicker.getLocales();
- final String[] langTags = userLocales.toLanguageTags().split(",");
- Collections.addAll(langTagsToIgnore, langTags);
- }
-
- if (parent != null) {
- mLocaleList = LocaleStore.getLevelLocales(context,
- langTagsToIgnore, parent, translatedOnly);
- if (mLocaleList.size() <= 1) {
- if (listener != null && (mLocaleList.size() == 1)) {
- listener.onLocaleSelected(mLocaleList.iterator().next());
- }
- return false;
- }
- } else {
- mLocaleList = LocaleStore.getLevelLocales(context, langTagsToIgnore,
- null /* no parent */, translatedOnly);
- }
-
- return true;
- }
-
- private void returnToParentFrame() {
- getFragmentManager().popBackStack(PARENT_FRAGMENT_NAME,
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
-
- if (mLocaleList == null) {
- // The fragment was killed and restored by the FragmentManager.
- // At this point we have no data, no listener. Just return, to prevend a NPE.
- // Fixes b/28748150. Created b/29400003 for a cleaner solution.
- returnToParentFrame();
- return;
- }
-
- final boolean countryMode = mParentLocale != null;
- final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
- mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
- final LocaleHelper.LocaleInfoComparator comp =
- new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
- mAdapter.sort(comp);
- setListAdapter(mAdapter);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- int id = menuItem.getItemId();
- switch (id) {
- case android.R.id.home:
- getFragmentManager().popBackStack();
- return true;
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (mParentLocale != null) {
- getActivity().setTitle(mParentLocale.getFullNameNative());
- } else {
- getActivity().setTitle(R.string.language_selection_title);
- }
-
- getListView().requestFocus();
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- // Save search status
- if (mSearchView != null) {
- mPreviousSearchHadFocus = mSearchView.hasFocus();
- mPreviousSearch = mSearchView.getQuery();
- } else {
- mPreviousSearchHadFocus = false;
- mPreviousSearch = null;
- }
-
- // Save scroll position
- final ListView list = getListView();
- final View firstChild = list.getChildAt(0);
- mFirstVisiblePosition = list.getFirstVisiblePosition();
- mTopDistance = (firstChild == null) ? 0 : (firstChild.getTop() - list.getPaddingTop());
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- final LocaleStore.LocaleInfo locale =
- (LocaleStore.LocaleInfo) getListAdapter().getItem(position);
-
- if (locale.getParent() != null) {
- if (mListener != null) {
- mListener.onLocaleSelected(locale);
- }
- returnToParentFrame();
- } else {
- LocalePickerWithRegion
- selector = LocalePickerWithRegion.createCountryPicker(
- getContext(), mListener, locale, mTranslatedOnly /* translate only */);
- if (selector != null) {
- getFragmentManager().beginTransaction()
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
- .replace(getId(), selector).addToBackStack(null)
- .commit();
- } else {
- returnToParentFrame();
- }
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if (mParentLocale == null) {
- inflater.inflate(R.menu.language_selection_list, menu);
-
- final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu);
- mSearchView = (SearchView) searchMenuItem.getActionView();
-
- mSearchView.setQueryHint(getText(R.string.search_language_hint));
- mSearchView.setOnQueryTextListener(this);
-
- // Restore previous search status
- if (!TextUtils.isEmpty(mPreviousSearch)) {
- searchMenuItem.expandActionView();
- mSearchView.setIconified(false);
- mSearchView.setActivated(true);
- if (mPreviousSearchHadFocus) {
- mSearchView.requestFocus();
- }
- mSearchView.setQuery(mPreviousSearch, true /* submit */);
- } else {
- mSearchView.setQuery(null, false /* submit */);
- }
-
- // Restore previous scroll position
- getListView().setSelectionFromTop(mFirstVisiblePosition, mTopDistance);
- }
- }
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- if (mAdapter != null) {
- mAdapter.getFilter().filter(newText);
- }
- return false;
- }
-}
diff --git a/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java
new file mode 100644
index 0000000..6ddcf23
--- /dev/null
+++ b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.localepicker;
+
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import com.android.internal.app.LocalePickerWithRegion;
+import com.android.internal.app.LocaleStore;
+
+public class LocalePickerWithRegionActivity extends Activity
+ implements LocalePickerWithRegion.LocaleSelectedListener {
+
+ private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
+ this, LocalePickerWithRegionActivity.this, false /* translate only */);
+ getFragmentManager()
+ .beginTransaction()
+ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
+ .replace(android.R.id.content, selector)
+ .addToBackStack(PARENT_FRAGMENT_NAME)
+ .commit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ handleBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
+ final Intent intent = new Intent();
+ intent.putExtra(LocaleListEditor.INTENT_LOCALE_KEY, locale);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ handleBackPressed();
+ }
+
+ private void handleBackPressed() {
+ if (getFragmentManager().getBackStackEntryCount() > 1) {
+ super.onBackPressed();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+}
+
diff --git a/src/com/android/settings/location/AppSettingsInjector.java b/src/com/android/settings/location/AppSettingsInjector.java
new file mode 100644
index 0000000..6b79a7e
--- /dev/null
+++ b/src/com/android/settings/location/AppSettingsInjector.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.location;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+
+import com.android.settings.widget.AppPreference;
+import com.android.settings.widget.RestrictedAppPreference;
+import com.android.settingslib.location.InjectedSetting;
+import com.android.settingslib.location.SettingsInjector;
+
+import java.util.List;
+
+/**
+ * Adds the preferences specified by the {@link InjectedSetting} objects to a preference group.
+ */
+public class AppSettingsInjector extends SettingsInjector {
+
+ public AppSettingsInjector(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected Preference createPreference(Context prefContext, InjectedSetting setting) {
+ return TextUtils.isEmpty(setting.userRestriction)
+ ? new AppPreference(prefContext)
+ : new RestrictedAppPreference(prefContext, setting.userRestriction);
+ }
+}
diff --git a/src/com/android/settings/location/InjectedSetting.java b/src/com/android/settings/location/InjectedSetting.java
deleted file mode 100644
index 4877cb4..0000000
--- a/src/com/android/settings/location/InjectedSetting.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2013 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.location;
-
-import android.content.Intent;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.Immutable;
-
-import java.util.Objects;
-
-/**
- * Specifies a setting that is being injected into Settings > Location > Location services.
- *
- * @see android.location.SettingInjectorService
- */
-@Immutable
-class InjectedSetting {
-
- /**
- * Package for the subclass of {@link android.location.SettingInjectorService} and for the
- * settings activity.
- */
- public final String packageName;
-
- /**
- * Class name for the subclass of {@link android.location.SettingInjectorService} that
- * specifies dynamic values for the location setting.
- */
- public final String className;
-
- /**
- * The {@link androidx.preference.Preference#getTitle()} value.
- */
- public final String title;
-
- /**
- * The {@link androidx.preference.Preference#getIcon()} value.
- */
- public final int iconId;
-
- /**
- * The user/profile associated with this setting (e.g. managed profile)
- */
- public final UserHandle mUserHandle;
-
- /**
- * The activity to launch to allow the user to modify the settings value. Assumed to be in the
- * {@link #packageName} package.
- */
- public final String settingsActivity;
-
- /**
- * The user restriction associated with this setting.
- */
- public final String userRestriction;
-
- private InjectedSetting(Builder builder) {
- this.packageName = builder.mPackageName;
- this.className = builder.mClassName;
- this.title = builder.mTitle;
- this.iconId = builder.mIconId;
- this.mUserHandle = builder.mUserHandle;
- this.settingsActivity = builder.mSettingsActivity;
- this.userRestriction = builder.mUserRestriction;
- }
-
- @Override
- public String toString() {
- return "InjectedSetting{" +
- "mPackageName='" + packageName + '\'' +
- ", mClassName='" + className + '\'' +
- ", label=" + title +
- ", iconId=" + iconId +
- ", userId=" + mUserHandle.getIdentifier() +
- ", settingsActivity='" + settingsActivity + '\'' +
- ", userRestriction='" + userRestriction +
- '}';
- }
-
- /**
- * Returns the intent to start the {@link #className} service.
- */
- public Intent getServiceIntent() {
- Intent intent = new Intent();
- intent.setClassName(packageName, className);
- return intent;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof InjectedSetting)) return false;
-
- InjectedSetting that = (InjectedSetting) o;
-
- return Objects.equals(packageName, that.packageName)
- && Objects.equals(className, that.className)
- && Objects.equals(title, that.title)
- && Objects.equals(iconId, that.iconId)
- && Objects.equals(mUserHandle, that.mUserHandle)
- && Objects.equals(settingsActivity, that.settingsActivity)
- && Objects.equals(userRestriction, that.userRestriction);
- }
-
- @Override
- public int hashCode() {
- int result = packageName.hashCode();
- result = 31 * result + className.hashCode();
- result = 31 * result + title.hashCode();
- result = 31 * result + iconId;
- result = 31 * result + (mUserHandle == null ? 0 : mUserHandle.hashCode());
- result = 31 * result + settingsActivity.hashCode();
- result = 31 * result + (userRestriction == null ? 0 : userRestriction.hashCode());
- return result;
- }
-
- public static class Builder {
- private String mPackageName;
- private String mClassName;
- private String mTitle;
- private int mIconId;
- private UserHandle mUserHandle;
- private String mSettingsActivity;
- private String mUserRestriction;
-
- public Builder setPackageName(String packageName) {
- mPackageName = packageName;
- return this;
- }
-
- public Builder setClassName(String className) {
- mClassName = className;
- return this;
- }
-
- public Builder setTitle(String title) {
- mTitle = title;
- return this;
- }
-
- public Builder setIconId(int iconId) {
- mIconId = iconId;
- return this;
- }
-
- public Builder setUserHandle(UserHandle userHandle) {
- mUserHandle = userHandle;
- return this;
- }
-
- public Builder setSettingsActivity(String settingsActivity) {
- mSettingsActivity = settingsActivity;
- return this;
- }
-
- public Builder setUserRestriction(String userRestriction) {
- mUserRestriction = userRestriction;
- return this;
- }
-
- public InjectedSetting build() {
- if (mPackageName == null || mClassName == null || TextUtils.isEmpty(mTitle)
- || TextUtils.isEmpty(mSettingsActivity)) {
- if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
- Log.w(SettingsInjector.TAG, "Illegal setting specification: package="
- + mPackageName + ", class=" + mClassName
- + ", title=" + mTitle + ", settingsActivity=" + mSettingsActivity);
- }
- return null;
- }
- return new InjectedSetting(this);
- }
- }
-}
diff --git a/src/com/android/settings/location/LocationServicePreferenceController.java b/src/com/android/settings/location/LocationServicePreferenceController.java
index 67ec152..035faad 100644
--- a/src/com/android/settings/location/LocationServicePreferenceController.java
+++ b/src/com/android/settings/location/LocationServicePreferenceController.java
@@ -47,19 +47,19 @@
private PreferenceCategory mCategoryLocationServices;
private final LocationSettings mFragment;
- private final SettingsInjector mInjector;
+ private final AppSettingsInjector mInjector;
/** Receives UPDATE_INTENT */
@VisibleForTesting
BroadcastReceiver mInjectedSettingsReceiver;
public LocationServicePreferenceController(Context context, LocationSettings fragment,
Lifecycle lifecycle) {
- this(context, fragment, lifecycle, new SettingsInjector(context));
+ this(context, fragment, lifecycle, new AppSettingsInjector(context));
}
@VisibleForTesting
LocationServicePreferenceController(Context context, LocationSettings fragment,
- Lifecycle lifecycle, SettingsInjector injector) {
+ Lifecycle lifecycle, AppSettingsInjector injector) {
super(context, lifecycle);
mFragment = fragment;
mInjector = injector;
diff --git a/src/com/android/settings/location/SettingsInjector.java b/src/com/android/settings/location/SettingsInjector.java
deleted file mode 100644
index 1206e85..0000000
--- a/src/com/android/settings/location/SettingsInjector.java
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright (C) 2013 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.location;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
-import android.location.SettingInjectorService;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.IconDrawableFactory;
-import android.util.Log;
-import android.util.Xml;
-
-import com.android.settings.widget.AppPreference;
-import com.android.settings.widget.RestrictedAppPreference;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import androidx.preference.Preference;
-
-/**
- * Adds the preferences specified by the {@link InjectedSetting} objects to a preference group.
- *
- * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. We do not use that
- * class directly because it is not a good match for our use case: we do not need the caching, and
- * so do not want the additional resource hit at app install/upgrade time; and we would have to
- * suppress the tie-breaking between multiple services reporting settings with the same name.
- * Code-sharing would require extracting {@link
- * android.content.pm.RegisteredServicesCache#parseServiceAttributes(android.content.res.Resources,
- * String, android.util.AttributeSet)} into an interface, which didn't seem worth it.
- */
-class SettingsInjector {
- static final String TAG = "SettingsInjector";
-
- /**
- * If reading the status of a setting takes longer than this, we go ahead and start reading
- * the next setting.
- */
- private static final long INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS = 1000;
-
- /**
- * {@link Message#what} value for starting to load status values
- * in case we aren't already in the process of loading them.
- */
- private static final int WHAT_RELOAD = 1;
-
- /**
- * {@link Message#what} value sent after receiving a status message.
- */
- private static final int WHAT_RECEIVED_STATUS = 2;
-
- /**
- * {@link Message#what} value sent after the timeout waiting for a status message.
- */
- private static final int WHAT_TIMEOUT = 3;
-
- private final Context mContext;
-
- /**
- * The settings that were injected
- */
- private final Set<Setting> mSettings;
-
- private final Handler mHandler;
-
- public SettingsInjector(Context context) {
- mContext = context;
- mSettings = new HashSet<Setting>();
- mHandler = new StatusLoadingHandler();
- }
-
- /**
- * Returns a list for a profile with one {@link InjectedSetting} object for each
- * {@link android.app.Service} that responds to
- * {@link SettingInjectorService#ACTION_SERVICE_INTENT} and provides the expected setting
- * metadata.
- *
- * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
- *
- * TODO: unit test
- */
- private List<InjectedSetting> getSettings(final UserHandle userHandle) {
- PackageManager pm = mContext.getPackageManager();
- Intent intent = new Intent(SettingInjectorService.ACTION_SERVICE_INTENT);
-
- final int profileId = userHandle.getIdentifier();
- List<ResolveInfo> resolveInfos =
- pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, profileId);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Found services for profile id " + profileId + ": " + resolveInfos);
- }
- List<InjectedSetting> settings = new ArrayList<InjectedSetting>(resolveInfos.size());
- for (ResolveInfo resolveInfo : resolveInfos) {
- try {
- InjectedSetting setting = parseServiceInfo(resolveInfo, userHandle, pm);
- if (setting == null) {
- Log.w(TAG, "Unable to load service info " + resolveInfo);
- } else {
- settings.add(setting);
- }
- } catch (XmlPullParserException e) {
- Log.w(TAG, "Unable to load service info " + resolveInfo, e);
- } catch (IOException e) {
- Log.w(TAG, "Unable to load service info " + resolveInfo, e);
- }
- }
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Loaded settings for profile id " + profileId + ": " + settings);
- }
-
- return settings;
- }
-
- /**
- * Returns the settings parsed from the attributes of the
- * {@link SettingInjectorService#META_DATA_NAME} tag, or null.
- *
- * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
- */
- private static InjectedSetting parseServiceInfo(ResolveInfo service, UserHandle userHandle,
- PackageManager pm) throws XmlPullParserException, IOException {
-
- ServiceInfo si = service.serviceInfo;
- ApplicationInfo ai = si.applicationInfo;
-
- if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "Ignoring attempt to inject setting from app not in system image: "
- + service);
- return null;
- }
- }
-
- XmlResourceParser parser = null;
- try {
- parser = si.loadXmlMetaData(pm, SettingInjectorService.META_DATA_NAME);
- if (parser == null) {
- throw new XmlPullParserException("No " + SettingInjectorService.META_DATA_NAME
- + " meta-data for " + service + ": " + si);
- }
-
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- }
-
- String nodeName = parser.getName();
- if (!SettingInjectorService.ATTRIBUTES_NAME.equals(nodeName)) {
- throw new XmlPullParserException("Meta-data does not start with "
- + SettingInjectorService.ATTRIBUTES_NAME + " tag");
- }
-
- Resources res = pm.getResourcesForApplicationAsUser(si.packageName,
- userHandle.getIdentifier());
- return parseAttributes(si.packageName, si.name, userHandle, res, attrs);
- } catch (PackageManager.NameNotFoundException e) {
- throw new XmlPullParserException(
- "Unable to load resources for package " + si.packageName);
- } finally {
- if (parser != null) {
- parser.close();
- }
- }
- }
-
- /**
- * Returns an immutable representation of the static attributes for the setting, or null.
- */
- private static InjectedSetting parseAttributes(String packageName, String className,
- UserHandle userHandle, Resources res, AttributeSet attrs) {
-
- TypedArray sa = res.obtainAttributes(attrs, android.R.styleable.SettingInjectorService);
- try {
- // Note that to help guard against malicious string injection, we do not allow dynamic
- // specification of the label (setting title)
- final String title = sa.getString(android.R.styleable.SettingInjectorService_title);
- final int iconId =
- sa.getResourceId(android.R.styleable.SettingInjectorService_icon, 0);
- final String settingsActivity =
- sa.getString(android.R.styleable.SettingInjectorService_settingsActivity);
- final String userRestriction = sa.getString(
- android.R.styleable.SettingInjectorService_userRestriction);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "parsed title: " + title + ", iconId: " + iconId
- + ", settingsActivity: " + settingsActivity);
- }
- return new InjectedSetting.Builder()
- .setPackageName(packageName)
- .setClassName(className)
- .setTitle(title)
- .setIconId(iconId)
- .setUserHandle(userHandle)
- .setSettingsActivity(settingsActivity)
- .setUserRestriction(userRestriction)
- .build();
- } finally {
- sa.recycle();
- }
- }
-
- /**
- * Gets a list of preferences that other apps have injected.
- *
- * @param profileId Identifier of the user/profile to obtain the injected settings for or
- * UserHandle.USER_CURRENT for all profiles associated with current user.
- */
- public List<Preference> getInjectedSettings(Context prefContext, final int profileId) {
- final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- final List<UserHandle> profiles = um.getUserProfiles();
- ArrayList<Preference> prefs = new ArrayList<>();
- final int profileCount = profiles.size();
- for (int i = 0; i < profileCount; ++i) {
- final UserHandle userHandle = profiles.get(i);
- if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
- Iterable<InjectedSetting> settings = getSettings(userHandle);
- for (InjectedSetting setting : settings) {
- Preference pref = addServiceSetting(prefContext, prefs, setting);
- mSettings.add(new Setting(setting, pref));
- }
- }
- }
-
- reloadStatusMessages();
-
- return prefs;
- }
-
- /**
- * Checks wheteher there is any preference that other apps have injected.
- *
- * @param profileId Identifier of the user/profile to obtain the injected settings for or
- * UserHandle.USER_CURRENT for all profiles associated with current user.
- */
- public boolean hasInjectedSettings(final int profileId) {
- final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- final List<UserHandle> profiles = um.getUserProfiles();
- final int profileCount = profiles.size();
- for (int i = 0; i < profileCount; ++i) {
- final UserHandle userHandle = profiles.get(i);
- if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
- Iterable<InjectedSetting> settings = getSettings(userHandle);
- for (InjectedSetting setting : settings) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Reloads the status messages for all the preference items.
- */
- public void reloadStatusMessages() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "reloadingStatusMessages: " + mSettings);
- }
- mHandler.sendMessage(mHandler.obtainMessage(WHAT_RELOAD));
- }
-
- /**
- * Adds an injected setting to the root.
- */
- private Preference addServiceSetting(Context prefContext, List<Preference> prefs,
- InjectedSetting info) {
- final PackageManager pm = mContext.getPackageManager();
- Drawable appIcon = null;
- try {
- final PackageItemInfo itemInfo = new PackageItemInfo();
- itemInfo.icon = info.iconId;
- itemInfo.packageName = info.packageName;
- final ApplicationInfo appInfo = pm.getApplicationInfo(info.packageName,
- PackageManager.GET_META_DATA);
- appIcon = IconDrawableFactory.newInstance(mContext)
- .getBadgedIcon(itemInfo, appInfo, info.mUserHandle.getIdentifier());
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Can't get ApplicationInfo for " + info.packageName, e);
- }
- Preference pref = TextUtils.isEmpty(info.userRestriction)
- ? new AppPreference(prefContext)
- : new RestrictedAppPreference(prefContext, info.userRestriction);
- pref.setTitle(info.title);
- pref.setSummary(null);
- pref.setIcon(appIcon);
- pref.setOnPreferenceClickListener(new ServiceSettingClickedListener(info));
- prefs.add(pref);
- return pref;
- }
-
- private class ServiceSettingClickedListener
- implements Preference.OnPreferenceClickListener {
- private InjectedSetting mInfo;
-
- public ServiceSettingClickedListener(InjectedSetting info) {
- mInfo = info;
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- // Activity to start if they click on the preference. Must start in new task to ensure
- // that "android.settings.LOCATION_SOURCE_SETTINGS" brings user back to
- // Settings > Location.
- Intent settingIntent = new Intent();
- settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity);
- // Sometimes the user may navigate back to "Settings" and launch another different
- // injected setting after one injected setting has been launched.
- //
- // FLAG_ACTIVITY_CLEAR_TOP allows multiple Activities to stack on each other. When
- // "back" button is clicked, the user will navigate through all the injected settings
- // launched before. Such behavior could be quite confusing sometimes.
- //
- // In order to avoid such confusion, we use FLAG_ACTIVITY_CLEAR_TASK, which always clear
- // up all existing injected settings and make sure that "back" button always brings the
- // user back to "Settings" directly.
- settingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- mContext.startActivityAsUser(settingIntent, mInfo.mUserHandle);
- return true;
- }
- }
-
- /**
- * Loads the setting status values one at a time. Each load starts a subclass of {@link
- * SettingInjectorService}, so to reduce memory pressure we don't want to load too many at
- * once.
- */
- private final class StatusLoadingHandler extends Handler {
-
- /**
- * Settings whose status values need to be loaded. A set is used to prevent redundant loads.
- */
- private Set<Setting> mSettingsToLoad = new HashSet<Setting>();
-
- /**
- * Settings that are being loaded now and haven't timed out. In practice this should have
- * zero or one elements.
- */
- private Set<Setting> mSettingsBeingLoaded = new HashSet<Setting>();
-
- /**
- * Settings that are being loaded but have timed out. If only one setting has timed out, we
- * will go ahead and start loading the next setting so that one slow load won't delay the
- * load of the other settings.
- */
- private Set<Setting> mTimedOutSettings = new HashSet<Setting>();
-
- private boolean mReloadRequested;
-
- private StatusLoadingHandler() {
- super(Looper.getMainLooper());
- }
- @Override
- public void handleMessage(Message msg) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "handleMessage start: " + msg + ", " + this);
- }
-
- // Update state in response to message
- switch (msg.what) {
- case WHAT_RELOAD:
- mReloadRequested = true;
- break;
- case WHAT_RECEIVED_STATUS:
- final Setting receivedSetting = (Setting) msg.obj;
- receivedSetting.maybeLogElapsedTime();
- mSettingsBeingLoaded.remove(receivedSetting);
- mTimedOutSettings.remove(receivedSetting);
- removeMessages(WHAT_TIMEOUT, receivedSetting);
- break;
- case WHAT_TIMEOUT:
- final Setting timedOutSetting = (Setting) msg.obj;
- mSettingsBeingLoaded.remove(timedOutSetting);
- mTimedOutSettings.add(timedOutSetting);
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "Timed out after " + timedOutSetting.getElapsedTime()
- + " millis trying to get status for: " + timedOutSetting);
- }
- break;
- default:
- Log.wtf(TAG, "Unexpected what: " + msg);
- }
-
- // Decide whether to load additional settings based on the new state. Start by seeing
- // if we have headroom to load another setting.
- if (mSettingsBeingLoaded.size() > 0 || mTimedOutSettings.size() > 1) {
- // Don't load any more settings until one of the pending settings has completed.
- // To reduce memory pressure, we want to be loading at most one setting (plus at
- // most one timed-out setting) at a time. This means we'll be responsible for
- // bringing in at most two services.
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "too many services already live for " + msg + ", " + this);
- }
- return;
- }
-
- if (mReloadRequested && mSettingsToLoad.isEmpty() && mSettingsBeingLoaded.isEmpty()
- && mTimedOutSettings.isEmpty()) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "reloading because idle and reload requesteed " + msg + ", " + this);
- }
- // Reload requested, so must reload all settings
- mSettingsToLoad.addAll(mSettings);
- mReloadRequested = false;
- }
-
- // Remove the next setting to load from the queue, if any
- Iterator<Setting> iter = mSettingsToLoad.iterator();
- if (!iter.hasNext()) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "nothing left to do for " + msg + ", " + this);
- }
- return;
- }
- Setting setting = iter.next();
- iter.remove();
-
- // Request the status value
- setting.startService();
- mSettingsBeingLoaded.add(setting);
-
- // Ensure that if receiving the status value takes too long, we start loading the
- // next value anyway
- Message timeoutMsg = obtainMessage(WHAT_TIMEOUT, setting);
- sendMessageDelayed(timeoutMsg, INJECTED_STATUS_UPDATE_TIMEOUT_MILLIS);
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "handleMessage end " + msg + ", " + this
- + ", started loading " + setting);
- }
- }
-
- @Override
- public String toString() {
- return "StatusLoadingHandler{" +
- "mSettingsToLoad=" + mSettingsToLoad +
- ", mSettingsBeingLoaded=" + mSettingsBeingLoaded +
- ", mTimedOutSettings=" + mTimedOutSettings +
- ", mReloadRequested=" + mReloadRequested +
- '}';
- }
- }
-
- /**
- * Represents an injected setting and the corresponding preference.
- */
- private final class Setting {
-
- public final InjectedSetting setting;
- public final Preference preference;
- public long startMillis;
-
- private Setting(InjectedSetting setting, Preference preference) {
- this.setting = setting;
- this.preference = preference;
- }
-
- @Override
- public String toString() {
- return "Setting{" +
- "setting=" + setting +
- ", preference=" + preference +
- '}';
- }
-
- /**
- * Returns true if they both have the same {@link #setting} value. Ignores mutable
- * {@link #preference} and {@link #startMillis} so that it's safe to use in sets.
- */
- @Override
- public boolean equals(Object o) {
- return this == o || o instanceof Setting && setting.equals(((Setting) o).setting);
- }
-
- @Override
- public int hashCode() {
- return setting.hashCode();
- }
-
- /**
- * Starts the service to fetch for the current status for the setting, and updates the
- * preference when the service replies.
- */
- public void startService() {
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- if (!am.isUserRunning(setting.mUserHandle.getIdentifier())) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Cannot start service as user "
- + setting.mUserHandle.getIdentifier() + " is not running");
- }
- return;
- }
- Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Bundle bundle = msg.getData();
- boolean enabled = bundle.getBoolean(SettingInjectorService.ENABLED_KEY, true);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, setting + ": received " + msg + ", bundle: " + bundle);
- }
- preference.setSummary(null);
- preference.setEnabled(enabled);
- mHandler.sendMessage(
- mHandler.obtainMessage(WHAT_RECEIVED_STATUS, Setting.this));
- }
- };
- Messenger messenger = new Messenger(handler);
-
- Intent intent = setting.getServiceIntent();
- intent.putExtra(SettingInjectorService.MESSENGER_KEY, messenger);
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, setting + ": sending update intent: " + intent
- + ", handler: " + handler);
- startMillis = SystemClock.elapsedRealtime();
- } else {
- startMillis = 0;
- }
-
- // Start the service, making sure that this is attributed to the user associated with
- // the setting rather than the system user.
- mContext.startServiceAsUser(intent, setting.mUserHandle);
- }
-
- public long getElapsedTime() {
- long end = SystemClock.elapsedRealtime();
- return end - startMillis;
- }
-
- public void maybeLogElapsedTime() {
- if (Log.isLoggable(TAG, Log.DEBUG) && startMillis != 0) {
- long elapsed = getElapsedTime();
- Log.d(TAG, this + " update took " + elapsed + " millis");
- }
- }
- }
-}
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 17739f9..ad721ba 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -23,10 +23,12 @@
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
+import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
@@ -62,6 +64,18 @@
private NotificationManager mNm;
@Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ final Context ctx = getContext();
+ if (UserManager.get(ctx).isManagedProfile()) {
+ // Apps in the work profile do not support notification listeners.
+ Toast.makeText(ctx, R.string.notification_settings_work_profile, Toast.LENGTH_SHORT)
+ .show();
+ finish();
+ }
+ }
+
+ @Override
public int getMetricsCategory() {
return MetricsEvent.NOTIFICATION_ACCESS;
}
diff --git a/src/com/android/settings/print/PrintServiceSettingsFragment.java b/src/com/android/settings/print/PrintServiceSettingsFragment.java
index 4629360..1311be0 100644
--- a/src/com/android/settings/print/PrintServiceSettingsFragment.java
+++ b/src/com/android/settings/print/PrintServiceSettingsFragment.java
@@ -22,9 +22,6 @@
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.pm.ResolveInfo;
-import android.database.DataSetObserver;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.print.PrintManager;
@@ -44,13 +41,10 @@
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.ListView;
import android.widget.SearchView;
import android.widget.Switch;
import android.widget.TextView;
@@ -67,8 +61,11 @@
import java.util.List;
import java.util.Map;
+import androidx.annotation.NonNull;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
/**
* Fragment with print service settings.
@@ -77,23 +74,18 @@
implements SwitchBar.OnSwitchChangeListener,
LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
- private static final String LOG_TAG = "PrintServiceSettingsFragment";
+ private static final String LOG_TAG = "PrintServiceSettings";
private static final int LOADER_ID_PRINTERS_LOADER = 1;
private static final int LOADER_ID_PRINT_SERVICE_LOADER = 2;
- private final DataSetObserver mDataObserver = new DataSetObserver() {
+ private final AdapterDataObserver mDataObserver = new AdapterDataObserver() {
@Override
public void onChanged() {
invalidateOptionsMenuIfNeeded();
updateEmptyView();
}
- @Override
- public void onInvalidated() {
- invalidateOptionsMenuIfNeeded();
- }
-
private void invalidateOptionsMenuIfNeeded() {
final int unfilteredItemCount = mPrintersAdapter.getUnfilteredCount();
if ((mLastUnfilteredItemCount <= 0 && unfilteredItemCount > 0)
@@ -173,8 +165,6 @@
super.onViewCreated(view, savedInstanceState);
initComponents();
updateUiForArguments();
- getListView().setVisibility(View.GONE);
- getBackupListView().setVisibility(View.VISIBLE);
}
@Override
@@ -189,15 +179,11 @@
.setPrintServiceEnabled(mComponentName, enabled);
}
- private ListView getBackupListView() {
- return (ListView) getView().findViewById(R.id.backup_list);
- }
-
private void updateEmptyView() {
ViewGroup contentRoot = (ViewGroup) getListView().getParent();
- View emptyView = getBackupListView().getEmptyView();
+ View emptyView = getEmptyView();
if (!mToggleSwitch.isChecked()) {
- if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
+ if (emptyView != null) {
contentRoot.removeView(emptyView);
emptyView = null;
}
@@ -209,11 +195,10 @@
TextView textView = (TextView) emptyView.findViewById(R.id.message);
textView.setText(R.string.print_service_disabled);
contentRoot.addView(emptyView);
- getBackupListView().setEmptyView(emptyView);
+ setEmptyView(emptyView);
}
} else if (mPrintersAdapter.getUnfilteredCount() <= 0) {
- if (emptyView != null
- && emptyView.getId() != R.id.empty_printers_list_service_enabled) {
+ if (emptyView != null) {
contentRoot.removeView(emptyView);
emptyView = null;
}
@@ -221,10 +206,10 @@
emptyView = getActivity().getLayoutInflater().inflate(
R.layout.empty_printers_list_service_enabled, contentRoot, false);
contentRoot.addView(emptyView);
- getBackupListView().setEmptyView(emptyView);
+ setEmptyView(emptyView);
}
- } else if (mPrintersAdapter.getCount() <= 0) {
- if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
+ } else if (mPrintersAdapter.getItemCount() <= 0) {
+ if (emptyView != null) {
contentRoot.removeView(emptyView);
emptyView = null;
}
@@ -236,7 +221,11 @@
TextView textView = (TextView) emptyView.findViewById(R.id.message);
textView.setText(R.string.print_no_printers_found);
contentRoot.addView(emptyView);
- getBackupListView().setEmptyView(emptyView);
+ setEmptyView(emptyView);
+ }
+ } else if (mPrintersAdapter.getItemCount() > 0) {
+ if (emptyView != null) {
+ contentRoot.removeView(emptyView);
}
}
}
@@ -254,7 +243,7 @@
private void initComponents() {
mPrintersAdapter = new PrintersAdapter();
- mPrintersAdapter.registerDataSetObserver(mDataObserver);
+ mPrintersAdapter.registerAdapterDataObserver(mDataObserver);
final SettingsActivity activity = (SettingsActivity) getActivity();
@@ -263,31 +252,12 @@
mSwitchBar.show();
mToggleSwitch = mSwitchBar.getSwitch();
- mToggleSwitch.setOnBeforeCheckedChangeListener(new ToggleSwitch.OnBeforeCheckedChangeListener() {
- @Override
- public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
- onPreferenceToggled(mPreferenceKey, checked);
- return false;
- }
+ mToggleSwitch.setOnBeforeCheckedChangeListener((toggleSwitch, checked) -> {
+ onPreferenceToggled(mPreferenceKey, checked);
+ return false;
});
- getBackupListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
- getBackupListView().setAdapter(mPrintersAdapter);
- getBackupListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- PrinterInfo printer = (PrinterInfo) mPrintersAdapter.getItem(position);
-
- if (printer.getInfoIntent() != null) {
- try {
- getActivity().startIntentSender(printer.getInfoIntent().getIntentSender(),
- null, 0, 0, 0);
- } catch (SendIntentException e) {
- Log.e(LOG_TAG, "Could not execute info intent: %s", e);
- }
- }
- }
- });
+ getListView().setAdapter(mPrintersAdapter);
}
@@ -446,8 +416,17 @@
}
}
- private final class PrintersAdapter extends BaseAdapter
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+
+ public ViewHolder(@NonNull View itemView) {
+ super(itemView);
+ }
+ }
+
+
+ private final class PrintersAdapter extends RecyclerView.Adapter<ViewHolder>
implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable {
+
private final Object mLock = new Object();
private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
@@ -509,19 +488,19 @@
}
}
notifyDataSetChanged();
+
}
};
}
@Override
- public int getCount() {
+ public int getItemCount() {
synchronized (mLock) {
return mFilteredPrinters.size();
}
}
- @Override
- public Object getItem(int position) {
+ private Object getItem(int position) {
synchronized (mLock) {
return mFilteredPrinters.get(position);
}
@@ -543,24 +522,27 @@
return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
}
+ @NonNull
@Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = getActivity().getLayoutInflater().inflate(
- R.layout.printer_dropdown_item, parent, false);
- }
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ final View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.printer_dropdown_item, parent, false);
+ return new ViewHolder(view);
+ }
- convertView.setEnabled(isActionable(position));
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ holder.itemView.setEnabled(isActionable(position));
final PrinterInfo printer = (PrinterInfo) getItem(position);
CharSequence title = printer.getName();
CharSequence subtitle = printer.getDescription();
Drawable icon = printer.loadIcon(getActivity());
- TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ TextView titleView = holder.itemView.findViewById(R.id.title);
titleView.setText(title);
- TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
+ TextView subtitleView = holder.itemView.findViewById(R.id.subtitle);
if (!TextUtils.isEmpty(subtitle)) {
subtitleView.setText(subtitle);
subtitleView.setVisibility(View.VISIBLE);
@@ -569,7 +551,7 @@
subtitleView.setVisibility(View.GONE);
}
- LinearLayout moreInfoView = (LinearLayout) convertView.findViewById(R.id.more_info);
+ LinearLayout moreInfoView = holder.itemView.findViewById(R.id.more_info);
if (printer.getInfoIntent() != null) {
moreInfoView.setVisibility(View.VISIBLE);
moreInfoView.setOnClickListener(new OnClickListener() {
@@ -587,7 +569,7 @@
moreInfoView.setVisibility(View.GONE);
}
- ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+ ImageView iconView = holder.itemView.findViewById(R.id.icon);
if (icon != null) {
iconView.setVisibility(View.VISIBLE);
if (!isActionable(position)) {
@@ -603,7 +585,18 @@
iconView.setVisibility(View.GONE);
}
- return convertView;
+ holder.itemView.setOnClickListener(v -> {
+ PrinterInfo pi = (PrinterInfo) getItem(position);
+
+ if (pi.getInfoIntent() != null) {
+ try {
+ getActivity().startIntentSender(pi.getInfoIntent().getIntentSender(),
+ null, 0, 0, 0);
+ } catch (SendIntentException e) {
+ Log.e(LOG_TAG, "Could not execute info intent: %s", e);
+ }
+ }
+ });
}
@Override
@@ -642,7 +635,7 @@
mFilteredPrinters.clear();
mLastSearchString = null;
}
- notifyDataSetInvalidated();
+ notifyDataSetChanged();
}
}
diff --git a/src/com/android/settings/wifi/LongPressAccessPointPreference.java b/src/com/android/settings/wifi/LongPressAccessPointPreference.java
index 579d848..85fd800 100644
--- a/src/com/android/settings/wifi/LongPressAccessPointPreference.java
+++ b/src/com/android/settings/wifi/LongPressAccessPointPreference.java
@@ -28,12 +28,6 @@
private final Fragment mFragment;
public LongPressAccessPointPreference(AccessPoint accessPoint, Context context,
- UserBadgeCache cache, boolean forSavedNetworks, Fragment fragment) {
- super(accessPoint, context, cache, forSavedNetworks);
- mFragment = fragment;
- }
-
- public LongPressAccessPointPreference(AccessPoint accessPoint, Context context,
UserBadgeCache cache, boolean forSavedNetworks, int iconResId, Fragment fragment) {
super(accessPoint, context, cache, iconResId, forSavedNetworks);
mFragment = fragment;
diff --git a/src/com/android/settings/wifi/WifiPickerActivity.java b/src/com/android/settings/wifi/WifiPickerActivity.java
index ca392ce..f7c4f79 100644
--- a/src/com/android/settings/wifi/WifiPickerActivity.java
+++ b/src/com/android/settings/wifi/WifiPickerActivity.java
@@ -21,6 +21,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.wifi.p2p.WifiP2pSettings;
+import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
import androidx.preference.PreferenceFragmentCompat;
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index e5ff3d9..28e10b2 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -231,7 +231,7 @@
Context prefContext = getPrefContext();
mAddPreference = new Preference(prefContext);
- mAddPreference.setIcon(R.drawable.ic_menu_add_inset);
+ mAddPreference.setIcon(R.drawable.ic_menu_add);
mAddPreference.setTitle(R.string.wifi_add_network);
mStatusMessagePreference = new LinkablePreference(prefContext);
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
new file mode 100644
index 0000000..a7c4038
--- /dev/null
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.savedaccesspoints;
+
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Controller that manages a PrferenceGroup, which contains a list of saved access points.
+ */
+public class SavedAccessPointsPreferenceController extends BasePreferenceController {
+
+ public SavedAccessPointsPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
similarity index 76%
rename from src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
rename to src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
index ebb493c..930cd85 100644
--- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
@@ -14,58 +14,44 @@
* limitations under the License.
*/
-package com.android.settings.wifi;
+package com.android.settings.wifi.savedaccesspoints;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
-import android.icu.text.Collator;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.search.Indexable;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.wifi.WifiConfigUiBase;
+import com.android.settings.wifi.WifiDialog;
+import com.android.settings.wifi.WifiSettings;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.AccessPointPreference;
import com.android.settingslib.wifi.WifiSavedConfigUtils;
import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
/**
* UI to manage saved networks/access points.
- * TODO(b/64806699): convert to {@link DashboardFragment} with {@link PreferenceController}s
*/
-public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment
- implements Indexable, WifiDialog.WifiDialogListener {
+public class SavedAccessPointsWifiSettings extends DashboardFragment
+ implements WifiDialog.WifiDialogListener {
private static final String TAG = "SavedAccessPoints";
@VisibleForTesting
static final int MSG_UPDATE_PREFERENCES = 1;
- private static final Comparator<AccessPoint> SAVED_NETWORK_COMPARATOR =
- new Comparator<AccessPoint>() {
- final Collator mCollator = Collator.getInstance();
- @Override
- public int compare(AccessPoint ap1, AccessPoint ap2) {
- return mCollator.compare(
- nullToEmpty(ap1.getConfigName()), nullToEmpty(ap2.getConfigName()));
- }
-
- private String nullToEmpty(String string) {
- return (string == null) ? "" : string;
- }
- };
@VisibleForTesting
final WifiManager.ActionListener mForgetListener = new WifiManager.ActionListener() {
@@ -95,13 +81,14 @@
public void onSuccess() {
postUpdatePreference();
}
+
@Override
public void onFailure(int reason) {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity,
- R.string.wifi_failed_save_message,
- Toast.LENGTH_SHORT).show();
+ R.string.wifi_failed_save_message,
+ Toast.LENGTH_SHORT).show();
}
}
};
@@ -111,7 +98,6 @@
private AccessPoint mDlgAccessPoint;
private Bundle mAccessPointSavedState;
private AccessPoint mSelectedAccessPoint;
- private Preference mAddNetworkPreference;
private AccessPointPreference.UserBadgeCache mUserBadgeCache;
@@ -124,9 +110,18 @@
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.wifi_display_saved_access_points);
+ protected int getPreferenceScreenResId() {
+ return R.xml.wifi_display_saved_access_points;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
}
@@ -139,12 +134,13 @@
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mWifiManager = (WifiManager) getContext()
+ .getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
mAccessPointSavedState =
- savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
+ savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
}
}
}
@@ -155,18 +151,17 @@
final List<AccessPoint> accessPoints =
WifiSavedConfigUtils.getAllConfigs(context, mWifiManager);
- Collections.sort(accessPoints, SAVED_NETWORK_COMPARATOR);
+ Collections.sort(accessPoints, SavedNetworkComparator.INSTANCE);
cacheRemoveAllPrefs(preferenceScreen);
final int accessPointsSize = accessPoints.size();
for (int i = 0; i < accessPointsSize; ++i) {
AccessPoint ap = accessPoints.get(i);
String key = ap.getKey();
- LongPressAccessPointPreference preference =
- (LongPressAccessPointPreference) getCachedPreference(key);
+ AccessPointPreference preference =
+ (AccessPointPreference) getCachedPreference(key);
if (preference == null) {
- preference = new LongPressAccessPointPreference(
- ap, context, mUserBadgeCache, true, this);
+ preference = new AccessPointPreference(ap, context, mUserBadgeCache, true);
preference.setKey(key);
preference.setIcon(null);
preferenceScreen.addPreference(preference);
@@ -176,15 +171,7 @@
removeCachedPrefs(preferenceScreen);
- if (mAddNetworkPreference == null) {
- mAddNetworkPreference = new Preference(getPrefContext());
- mAddNetworkPreference.setIcon(R.drawable.ic_menu_add_inset);
- mAddNetworkPreference.setTitle(R.string.wifi_add_network);
- }
- mAddNetworkPreference.setOrder(accessPointsSize);
- preferenceScreen.addPreference(mAddNetworkPreference);
-
- if(getPreferenceScreen().getPreferenceCount() < 1) {
+ if (getPreferenceScreen().getPreferenceCount() < 1) {
Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
}
}
@@ -195,7 +182,7 @@
}
}
- private void showWifiDialog(@Nullable LongPressAccessPointPreference accessPoint) {
+ private void showWifiDialog(@Nullable AccessPointPreference accessPoint) {
if (mDialog != null) {
removeDialog(WifiSettings.WIFI_DIALOG_ID);
mDialog = null;
@@ -290,11 +277,8 @@
@Override
public boolean onPreferenceTreeClick(Preference preference) {
- if (preference instanceof LongPressAccessPointPreference) {
- showWifiDialog((LongPressAccessPointPreference) preference);
- return true;
- } else if (preference == mAddNetworkPreference) {
- showWifiDialog(null);
+ if (preference instanceof AccessPointPreference) {
+ showWifiDialog((AccessPointPreference) preference);
return true;
} else {
return super.onPreferenceTreeClick(preference);
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedNetworkComparator.java b/src/com/android/settings/wifi/savedaccesspoints/SavedNetworkComparator.java
new file mode 100644
index 0000000..cff4387
--- /dev/null
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedNetworkComparator.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.savedaccesspoints;
+
+import android.icu.text.Collator;
+
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.Comparator;
+
+public final class SavedNetworkComparator {
+ public static final Comparator<AccessPoint> INSTANCE =
+ new Comparator<AccessPoint>() {
+ final Collator mCollator = Collator.getInstance();
+
+ @Override
+ public int compare(AccessPoint ap1, AccessPoint ap2) {
+ return mCollator.compare(
+ nullToEmpty(ap1.getConfigName()), nullToEmpty(ap2.getConfigName()));
+ }
+
+ private String nullToEmpty(String string) {
+ return (string == null) ? "" : string;
+ }
+ };
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 48c9de9..37869e9 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -73,5 +73,5 @@
com.android.settings.wifi.ChangeWifiStateDetails
com.android.settings.wifi.details.WifiNetworkDetailsFragment
com.android.settings.wifi.p2p.WifiP2pSettings
-com.android.settings.wifi.SavedAccessPointsWifiSettings
+com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings
com.android.settings.wifi.WifiInfo
diff --git a/tests/robotests/assets/grandfather_not_implementing_instrumentable b/tests/robotests/assets/grandfather_not_implementing_instrumentable
index 27ab65c..2c8ae5d 100644
--- a/tests/robotests/assets/grandfather_not_implementing_instrumentable
+++ b/tests/robotests/assets/grandfather_not_implementing_instrumentable
@@ -5,5 +5,4 @@
com.android.settings.password.ChooseLockPattern$SaveAndFinishWorker
com.android.settings.RestrictedListPreference$RestrictedListPreferenceDialogFragment
com.android.settings.password.ConfirmDeviceCredentialBaseFragment$LastTryDialog
-com.android.settings.password.CredentialCheckResultTracker
-com.android.settings.localepicker.LocalePickerWithRegion
+com.android.settings.password.CredentialCheckResultTracker
\ No newline at end of file
diff --git a/tests/robotests/res/values/themes.xml b/tests/robotests/res/values/themes.xml
index 74bdd9b..9a247f6 100644
--- a/tests/robotests/res/values/themes.xml
+++ b/tests/robotests/res/values/themes.xml
@@ -1,5 +1,8 @@
<resources>
- <style name="Theme.Settings" parent="@android:style/Theme.DeviceDefault.Settings" />
+ <style name="Theme.Settings" parent="@android:style/Theme.DeviceDefault.Settings">
+ <!-- For AndroidX AlertDialogs -->
+ <item name="alertDialogTheme">@style/Theme.AppCompat.DayNight.Dialog.Alert</item>
+ </style>
<!-- Override the main app's style for ActionPrimaryButton to get around lack of new style
support in robolectric -->
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultPhonePickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultPhonePickerTest.java
index f304b49..57d31cf 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultPhonePickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultPhonePickerTest.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager;
import android.os.UserManager;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -53,6 +54,8 @@
private DefaultPhonePicker.DefaultKeyUpdater mDefaultKeyUpdater;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private BatteryUtils mBatteryUtils;
private DefaultPhonePicker mPicker;
@@ -66,6 +69,7 @@
ReflectionHelpers.setField(mPicker, "mPm", mPackageManager);
ReflectionHelpers.setField(mPicker, "mDefaultKeyUpdater", mDefaultKeyUpdater);
+ ReflectionHelpers.setField(mPicker, "mBatteryUtils", mBatteryUtils);
doReturn(RuntimeEnvironment.application).when(mPicker).getContext();
}
@@ -87,6 +91,14 @@
@Test
public void getDefaultAppKey_shouldReturnDefault() {
mPicker.getDefaultKey();
+
verify(mDefaultKeyUpdater).getDefaultDialerApplication(any(Context.class), anyInt());
}
+
+ @Test
+ public void setDefaultKey_shouldUnrestrictApp() {
+ mPicker.setDefaultKey(TEST_APP_KEY);
+
+ verify(mBatteryUtils).clearForceAppStandby(TEST_APP_KEY);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultSmsPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultSmsPickerTest.java
index 18bb60e..ade62a1 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultSmsPickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultSmsPickerTest.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.os.UserManager;
+import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -52,6 +53,8 @@
private DefaultSmsPicker.DefaultKeyUpdater mDefaultKeyUpdater;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private BatteryUtils mBatteryUtils;
private DefaultSmsPicker mPicker;
@@ -64,6 +67,7 @@
ReflectionHelpers.setField(mPicker, "mPm", mPackageManager);
ReflectionHelpers.setField(mPicker, "mDefaultKeyUpdater", mDefaultKeyUpdater);
+ ReflectionHelpers.setField(mPicker, "mBatteryUtils", mBatteryUtils);
doReturn(RuntimeEnvironment.application).when(mPicker).getContext();
}
@@ -80,4 +84,11 @@
verify(mDefaultKeyUpdater).getDefaultApplication(any(Context.class));
}
+
+ @Test
+ public void setDefaultKey_shouldUnrestrictApp() {
+ mPicker.setDefaultKey(TEST_APP_KEY);
+
+ verify(mBatteryUtils).clearForceAppStandby(TEST_APP_KEY);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAddTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAddTest.java
index e85f3f6..6bc143c 100644
--- a/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAddTest.java
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAddTest.java
@@ -17,9 +17,13 @@
package com.android.settings.applications.specialaccess.deviceadmin;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+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;
@@ -39,6 +43,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class DeviceAdminAddTest {
@@ -47,7 +52,6 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private DeviceAdminInfo mDeviceAdmin;
- @Mock
private BatteryUtils mBatteryUtils;
private FakeFeatureFactory mFeatureFactory;
private DeviceAdminAdd mDeviceAdminAdd;
@@ -56,6 +60,8 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mBatteryUtils = spy(BatteryUtils.getInstance(RuntimeEnvironment.application));
+ doNothing().when(mBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt());
mFeatureFactory = FakeFeatureFactory.setupForTest();
mDeviceAdminAdd = Robolectric.buildActivity(DeviceAdminAdd.class).get();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 238a88b..df34b78 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -653,4 +653,35 @@
assertThat(mBatteryUtils.shouldHideAnomaly(mPowerWhitelistBackend, UID,
mAnomalyInfo)).isTrue();
}
+
+ @Test
+ public void clearForceAppStandby_appRestricted_clearAndReturnTrue() {
+ when(mBatteryUtils.getPackageUid(HIGH_SDK_PACKAGE)).thenReturn(UID);
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ HIGH_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
+
+ assertThat(mBatteryUtils.clearForceAppStandby(HIGH_SDK_PACKAGE)).isTrue();
+ verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+ }
+
+ @Test
+ public void clearForceAppStandby_appInvalid_returnFalse() {
+ when(mBatteryUtils.getPackageUid(PACKAGE_NAME)).thenReturn(BatteryUtils.UID_NULL);
+
+ assertThat(mBatteryUtils.clearForceAppStandby(PACKAGE_NAME)).isFalse();
+ verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+ }
+
+ @Test
+ public void clearForceAppStandby_appUnrestricted_returnFalse() {
+ when(mBatteryUtils.getPackageUid(PACKAGE_NAME)).thenReturn(UID);
+ when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_ALLOWED);
+
+ assertThat(mBatteryUtils.clearForceAppStandby(PACKAGE_NAME)).isFalse();
+ verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
+ PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index b0d6a7d..3ada030 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -28,9 +28,13 @@
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
+import com.android.settings.fuelgauge.batterytip.tips.AppRestrictionPredicate;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -77,6 +81,12 @@
mBatteryTipLoader.mBatteryUtils = mBatteryUtils;
}
+ @After
+ public void tearDown() {
+ BatteryTestUtils.clearStaticInstance(AppLabelPredicate.class, "sInstance");
+ BatteryTestUtils.clearStaticInstance(AppRestrictionPredicate.class, "sInstance");
+ }
+
@Test
public void testLoadBackground_containsAllTipsWithOrder() {
final List<BatteryTip> batteryTips = mBatteryTipLoader.loadInBackground();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
index 547e0eb..053a716 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
@@ -49,7 +49,8 @@
+ ",test_battery_saver_tip=true"
+ ",test_high_usage_tip=false"
+ ",test_smart_battery_tip=true"
- + ",test_low_battery_tip=true";
+ + ",test_low_battery_tip=true"
+ + ",app_restriction_active_hour=6";
private Context mContext;
@Before
@@ -72,6 +73,7 @@
assertThat(batteryTipPolicy.highUsagePeriodMs).isEqualTo(2000);
assertThat(batteryTipPolicy.highUsageBatteryDraining).isEqualTo(30);
assertThat(batteryTipPolicy.appRestrictionEnabled).isTrue();
+ assertThat(batteryTipPolicy.appRestrictionActiveHour).isEqualTo(6);
assertThat(batteryTipPolicy.reducedBatteryEnabled).isTrue();
assertThat(batteryTipPolicy.reducedBatteryPercent).isEqualTo(30);
assertThat(batteryTipPolicy.lowBatteryEnabled).isFalse();
@@ -99,6 +101,7 @@
assertThat(batteryTipPolicy.highUsagePeriodMs).isEqualTo(2 * DateUtils.HOUR_IN_MILLIS);
assertThat(batteryTipPolicy.highUsageBatteryDraining).isEqualTo(25);
assertThat(batteryTipPolicy.appRestrictionEnabled).isTrue();
+ assertThat(batteryTipPolicy.appRestrictionActiveHour).isEqualTo(24);
assertThat(batteryTipPolicy.reducedBatteryEnabled).isFalse();
assertThat(batteryTipPolicy.reducedBatteryPercent).isEqualTo(50);
assertThat(batteryTipPolicy.lowBatteryEnabled).isTrue();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
index 459c4e2..3882e8c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge.batterytip;
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.when;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java
index 9b0007b..179f2a1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java
@@ -34,8 +34,11 @@
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
+import com.android.settings.fuelgauge.batterytip.tips.AppRestrictionPredicate;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
+import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -86,6 +89,7 @@
mContext = spy(RuntimeEnvironment.application);
mPolicy = spy(new BatteryTipPolicy(mContext));
+ doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager).checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, RESTRICTED_UID, RESTRICTED_PACKAGE_NAME);
@@ -103,7 +107,12 @@
mRestrictAppDetector = new RestrictAppDetector(mContext, mPolicy);
mRestrictAppDetector.mBatteryDatabaseManager = mBatteryDatabaseManager;
+ }
+ @After
+ public void tearDown() {
+ BatteryTestUtils.clearStaticInstance(AppLabelPredicate.class, "sInstance");
+ BatteryTestUtils.clearStaticInstance(AppRestrictionPredicate.class, "sInstance");
}
@After
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
index 5c8b7d9..dd3e281 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
@@ -34,9 +34,11 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.fuelgauge.batterytip.AppInfo;
+import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -74,6 +76,7 @@
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME,
PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.MATCH_ANY_USER);
@@ -98,6 +101,12 @@
mInvisibleBatteryTip = new RestrictAppTip(BatteryTip.StateType.INVISIBLE, new ArrayList<>());
}
+ @After
+ public void tearDown() {
+ BatteryTestUtils.clearStaticInstance(AppLabelPredicate.class, "sInstance");
+ BatteryTestUtils.clearStaticInstance(AppRestrictionPredicate.class, "sInstance");
+ }
+
@Test
public void parcelable() {
Parcel parcel = Parcel.obtain();
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java b/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java
new file mode 100644
index 0000000..bad3dbd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/localepicker/LocalePickerWithRegionActivityTest.java
@@ -0,0 +1,51 @@
+package com.android.settings.localepicker;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.app.Activity;
+
+import com.android.internal.app.LocaleStore;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.Shadows;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.shadows.ShadowActivity;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class LocalePickerWithRegionActivityTest {
+
+ private LocalePickerWithRegionActivity mActivity;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final ActivityController<LocalePickerWithRegionActivity> mActivityController =
+ Robolectric.buildActivity(LocalePickerWithRegionActivity.class);
+ mActivity = spy(mActivityController.get());
+ }
+
+ @Test
+ public void onLocaleSelected_resultShouldBeOK() {
+ final ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+ mActivity.onLocaleSelected(mock(LocaleStore.LocaleInfo.class));
+
+ assertEquals(Activity.RESULT_OK, shadowActivity.getResultCode());
+ }
+
+ @Test
+ public void onLocaleSelected_localeInfoShouldBeSentBack() {
+ final ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+ mActivity.onLocaleSelected(mock(LocaleStore.LocaleInfo.class));
+
+ assertNotNull(shadowActivity.getResultIntent().getSerializableExtra(
+ LocaleListEditor.INTENT_LOCALE_KEY));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java b/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java
deleted file mode 100644
index 5045837..0000000
--- a/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.location;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-public final class InjectedSettingTest {
-
- private static final String TEST_STRING = "test";
-
- @Test
- public void buildWithoutPackageName_ShouldReturnNull() {
- assertThat(((new InjectedSetting.Builder())
- .setClassName(TEST_STRING)
- .setTitle(TEST_STRING)
- .setSettingsActivity(TEST_STRING).build())).isNull();
- }
-
- private InjectedSetting getTestSetting() {
- return new InjectedSetting.Builder()
- .setPackageName(TEST_STRING)
- .setClassName(TEST_STRING)
- .setTitle(TEST_STRING)
- .setSettingsActivity(TEST_STRING).build();
- }
-
- @Test
- public void testEquals() {
- InjectedSetting setting1 = getTestSetting();
- InjectedSetting setting2 = getTestSetting();
- assertThat(setting1).isEqualTo(setting2);
- }
-
- @Test
- public void testHashCode() {
- InjectedSetting setting = getTestSetting();
- assertThat(setting.hashCode()).isEqualTo(1225314048);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
index ba5decc..f0904d0 100644
--- a/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
@@ -67,7 +67,7 @@
@Mock
private PreferenceScreen mScreen;
@Mock
- private SettingsInjector mSettingsInjector;
+ private AppSettingsInjector mSettingsInjector;
@Mock
private DevicePolicyManager mDevicePolicyManager;
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
index f76a5ca..5068f85 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockTypeDialogFragmentTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Google Inc.
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,38 +16,33 @@
package com.android.settings.password;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.app.AlertDialog;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.password.ChooseLockTypeDialogFragment.OnLockTypeSelectedListener;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl;
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settingslib.testutils.FragmentTestUtils;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowAlertDialog;
-import org.robolectric.shadows.ShadowDialog;
+import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = {ShadowUserManager.class, ShadowUtils.class})
+@Config(shadows = {SettingsShadowResourcesImpl.class, ShadowAlertDialogCompat.class})
public class ChooseLockTypeDialogFragmentTest {
private Context mContext;
@@ -61,32 +56,36 @@
}
@Test
- @Ignore("b/111247403")
public void testThatDialog_IsShown() {
AlertDialog latestDialog = startLockFragment();
- assertNotNull(latestDialog);
- ShadowDialog shadowDialog = Shadows.shadowOf(latestDialog);
+ ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(
+ latestDialog);
+
+ assertThat(latestDialog).isNotNull();
+ assertThat(latestDialog.isShowing()).isTrue();
// verify that we are looking at the expected dialog.
- assertEquals(shadowDialog.getTitle(),
+ assertThat(shadowAlertDialog.getTitle()).isEqualTo(
mContext.getString(R.string.setup_lock_settings_options_dialog_title));
}
@Test
- @Ignore("b/111247403")
public void testThat_OnClickListener_IsCalled() {
mFragment.mDelegate = mock(OnLockTypeSelectedListener.class);
AlertDialog lockDialog = startLockFragment();
- ShadowAlertDialog shadowAlertDialog = Shadows.shadowOf(lockDialog);
+ ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(lockDialog);
+
shadowAlertDialog.clickOnItem(0);
+
verify(mFragment.mDelegate, times(1)).onLockTypeSelected(any(ScreenLockType.class));
}
@Test
- @Ignore("b/111247403")
public void testThat_OnClickListener_IsNotCalledWhenCancelled() {
mFragment.mDelegate = mock(OnLockTypeSelectedListener.class);
AlertDialog lockDialog = startLockFragment();
+
lockDialog.dismiss();
+
verify(mFragment.mDelegate, never()).onLockTypeSelected(any(ScreenLockType.class));
}
@@ -94,7 +93,7 @@
ChooseLockTypeDialogFragment chooseLockTypeDialogFragment =
ChooseLockTypeDialogFragment.newInstance(1234);
chooseLockTypeDialogFragment.show(mFragment.getChildFragmentManager(), null);
- return ShadowAlertDialog.getLatestAlertDialog();
+ return ShadowAlertDialogCompat.getLatestAlertDialog();
}
public static class TestFragment extends Fragment implements OnLockTypeSelectedListener {
diff --git a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
index 636248a..37c972a 100644
--- a/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
+++ b/tests/robotests/src/com/android/settings/password/ConfirmCredentialTest.java
@@ -20,25 +20,20 @@
import com.android.settings.password.ConfirmDeviceCredentialBaseFragment.LastTryDialog;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.SettingsShadowResources;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
-import org.robolectric.annotation.Config;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
@RunWith(SettingsRobolectricTestRunner.class)
-@Config(shadows = SettingsShadowResources.SettingsShadowTheme.class)
public class ConfirmCredentialTest {
@Test
- @Ignore("b/111193572")
public void testLastTryDialogShownExactlyOnce() {
FragmentManager fm = Robolectric.buildActivity(FragmentActivity.class).
- get().getSupportFragmentManager();
+ setup().get().getSupportFragmentManager();
// Launch only one instance at a time.
assertThat(LastTryDialog.show(
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index 2bdab27..eed2009 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -19,6 +19,8 @@
import android.content.Intent;
import android.os.BatteryManager;
+import java.lang.reflect.Field;
+
public class BatteryTestUtils {
public static Intent getChargingIntent() {
@@ -47,4 +49,15 @@
return intent;
}
+ public static void clearStaticInstance(Class clazz, String fieldName) {
+ Field instance;
+ try {
+ instance = clazz.getDeclaredField(fieldName);
+ instance.setAccessible(true);
+ instance.set(null, null);
+ } catch (Exception e) {
+ throw new RuntimeException();
+ }
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResourcesImpl.java b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResourcesImpl.java
index 9fb69a3..dd51687 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResourcesImpl.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResourcesImpl.java
@@ -43,7 +43,8 @@
// that Robolectric isn't yet aware of.
// TODO: Remove this once Robolectric is updated.
if (id == R.drawable.switchbar_background
- || id == R.color.ripple_material_light) {
+ || id == R.color.ripple_material_light
+ || id == R.color.ripple_material_dark) {
return new ColorDrawable();
} else if (id == R.drawable.ic_launcher_settings) {
// ic_launcher_settings uses adaptive-icon, which is not supported by robolectric,
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowTypedArray.java b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowTypedArray.java
new file mode 100644
index 0000000..fc3ff0c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowTypedArray.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.testutils.shadow;
+
+import static org.robolectric.shadow.api.Shadow.directlyOn;
+
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.StyleableRes;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.shadows.ShadowTypedArray;
+
+@Implements(value = TypedArray.class, inheritImplementationMethods = true)
+public class SettingsShadowTypedArray extends ShadowTypedArray {
+
+ @RealObject
+ TypedArray realTypedArray;
+
+ @Implementation
+ @Nullable
+ public ColorStateList getColorStateList(@StyleableRes int index) {
+ if (index == com.android.internal.R.styleable.TextView_textColorLink) {
+ return ColorStateList.valueOf(Color.WHITE);
+ }
+ return directlyOn(realTypedArray, TypedArray.class).getColorStateList(index);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
new file mode 100644
index 0000000..a682d85
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAlertDialogCompat.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.testutils.shadow;
+
+import android.annotation.SuppressLint;
+import android.view.View;
+
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.annotation.Resetter;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowDialog;
+import org.robolectric.util.ReflectionHelpers;
+
+import javax.annotation.Nullable;
+
+import androidx.appcompat.app.AlertDialog;
+
+/* Robolectric shadow for the androidx alert dialog. */
+@Implements(AlertDialog.class)
+public class ShadowAlertDialogCompat extends ShadowDialog {
+
+ @SuppressLint("StaticFieldLeak")
+ @Nullable
+ private static ShadowAlertDialogCompat latestSupportAlertDialog;
+ @RealObject
+ private AlertDialog realAlertDialog;
+
+ @Implementation
+ public void show() {
+ super.show();
+ latestSupportAlertDialog = this;
+ }
+
+ public CharSequence getMessage() {
+ final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ return ReflectionHelpers.getField(alertController, "mMessage");
+ }
+
+ public CharSequence getTitle() {
+ final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ return ReflectionHelpers.getField(alertController, "mTitle");
+ }
+
+ public View getView() {
+ final Object alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert");
+ return ReflectionHelpers.getField(alertController, "mView");
+ }
+
+ @Nullable
+ public static AlertDialog getLatestAlertDialog() {
+ return latestSupportAlertDialog == null ? null : latestSupportAlertDialog.realAlertDialog;
+ }
+
+ @Resetter
+ public static void reset() {
+ latestSupportAlertDialog = null;
+ }
+
+ public static ShadowAlertDialogCompat shadowOf(AlertDialog alertDialog) {
+ return (ShadowAlertDialogCompat) Shadow.extract(alertDialog);
+ }
+
+ public void clickOnItem(int index) {
+ Shadows.shadowOf(realAlertDialog.getListView()).performItemClick(index);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
index 8cdecff..b40ea2e 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java
@@ -17,6 +17,7 @@
package com.android.settings.wifi;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.doReturn;
import android.content.Intent;
@@ -25,6 +26,7 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
+import com.android.settings.testutils.shadow.SettingsShadowTypedArray;
import com.android.settings.testutils.shadow.ShadowWifiManager;
import org.junit.Before;
@@ -39,9 +41,10 @@
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {
- SettingsShadowResources.SettingsShadowTheme.class,
- ShadowConnectivityManager.class,
- ShadowWifiManager.class
+ SettingsShadowResources.SettingsShadowTheme.class,
+ ShadowConnectivityManager.class,
+ SettingsShadowTypedArray.class,
+ ShadowWifiManager.class
}
)
public class WifiDialogActivityTest {
@@ -78,7 +81,7 @@
Robolectric.buildActivity(
WifiDialogActivity.class,
new Intent().putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false))
- .setup().get();
+ .setup().get();
WifiDialog dialog = (WifiDialog) ShadowAlertDialog.getLatestAlertDialog();
assertThat(dialog).isNotNull();
diff --git a/tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
similarity index 86%
rename from tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java
rename to tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
index b4fc4cd..a988390 100644
--- a/tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.settings.wifi;
+package com.android.settings.wifi.savedaccesspoints;
+
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -27,7 +29,11 @@
import android.net.wifi.WifiManager.ActionListener;
import android.os.Handler;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.wifi.WifiConfigController;
+import com.android.settings.wifi.WifiDialog;
import com.android.settingslib.wifi.AccessPoint;
import org.junit.Before;
@@ -105,4 +111,11 @@
verify(mockWifiManager)
.forget(eq(mockWifiConfiguration.networkId), any(ActionListener.class));
}
+
+ @Test
+ public void verifyConstants() {
+ assertThat(mSettings.getMetricsCategory()).isEqualTo(MetricsEvent.WIFI_SAVED_ACCESS_POINTS);
+ assertThat(mSettings.getPreferenceScreenResId())
+ .isEqualTo(R.xml.wifi_display_saved_access_points);
+ }
}