Merge "Fix test"
diff --git a/Android.mk b/Android.mk
index 0fbaacf..c99e30c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,7 @@
LOCAL_PACKAGE_NAME := Settings
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_REQUIRED_MODULES := privapp_whitelist_com.android.settings
LOCAL_MODULE_TAGS := optional
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6379e0f..871f609 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1624,7 +1624,7 @@
android:icon="@drawable/ic_settings_security">
<intent-filter android:priority="1">
<action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.LOCK_SCREEN" />
+ <category android:name="com.android.settings.suggested.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.title"
android:resource="@string/suggested_lock_settings_title" />
@@ -2973,11 +2973,16 @@
android:label="@string/settings_panel_title"
android:theme="@style/Theme.BottomDialog"
android:excludeFromRecents="true"
- android:launchMode="singleTask">
+ android:launchMode="singleTask"
+ android:exported="true">
<intent-filter>
- <action android:name="android.settings.SETTINGSPANEL" />
+ <action android:name="android.settings.panel.action.INTERNET_CONNECTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.settings.panel.action.VOLUME" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
<provider android:name=".slices.SettingsSliceProvider"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6ead46e..93445f9 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -46,6 +46,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Settings_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Settings)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/OWNERS b/OWNERS
index d2bc1ff..37124b2 100644
--- a/OWNERS
+++ b/OWNERS
@@ -7,8 +7,11 @@
dehboxturtle@google.com
dhnishi@google.com
dling@google.com
+edgarwang@google.com
jackqdyulei@google.com
mfritze@google.com
+rafftsai@google.com
+tmfang@google.com
zhfan@google.com
# Emergency approvers in case the above are not available
diff --git a/res/drawable/ic_battery_saver_accent_24dp.xml b/res/drawable/ic_battery_saver_accent_24dp.xml
deleted file mode 100644
index c8def54..0000000
--- a/res/drawable/ic_battery_saver_accent_24dp.xml
+++ /dev/null
@@ -1,29 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorAccent">
- <path
- android:fillColor="#FF000000"
- android:pathData="M15,14l-2,0l0,2l-2,0l0,-2l-2,0l0,-2l2,0l0,-2l2,0l0,2l2,0z"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M16.2,22.5H7.8c-1.3,0 -2.3,-1 -2.3,-2.3V5.8c0,-1.3 1,-2.3 2.3,-2.3h0.7v-2h7v2h0.7c1.3,0 2.3,1.1 2.3,2.3v14.3C18.5,21.5 17.5,22.5 16.2,22.5zM7.8,5.5c-0.2,0 -0.3,0.2 -0.3,0.3v14.3c0,0.2 0.2,0.3 0.3,0.3h8.3c0.2,0 0.3,-0.1 0.3,-0.3V5.8c0,-0.2 -0.1,-0.3 -0.3,-0.3h-2.7v-2h-3v2H7.8z"/>
-</vector>
diff --git a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
index 0c938f8..4217867 100644
--- a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
+++ b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
@@ -24,28 +24,24 @@
<include layout="@layout/wifi_dpp_fragment_header"/>
- <FrameLayout
+ <com.android.settings.wifi.qrcode.QrPreviewLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <SurfaceView
+ android:layout_height="match_parent"
+ android:layout_gravity="center">
+ <TextureView
android:id="@+id/preview_view"
- android:layout_width="426dp"
- android:layout_height="320dp"
- android:layout_gravity="center"/>
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
<com.android.settings.wifi.qrcode.QrDecorateView
android:id="@+id/decorate_view"
- android:layout_width="426dp"
- android:layout_height="320dp"
- android:layout_gravity="center"/>
- </FrameLayout>
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
+ </com.android.settings.wifi.qrcode.QrPreviewLayout>
<TextView android:id="@+id/error_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
- <include layout="@layout/wifi_dpp_fragment_footer"
- android:gravity="center|bottom"/>
-
</LinearLayout>
diff --git a/res/layout/face_enroll_accessibility_toggle.xml b/res/layout/face_enroll_accessibility_toggle.xml
new file mode 100644
index 0000000..4dda2a7
--- /dev/null
+++ b/res/layout/face_enroll_accessibility_toggle.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/title"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <Switch
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/toggle"
+ android:checked="true"/>
+
+</LinearLayout>
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index 7a5c172..025c239 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -18,6 +18,7 @@
<com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:FaceEnrollAccessibilitySwitch="http://schemas.android.com/apk/res/com.android.settings"
style="?attr/face_layout_theme"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -59,6 +60,41 @@
</com.google.android.setupdesign.view.FillContentLayout>
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center">
+ <Button
+ android:id="@+id/accessibility_button"
+ style="@style/SuwGlifButton.Secondary"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/security_settings_face_enroll_introduction_accessibility" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:id="@+id/accessibility_layout"
+ android:orientation="vertical"
+ android:visibility="invisible">
+
+ <com.android.settings.biometrics.face.FaceEnrollAccessibilityToggle
+ android:id="@+id/toggle_diversity"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_diversity"/>
+
+ <com.android.settings.biometrics.face.FaceEnrollAccessibilityToggle
+ android:id="@+id/toggle_vision"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_vision"/>
+
+ </LinearLayout>
+ </FrameLayout>
+
</LinearLayout>
</com.google.android.setupdesign.GlifLayout>
diff --git a/res/layout/face_enroll_introduction_footer.xml b/res/layout/face_enroll_introduction_footer.xml
index d73a8ed..15993f0 100644
--- a/res/layout/face_enroll_introduction_footer.xml
+++ b/res/layout/face_enroll_introduction_footer.xml
@@ -39,6 +39,6 @@
style="@style/SuwGlifButton.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/suw_next_button_label" />
+ android:text="@string/wizard_next" />
</com.google.android.setupdesign.view.ButtonBarLayout>
diff --git a/res/layout/fingerprint_enroll_introduction_footer.xml b/res/layout/fingerprint_enroll_introduction_footer.xml
index 1298d82..47d7657 100644
--- a/res/layout/fingerprint_enroll_introduction_footer.xml
+++ b/res/layout/fingerprint_enroll_introduction_footer.xml
@@ -39,6 +39,6 @@
style="@style/SuwGlifButton.Primary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/suw_next_button_label" />
+ android:text="@string/wizard_next" />
</com.google.android.setupdesign.view.ButtonBarLayout>
diff --git a/res/layout/panel_layout.xml b/res/layout/panel_layout.xml
index a6f62a4..c466ce8 100644
--- a/res/layout/panel_layout.xml
+++ b/res/layout/panel_layout.xml
@@ -22,7 +22,7 @@
android:orientation="vertical">
<TextView
- android:id="@+id/title"
+ android:id="@+id/panel_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
diff --git a/res/layout/slice_preference_layout.xml b/res/layout/slice_preference_layout.xml
new file mode 100644
index 0000000..4cea9c0
--- /dev/null
+++ b/res/layout/slice_preference_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ <androidx.slice.widget.SliceView
+ android:id="@+id/slice_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+</FrameLayout>
diff --git a/res/layout/storage_wizard_footer.xml b/res/layout/storage_wizard_footer.xml
index 0ff40aa..a4cda18 100644
--- a/res/layout/storage_wizard_footer.xml
+++ b/res/layout/storage_wizard_footer.xml
@@ -27,7 +27,7 @@
android:layout_height="wrap_content"
android:onClick="onNavigateBack"
android:visibility="gone"
- android:text="@string/suw_back_button_label" />
+ android:text="@string/wizard_back" />
<Space
android:layout_width="0dp"
@@ -41,6 +41,6 @@
android:layout_height="wrap_content"
android:onClick="onNavigateNext"
android:visibility="gone"
- android:text="@string/suw_next_button_label" />
+ android:text="@string/wizard_next" />
</LinearLayout>
diff --git a/res/layout/wifi_dpp_activity.xml b/res/layout/wifi_dpp_activity.xml
index a833dcc..cb82f66 100644
--- a/res/layout/wifi_dpp_activity.xml
+++ b/res/layout/wifi_dpp_activity.xml
@@ -22,12 +22,6 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_wifi_signal_4"
- android:layout_gravity="center"/>
-
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
diff --git a/res/layout/wifi_dpp_fragment_header.xml b/res/layout/wifi_dpp_fragment_header.xml
index 99b246f..266a3e8 100644
--- a/res/layout/wifi_dpp_fragment_header.xml
+++ b/res/layout/wifi_dpp_fragment_header.xml
@@ -17,18 +17,42 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_centerHorizontal="true"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp">
- <TextView android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"/>
+ <ImageView
+ android:id="@+id/header_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitCenter"/>
- <TextView android:id="@+id/description"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.EntityHeaderTitle"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center"/>
+ android:gravity="center_horizontal"
+ android:textAlignment="center"
+ android:layout_marginTop="8dp"
+ android:paddingStart="32dp"
+ android:paddingEnd="32dp"/>
+
+ <TextView
+ android:id="@+id/description"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="false"
+ android:gravity="center_horizontal"
+ android:textAlignment="center"
+ android:layout_marginTop="2dp"
+ android:paddingStart="32dp"
+ android:paddingEnd="32dp"/>
</LinearLayout>
diff --git a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
index 0beacff..913998f 100644
--- a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
+++ b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
@@ -24,20 +24,20 @@
<include layout="@layout/wifi_dpp_fragment_header"/>
- <FrameLayout
+ <com.android.settings.wifi.qrcode.QrPreviewLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <SurfaceView
+ android:layout_height="match_parent">
+ <TextureView
android:id="@+id/preview_view"
- android:layout_width="320dp"
- android:layout_height="426dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="center"/>
<com.android.settings.wifi.qrcode.QrDecorateView
android:id="@+id/decorate_view"
- android:layout_width="320dp"
- android:layout_height="426dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="center"/>
- </FrameLayout>
+ </com.android.settings.wifi.qrcode.QrPreviewLayout>
<TextView android:id="@+id/error_message"
android:layout_width="wrap_content"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 86763b7..806e148 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -52,6 +52,8 @@
<attr name="apnPreferenceStyle" format="reference" />
+ <attr name="slicePreferenceStyle" format="reference" />
+
<attr name="footerPreferenceStyle" format="reference" />
<declare-styleable name="FixedLineSummaryPreference">
@@ -144,6 +146,11 @@
<attr name="thickness" format="dimension" />
</declare-styleable>
+ <!-- For Face enroll accessibility toggle -->
+ <declare-styleable name="FaceEnrollAccessibilityToggle">
+ <attr name="messageText" format="reference" />
+ </declare-styleable>
+
<!-- For TwoStatesButtonPreference -->
<declare-styleable name="TwoStateButtonPreference">
<attr name="textOn" format="reference" />
diff --git a/res/values/config.xml b/res/values/config.xml
index edd948f7..7108cbd 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -165,4 +165,7 @@
<!-- Email address for the homepage contextual cards feedback -->
<string name="config_contextual_card_feedback_email" translatable="false"></string>
+
+ <!-- Uri that represents extra bluetooth settings -->
+ <string name="config_bluetooth_device_settings_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/settings_slice?addr=<xliff:g id="mac_address">%1$s</xliff:g></string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 57897dc..da05a41 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -827,8 +827,15 @@
<string name="location_settings_title">Location</string>
<!-- Used in the location settings to control turning on/off the feature entirely -->
<string name="location_settings_master_switch_title">Use location</string>
- <!-- Summary for Location settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
- <string name="location_settings_summary">Scanning, location history</string>
+ <!-- Summary for Location settings when location is off [CHAR LIMIT=NONE] -->
+ <string name="location_settings_summary_location_off">Off</string>
+ <!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
+ <plurals name="location_settings_summary_location_on">
+ <item quantity="one">On - <xliff:g id="count">%1$d</xliff:g> app can access location</item>
+ <item quantity="other">On - <xliff:g id="count">%1$d</xliff:g> apps can access location</item>
+ </plurals>
+ <!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] -->
+ <string name="location_settings_loading_app_permission_stats">Loading\u2026</string>
<!-- Main Settings screen setting option title for the item to take you to the accounts screen [CHAR LIMIT=22] -->
<string name="account_settings_title">Accounts</string>
@@ -870,6 +877,12 @@
<string name="security_settings_face_preference_summary_none">Tap to set up face authentication</string>
<!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
<string name="security_settings_face_preference_title">Face authentication</string>
+ <!-- Button shown which shows accessibility toggles for face enrollment when clicked. [CHAR LIMIT=32] -->
+ <string name="security_settings_face_enroll_introduction_accessibility">Use accessibility setup</string>
+ <!-- Message shown for a toggle which when disabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_accessibility_diversity"></string>
+ <!-- Message shown for a toggle which when disabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
+ <string name="security_settings_face_enroll_introduction_accessibility_vision"></string>
<!-- Button text to cancel enrollment from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_face_enroll_introduction_cancel">Cancel</string>
<!-- Introduction title shown in face enrollment to introduce the face unlock feature [CHAR LIMIT=40] -->
@@ -3630,15 +3643,28 @@
<string name="managed_profile_location_switch_title">Location for work profile</string>
<!-- [CHAR LIMIT=30] Location settings screen. It's a link that directs the user to a page that
shows the location permission setting for each installed app -->
- <string name="location_app_level_permissions">App-level permissions</string>
- <!-- [CHAR LIMIT=42] Location settings screen, sub category for recent location requests -->
- <string name="location_category_recent_location_requests">Recent location requests</string>
- <!-- Location settings screen, displayed when there're more than three recent location requests -->
- <string name="location_recent_location_requests_see_all">See all</string>
+ <string name="location_app_level_permissions">App permission</string>
+ <!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
+ <string name="location_app_permission_summary_location_off">Location is off</string>
+ <!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
+ <plurals name="location_app_permission_summary_location_on">
+ <item quantity="one">
+ <xliff:g id="background_location_app_count">%1$d</xliff:g>
+ of
+ <xliff:g id="total_location_app_count">%2$d</xliff:g>
+ app has unlimited access</item>
+ <item quantity="other">
+ <xliff:g id="background_location_app_count">%1$d</xliff:g>
+ of
+ <xliff:g id="total_location_app_count">%2$d</xliff:g>
+ apps have unlimited access</item>
+ </plurals>
+ <!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
+ <string name="location_category_recent_location_access">Recent location access</string>
+ <!-- [CHAR LIMIT=30] Location settings screen, button to bring the user to view the details of recent location access -->
+ <string name="location_recent_location_access_view_details">View details</string>
<!-- Location settings screen, displayed when there's no recent app accessing location -->
<string name="location_no_recent_apps">No apps have requested location recently</string>
- <!-- [CHAR LIMIT=30] Location settings screen, sub category for location services -->
- <string name="location_category_location_services">Location services</string>
<!-- [CHAR LIMIT=30] Location settings screen, recent location requests high battery use-->
<string name="location_high_battery_use">High battery use</string>
<!-- [CHAR LIMIT=30] Location settings screen, recent location requests low battery use-->
@@ -6746,7 +6772,7 @@
<string name="wizard_back">Back</string>
<!-- Wizard next button label [CHAR LIMIT=25] -->
<string name="wizard_next">Next</string>
- <!-- Wizard next button label [CHAR LIMIT=25] -->
+ <!-- Wizard finish button label [CHAR LIMIT=25] -->
<string name="wizard_finish">Finish</string>
<!-- An option in a photo selection dialog, if there is no photo yet [CHAR LIMIT=50] -->
@@ -6943,6 +6969,8 @@
<string name="keywords_sim_status">network, mobile network state, service state, signal strength, mobile network type, roaming, iccid</string>
<string name="keywords_model_and_hardware">serial number, hardware version</string>
<string name="keywords_android_version">android security patch level, baseband version, kernel version</string>
+ <!--Search keywords for financial apps sms access settings -->
+ <string name="keywords_financial_apps_sms_access">financial app, sms, permission</string>
<!-- Search keyword for Device Theme Settings [CHAR LIMIT=NONE] -->
<string name="keywords_systemui_theme">dark theme</string>
@@ -8833,6 +8861,10 @@
<!-- Summary of number of apps currently can write system settings [CHAR LIMIT=60] -->
<string name="write_settings_summary"><xliff:g id="count" example="10">%1$d</xliff:g> of <xliff:g id="count" example="10">%2$d</xliff:g> apps allowed to modify system settings</string>
+ <!-- Settings title in main settings screen for financial apps sms access [CHAR LIMIT=60] -->
+ <string name="financial_apps_sms_access_title">Financial Apps Sms Access</string>
+ <!-- Preference key for financial apps sms access screen -->
+ <string name="financial_sms_root_screen_key" translatable="false">financial_sms_root_screen_key</string>
<!-- Label for showing apps that can install other apps [CHAR LIMIT=45] -->
<string name="filter_install_sources_apps">Can install other apps</string>
<!-- Label for showing apps that can write system settings [CHAR LIMIT=45] -->
@@ -9021,12 +9053,6 @@
<!-- Summary of condition that do not disturb is on [CHAR LIMIT=36] -->
<string name="condition_zen_summary">Impacts what you hear and see</string>
- <!-- Title of condition that battery saver is on [CHAR LIMIT=30] -->
- <string name="condition_battery_title">Battery Saver is on</string>
-
- <!-- Summary of condition that battery saver is on [CHAR LIMIT=NONE] -->
- <string name="condition_battery_summary">Features restricted</string>
-
<!-- Title of condition that cellular data is off [CHAR LIMIT=50] -->
<string name="condition_cellular_title">Mobile data is off</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 48cd876..15ec46d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -489,4 +489,8 @@
<item name="android:textAllCaps">false</item>
</style>
+ <style name="Widget.SliceView.Settings">
+ <item name="titleSize">@*android:dimen/text_size_subhead_material</item>
+ </style>
+
</resources>
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index 0f7ecab..f25289d 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -21,6 +21,7 @@
<style name="PreferenceTheme" parent="@style/PreferenceThemeOverlay.SettingsBase">
<item name="apnPreferenceStyle">@style/ApnPreference</item>
+ <item name="slicePreferenceStyle">@style/SlicePreference</item>
<item name="seekBarPreferenceStyle">@style/SettingsSeekBarPreference</item>
<item name="twoStateButtonPreferenceStyle">@style/TwoStateButtonPreference</item>
</style>
@@ -34,6 +35,10 @@
<item name="android:layout">@layout/apn_preference_layout</item>
</style>
+ <style name="SlicePreference" parent="@style/Preference.Material">
+ <item name="android:layout">@layout/slice_preference_layout</item>
+ </style>
+
<style name="SettingsSeekBarPreference" parent="@style/Preference.Material">
<item name="android:layout">@layout/preference_widget_seekbar_settings</item>
</style>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 390be584..f22d111 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -32,9 +32,13 @@
<item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
<item name="face_layout_theme">@style/FaceLayoutTheme</item>
<item name="ic_menu_moreoverflow">@*android:drawable/ic_menu_moreoverflow_holo_dark</item>
+
+ <!-- For wifi icon -->
<item name="wifi_signal">@drawable/wifi_signal</item>
<item name="wifi_signal_color">?android:attr/colorAccent</item>
<item name="wifi_friction">@drawable/wifi_friction</item>
+ <item name="frictionIconColor">?android:colorControlNormal</item>
+
<item name="side_margin">@dimen/settings_side_margin</item>
<item name="suwListItemIconColor">?android:attr/colorAccent</item>
@@ -58,6 +62,9 @@
<!-- TODO(118444000): Remove colorPrimary and colorPrimaryVariant -->
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
<item name="colorPrimaryVariant">@android:color/white</item>
+
+ <!-- For slice view in settings -->
+ <item name="sliceViewStyle">@style/Widget.SliceView.Settings</item>
</style>
<!-- Variant of the settings theme with no action bar. -->
@@ -71,9 +78,6 @@
<item name="android:actionBarStyle">@style/Widget.ActionBar.SubSettings</item>
<item name="switchBarTheme">@style/ThemeOverlay.SwitchBar.Settings</item>
-
- <!-- Friction icon color for wifi preferences -->
- <item name="frictionIconColor">?android:colorControlNormal</item>
</style>
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
diff --git a/res/xml/battery_saver_settings.xml b/res/xml/battery_saver_settings.xml
index a086018..89f7eab 100644
--- a/res/xml/battery_saver_settings.xml
+++ b/res/xml/battery_saver_settings.xml
@@ -26,18 +26,6 @@
android:title="@string/battery_saver_schedule_settings_title"
settings:controller="com.android.settings.fuelgauge.batterysaver.BatterySaverSchedulePreferenceController"/>
- <!-- Turn on automatically -->
- <SwitchPreference
- android:key="auto_battery_saver"
- android:title="@string/battery_saver_auto_title"
- settings:controller="com.android.settings.fuelgauge.batterysaver.AutoBatterySaverPreferenceController" />
-
- <com.android.settings.widget.SeekBarPreference
- android:key="battery_saver_seek_bar"
- android:title="@string/battery_saver_seekbar_title_placeholder"
- android:max="15"
- android:min="1" />
-
<com.android.settings.widget.TwoStateButtonPreference
android:key="battery_saver"
android:title="@string/battery_saver"
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 40ce93d..90895f2 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -26,7 +26,14 @@
settings:allowDividerBelow="true"/>
<com.android.settingslib.widget.ActionButtonsPreference
- android:key="action_buttons" />
+ android:key="action_buttons"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.slices.SlicePreference
+ android:key="bt_device_slice"
+ settings:controller="com.android.settings.slices.SlicePreferenceController"
+ settings:allowDividerBelow="true"
+ settings:allowDividerAbove="true"/>
<PreferenceCategory
android:key="bluetooth_profiles"/>
diff --git a/res/xml/location_recent_requests_see_all.xml b/res/xml/financial_app_sms_access.xml
similarity index 64%
rename from res/xml/location_recent_requests_see_all.xml
rename to res/xml/financial_app_sms_access.xml
index 38db142..6f7ba50 100644
--- a/res/xml/location_recent_requests_see_all.xml
+++ b/res/xml/financial_app_sms_access.xml
@@ -9,16 +9,14 @@
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/location_category_recent_location_requests"
- android:key="recent_location_requests_see_all">
-
- <PreferenceCategory
- android:key="all_recent_location_requests"/>
-</PreferenceScreen>
\ No newline at end of file
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="@string/financial_sms_root_screen_key"
+ android:title="@string/financial_apps_sms_access_title"
+ settings:controller="com.android.settings.applications.specialaccess.financialapps.FinancialAppsController" />
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index b53e986..f1c13cf 100644
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -20,21 +20,14 @@
android:title="@string/location_settings_title"
settings:keywords="@string/keywords_location">
- <PreferenceCategory
- android:key="recent_location_requests"
- android:title="@string/location_category_recent_location_requests"/>
-
- <Preference
- android:key="recent_location_requests_see_all_button"
- android:title="@string/location_recent_location_requests_see_all"
- android:icon="@drawable/ic_chevron_right_24dp"
- android:selectable="true"
- android:fragment="com.android.settings.location.RecentLocationRequestSeeAllFragment"
- settings:searchable="false"/>
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="apps_dashboard"
+ android:layout="@layout/app_entities_header"
+ settings:allowDividerBelow="true" />
<PreferenceCategory
android:key="location_advanced_settings"
- settings:initialExpandedChildrenCount="1">
+ settings:initialExpandedChildrenCount="0">
<!-- This preference category gets removed if new_recent_location_ui is disabled -->
<Preference
@@ -60,8 +53,7 @@
android:selectable="true" />
<PreferenceCategory
- android:key="location_services"
- android:title="@string/location_category_location_services"/>
+ android:key="location_services" />
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/network_and_internet_v2.xml b/res/xml/network_and_internet_v2.xml
index 974739d..8e0b426 100644
--- a/res/xml/network_and_internet_v2.xml
+++ b/res/xml/network_and_internet_v2.xml
@@ -18,8 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="network_and_internet_screen"
- android:title="@string/network_dashboard_title"
- settings:initialExpandedChildrenCount="5">
+ android:title="@string/network_dashboard_title">
<PreferenceCategory
android:key="multi_network_header"
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 57e673f..cb76693 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -130,4 +130,9 @@
android:value="com.android.settings.Settings$ChangeWifiStateActivity" />
</Preference>
+ <Preference
+ android:key="financial_apps_sms_access"
+ android:title="@string/financial_apps_sms_access_title"
+ android:fragment="com.android.settings.applications.specialaccess.financialapps.FinancialAppsSmsAccess"
+ settings:keywords="@string/keywords_financial_apps_sms_access" />
</PreferenceScreen>
diff --git a/res/xml/top_level_settings.xml b/res/xml/top_level_settings.xml
index 03e32dc..9f4f902 100644
--- a/res/xml/top_level_settings.xml
+++ b/res/xml/top_level_settings.xml
@@ -93,10 +93,11 @@
<Preference
android:key="top_level_location"
android:title="@string/location_settings_title"
- android:summary="@string/location_settings_summary"
+ android:summary="@string/location_settings_loading_app_permission_stats"
android:icon="@drawable/ic_homepage_location"
android:order="-50"
- android:fragment="com.android.settings.location.LocationSettings"/>
+ android:fragment="com.android.settings.location.LocationSettings"
+ settings:controller="com.android.settings.location.TopLevelLocationPreferenceController"/>
<Preference
android:key="top_level_security"
@@ -149,4 +150,4 @@
android:order="100"
settings:controller="com.android.settings.support.SupportPreferenceController"/>
-</PreferenceScreen>
\ No newline at end of file
+</PreferenceScreen>
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 6557aee..fdd7f2e 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -32,7 +32,6 @@
import com.android.settings.display.ThemePreferenceController;
import com.android.settings.display.TimeoutPreferenceController;
import com.android.settings.display.VrDisplayPreferenceController;
-import com.android.settings.display.WallpaperPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 8e745a3..61a247d 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -66,7 +66,9 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.setupcompat.TemplateLayout;
-import com.google.android.setupdesign.template.ButtonFooterMixin;
+import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.item.FooterButton.ButtonType;
+import com.google.android.setupcompat.template.ButtonFooterMixin;
import java.util.List;
@@ -96,7 +98,7 @@
private View mContentView;
@VisibleForTesting
- Button mInitiateButton;
+ FooterButton mInitiateButton;
private View mExternalStorageContainer;
@VisibleForTesting
CheckBox mExternalStorage;
@@ -416,12 +418,15 @@
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.removeAllViews();
- buttonFooterMixin.addSpace();
- buttonFooterMixin.addSpace();
- mInitiateButton = buttonFooterMixin.addButton(R.string.master_clear_button_text,
- R.style.SuwGlifButton_Primary);
- mInitiateButton.setOnClickListener(mInitiateListener);
+ buttonFooterMixin.setPrimaryButton(
+ new FooterButton(
+ getActivity(),
+ R.string.master_clear_button_text,
+ mInitiateListener,
+ ButtonType.OTHER,
+ R.style.SuwGlifButton_Primary)
+ );
+ mInitiateButton = buttonFooterMixin.getPrimaryButton();
}
private void getContentDescription(View v, StringBuffer description) {
diff --git a/src/com/android/settings/MasterClearConfirm.java b/src/com/android/settings/MasterClearConfirm.java
index ffbb2aa..b2bf838 100644
--- a/src/com/android/settings/MasterClearConfirm.java
+++ b/src/com/android/settings/MasterClearConfirm.java
@@ -45,7 +45,9 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.setupcompat.TemplateLayout;
-import com.google.android.setupdesign.template.ButtonFooterMixin;
+import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.item.FooterButton.ButtonType;
+import com.google.android.setupcompat.template.ButtonFooterMixin;
/**
* Confirm and execute a reset of the device to a clean "just out of the box"
@@ -153,11 +155,14 @@
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.removeAllViews();
- buttonFooterMixin.addSpace();
- buttonFooterMixin.addSpace();
- buttonFooterMixin.addButton(R.string.master_clear_button_text,
- R.style.SuwGlifButton_Primary).setOnClickListener(mFinalClickListener);
+ buttonFooterMixin.setPrimaryButton(
+ new FooterButton(
+ getActivity(),
+ R.string.master_clear_button_text,
+ mFinalClickListener,
+ ButtonType.OTHER,
+ R.style.SuwGlifButton_Primary)
+ );
}
private void setUpActionBarAndTitle() {
diff --git a/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java
new file mode 100644
index 0000000..492e4fd
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsController.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.applications.specialaccess.financialapps;
+
+import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
+import static android.Manifest.permission.READ_SMS;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.SwitchPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FinancialAppsController extends BasePreferenceController
+ implements ApplicationsState.Callbacks {
+ private final static String TAG = FinancialAppsController.class.getSimpleName();
+
+ @VisibleForTesting
+ PreferenceScreen mRoot;
+
+ public FinancialAppsController(Context context, String key) {
+ super(context, key);
+ }
+
+ @AvailabilityStatus
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mRoot = screen;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ updateList();
+ }
+
+ private void updateList() {
+ mRoot.removeAll();
+
+ final PackageManager packageManager = mContext.getPackageManager();
+ final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+
+ final List<PackageInfo> installedPackages =
+ packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+ final int numPackages = installedPackages.size();
+ for (int i = 0; i < numPackages; i++) {
+ final PackageInfo installedPackage = installedPackages.get(i);
+
+ if (installedPackage.requestedPermissions == null) {
+ continue;
+ }
+ final int targetSdk = installedPackage.applicationInfo.targetSdkVersion;
+ final String pkgName = installedPackage.packageName;
+
+ if ((targetSdk >= Build.VERSION_CODES.Q
+ && ArrayUtils.contains(installedPackage.requestedPermissions,
+ SMS_FINANCIAL_TRANSACTIONS))
+ || (targetSdk < Build.VERSION_CODES.Q
+ && ArrayUtils.contains(installedPackage.requestedPermissions,
+ READ_SMS))) {
+ final SwitchPreference pref = new SwitchPreference(mRoot.getContext());
+ pref.setTitle(installedPackage.applicationInfo.loadLabel(packageManager));
+ pref.setKey(pkgName);
+
+ pref.setChecked(
+ appOpsManager.checkOp(
+ targetSdk >= Build.VERSION_CODES.Q
+ ? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
+ : AppOpsManager.OP_READ_SMS,
+ installedPackage.applicationInfo.uid,
+ pkgName) == AppOpsManager.MODE_ALLOWED);
+
+ pref.setOnPreferenceChangeListener((preference, newValue) -> {
+ final int uid;
+ try {
+ uid = packageManager.getPackageInfo(preference.getKey(), 0)
+ .applicationInfo.uid;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "onPreferenceChange: Failed to get uid for "
+ + preference.getKey());
+ return false;
+ }
+
+ appOpsManager.setMode(
+ targetSdk >= Build.VERSION_CODES.Q
+ ? AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS
+ : AppOpsManager.OP_READ_SMS,
+ uid,
+ pkgName,
+ (Boolean) newValue ? AppOpsManager.MODE_ALLOWED
+ : AppOpsManager.MODE_IGNORED);
+ return true;
+ });
+ mRoot.addPreference(pref);
+ }
+ }
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {}
+
+ @Override
+ public void onPackageListChanged() {
+ updateList();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {}
+
+ @Override
+ public void onPackageIconChanged() {}
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {}
+
+ @Override
+ public void onAllSizesComputed() {}
+
+ @Override
+ public void onLauncherInfoChanged() {}
+
+ @Override
+ public void onLoadEntriesCompleted() {}
+}
diff --git a/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
new file mode 100644
index 0000000..92f4e28
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsSmsAccess.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.specialaccess.financialapps;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SearchIndexable
+public class FinancialAppsSmsAccess extends DashboardFragment {
+ private final static String TAG = FinancialAppsSmsAccess.class.getSimpleName();
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.financial_app_sms_access;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.SETTINGS_FINANCIAL_APPS_SMS_ACCESS;
+ }
+
+ public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final ArrayList<SearchIndexableResource> result = new ArrayList<>();
+
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.financial_app_sms_access;
+ result.add(sir);
+ return result;
+ }
+ };
+}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index 0aa8936..7a06671 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -40,8 +40,10 @@
*/
public abstract class BiometricEnrollBase extends InstrumentedActivity
implements View.OnClickListener {
- public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
+ public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock";
+ public static final String EXTRA_KEY_REQUIRE_VISION = "accessibility_vision";
+ public static final String EXTRA_KEY_REQUIRE_DIVERSITY = "accessibility_diversity";
/**
* Used by the choose fingerprint wizard to indicate the wizard is
@@ -67,8 +69,11 @@
*/
public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2;
- public static final int CONFIRM_REQUEST = 1;
- public static final int ENROLLING = 2;
+ public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
+ public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
+ public static final int LEARN_MORE_REQUEST = 3;
+ public static final int CONFIRM_REQUEST = 4;
+ public static final int ENROLLING = 5;
protected boolean mLaunchedConfirmLock;
protected byte[] mToken;
@@ -105,10 +110,6 @@
initViews();
}
- protected boolean shouldLaunchConfirmLock() {
- return mToken == null && !mLaunchedConfirmLock;
- }
-
protected void initViews() {
getWindow().setStatusBarColor(Color.TRANSPARENT);
Button nextButton = getNextButton();
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 2424eb1..8a2a8ec 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -37,10 +37,6 @@
public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
implements LinkSpan.OnClickListener {
- public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
- public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
- public static final int LEARN_MORE_REQUEST = 3;
-
private UserManager mUserManager;
private boolean mHasPassword;
private boolean mBiometricUnlockDisabledByAdmin;
@@ -110,6 +106,11 @@
protected abstract Intent getEnrollingIntent();
/**
+ * @return the title to be shown on the ConfirmLock screen.
+ */
+ protected abstract int getConfirmLockTitleResId();
+
+ /**
* @param span
*/
public abstract void onClick(LinkSpan span);
@@ -133,6 +134,13 @@
mUserManager = UserManager.get(this);
updatePasswordQuality();
+
+ if (!mHasPassword) {
+ // No password registered, launch into enrollment wizard.
+ launchChooseLock();
+ } else {
+ launchConfirmLock(getConfirmLockTitleResId(), getChallenge());
+ }
}
@Override
@@ -157,13 +165,8 @@
@Override
protected void onNextButtonClick() {
- if (!mHasPassword) {
- // No biometrics registered, launch into enrollment wizard.
- launchChooseLock();
- } else {
- // Lock thingy is already set up, launch directly into find sensor step from wizard.
- launchFindSensor(null);
- }
+ // Lock thingy is already set up, launch directly to the next page
+ launchNextEnrollingActivity(mToken);
}
private void launchChooseLock() {
@@ -181,7 +184,7 @@
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
}
- private void launchFindSensor(byte[] token) {
+ private void launchNextEnrollingActivity(byte[] token) {
Intent intent = getEnrollingIntent();
if (token != null) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
@@ -199,9 +202,9 @@
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
final boolean isResultFinished = resultCode == RESULT_FINISHED;
+ final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
if (requestCode == BIOMETRIC_FIND_SENSOR_REQUEST) {
if (isResultFinished || resultCode == RESULT_SKIP) {
- final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
setResult(result, data);
finish();
return;
@@ -209,10 +212,21 @@
} else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
if (isResultFinished) {
updatePasswordQuality();
- byte[] token = data.getByteArrayExtra(
+ mToken = data.getByteArrayExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
- launchFindSensor(token);
+ overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
return;
+ } else {
+ setResult(result, data);
+ finish();
+ }
+ } else if (requestCode == CONFIRM_REQUEST) {
+ if (resultCode == RESULT_OK && data != null) {
+ mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
+ overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
+ } else {
+ setResult(result, data);
+ finish();
}
} else if (requestCode == LEARN_MORE_REQUEST) {
overridePendingTransition(R.anim.suw_slide_back_in, R.anim.suw_slide_back_out);
diff --git a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
index f101038..033fb4b 100644
--- a/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/BiometricsEnrollEnrolling.java
@@ -48,13 +48,6 @@
*/
protected abstract boolean shouldStartAutomatically();
- /**
- * @return true if enrollment should finish when onStop is called.
- */
- protected boolean shouldFinishOnStop() {
- return true;
- }
-
@Override
protected void onStart() {
super.onStart();
@@ -70,7 +63,7 @@
mSidecar.setListener(null);
}
- if (shouldFinishOnStop() && !isChangingConfigurations()) {
+ if (!isChangingConfigurations()) {
if (mSidecar != null) {
mSidecar.cancelEnrollment();
getSupportFragmentManager()
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java
new file mode 100644
index 0000000..49f4f7f
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java
@@ -0,0 +1,66 @@
+/*
+ * 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.biometrics.face;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+/**
+ * A layout that contains a start-justified title, and an end-justified switch.
+ */
+public class FaceEnrollAccessibilityToggle extends LinearLayout {
+
+ private Switch mSwitch;
+
+ public FaceEnrollAccessibilityToggle(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public FaceEnrollAccessibilityToggle(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FaceEnrollAccessibilityToggle(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ LayoutInflater.from(context).inflate(R.layout.face_enroll_accessibility_toggle,
+ this, true /* attachToRoot */);
+
+ final TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.FaceEnrollAccessibilityToggle);
+ try {
+ final CharSequence title =
+ a.getText(R.styleable.FaceEnrollAccessibilityToggle_messageText);
+ final TextView titleTextView = findViewById(R.id.title);
+ titleTextView.setText(title);
+ } finally {
+ a.recycle();
+ }
+ mSwitch = findViewById(R.id.toggle);
+ }
+
+ public boolean isChecked() {
+ return mSwitch.isChecked();
+ }
+}
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index 727d74a..990eef4 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -29,11 +29,12 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
-import com.android.settings.Utils;
+import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricErrorDialog;
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
-import com.android.settings.password.ChooseLockSettingsHelper;
+
+import java.util.ArrayList;
public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
@@ -44,9 +45,10 @@
private TextView mErrorText;
private Interpolator mLinearOutSlowInInterpolator;
- private boolean mShouldFinishOnStop = true;
private FaceEnrollPreviewFragment mPreviewFragment;
+ private ArrayList<Integer> mDisabledFeatures = new ArrayList<>();
+
private FaceFeatureProvider.Listener mListener = new FaceFeatureProvider.Listener() {
@Override
public void onEnrolled() {
@@ -92,13 +94,14 @@
Button skipButton = findViewById(R.id.skip_button);
skipButton.setOnClickListener(this);
- if (shouldLaunchConfirmLock()) {
- launchConfirmLock(R.string.security_settings_face_preference_title,
- Utils.getFaceManagerOrNull(this).generateChallenge());
- mShouldFinishOnStop = false;
- } else {
- startEnrollment();
+ if (!getIntent().getBooleanExtra(BiometricEnrollBase.EXTRA_KEY_REQUIRE_DIVERSITY, true)) {
+ mDisabledFeatures.add(FaceManager.FEATURE_REQUIRE_REQUIRE_DIVERSITY);
}
+ if (!getIntent().getBooleanExtra(BiometricEnrollBase.EXTRA_KEY_REQUIRE_VISION, true)) {
+ mDisabledFeatures.add(FaceManager.FEATURE_REQUIRE_ATTENTION);
+ }
+
+ startEnrollment();
}
@Override
@@ -121,7 +124,12 @@
@Override
protected BiometricEnrollSidecar getSidecar() {
- return new FaceEnrollSidecar();
+ final int[] disabledFeatures = new int[mDisabledFeatures.size()];
+ for (int i = 0; i < mDisabledFeatures.size(); i++) {
+ disabledFeatures[i] = mDisabledFeatures.get(i);
+ }
+
+ return new FaceEnrollSidecar(disabledFeatures);
}
@Override
@@ -130,11 +138,6 @@
}
@Override
- protected boolean shouldFinishOnStop() {
- return mShouldFinishOnStop;
- }
-
- @Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.FACE_ENROLL_ENROLLING;
}
@@ -178,23 +181,6 @@
}
}
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == CONFIRM_REQUEST) {
- if (resultCode == RESULT_OK && data != null) {
- mShouldFinishOnStop = true;
- mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
- overridePendingTransition(R.anim.suw_slide_next_in, R.anim.suw_slide_next_out);
- getIntent().putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
- startEnrollment();
- } else {
- finish();
- }
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-
private void showErrorDialog(CharSequence msg, int msgId) {
BiometricErrorDialog dialog = FaceErrorDialog.newInstance(msg, msgId);
dialog.show(getSupportFragmentManager(), FaceErrorDialog.class.getName());
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index c4a9c4f..e221c96 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -20,7 +20,9 @@
import android.content.Intent;
import android.hardware.face.FaceManager;
import android.os.Bundle;
+import android.view.View;
import android.widget.Button;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
@@ -37,11 +39,22 @@
private static final String TAG = "FaceIntro";
private FaceManager mFaceManager;
+ private FaceEnrollAccessibilityToggle mSwitchVision;
+ private FaceEnrollAccessibilityToggle mSwitchDiversity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFaceManager = Utils.getFaceManagerOrNull(this);
+ final LinearLayout accessibilityLayout = findViewById(R.id.accessibility_layout);
+ final Button accessibilityButton = findViewById(R.id.accessibility_button);
+ accessibilityButton.setOnClickListener(view -> {
+ accessibilityButton.setVisibility(View.INVISIBLE);
+ accessibilityLayout.setVisibility(View.VISIBLE);
+ });
+
+ mSwitchVision = findViewById(R.id.toggle_vision);
+ mSwitchDiversity = findViewById(R.id.toggle_diversity);
}
@Override
@@ -102,6 +115,7 @@
@Override
protected long getChallenge() {
+ mFaceManager = Utils.getFaceManagerOrNull(this);
if (mFaceManager == null) {
return 0;
}
@@ -115,7 +129,15 @@
@Override
protected Intent getEnrollingIntent() {
- return new Intent(this, FaceEnrollEnrolling.class);
+ final Intent intent = new Intent(this, FaceEnrollEnrolling.class);
+ intent.putExtra(EXTRA_KEY_REQUIRE_VISION, mSwitchVision.isChecked());
+ intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, mSwitchDiversity.isChecked());
+ return intent;
+ }
+
+ @Override
+ protected int getConfirmLockTitleResId() {
+ return R.string.security_settings_face_preference_title;
}
@Override
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
index 2433fcb..7519530 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java
@@ -24,13 +24,22 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollSidecar;
+import java.util.ArrayList;
+import java.util.Arrays;
+
/**
* Sidecar fragment to handle the state around face enrollment
*/
public class FaceEnrollSidecar extends BiometricEnrollSidecar {
+ private final int[] mDisabledFeatures;
+
private FaceManager mFaceManager;
+ public FaceEnrollSidecar(int[] disabledFeatures) {
+ mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
+ }
+
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
@@ -43,9 +52,9 @@
if (mUserId != UserHandle.USER_NULL) {
mFaceManager.setActiveUser(mUserId);
}
- // TODO: Send the list of disabled features
+
mFaceManager.enroll(mToken, mEnrollmentCancel,
- mEnrollmentCallback, new int[0] /* disabledFeatures */);
+ mEnrollmentCallback, mDisabledFeatures);
}
private FaceManager.EnrollmentCallback mEnrollmentCallback
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 4b4f65a..0772c66 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -51,12 +51,9 @@
setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title);
- if (shouldLaunchConfirmLock()) {
- launchConfirmLock(R.string.security_settings_fingerprint_preference_title,
- Utils.getFingerprintManagerOrNull(this).preEnroll());
- } else if (mToken != null) {
- startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
- }
+
+ startLookingForFingerprint(); // already confirmed, so start looking for fingerprint
+
View animationView = findViewById(R.id.fingerprint_sensor_location_animation);
if (animationView instanceof FingerprintFindSensorAnimation) {
mAnimation = (FingerprintFindSensorAnimation) animationView;
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index 8821ce5..61c67a5 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -106,6 +106,7 @@
@Override
protected long getChallenge() {
+ mFingerprintManager = Utils.getFingerprintManagerOrNull(this);
if (mFingerprintManager == null) {
return 0;
}
@@ -123,6 +124,11 @@
}
@Override
+ protected int getConfirmLockTitleResId() {
+ return R.string.security_settings_fingerprint_preference_title;
+ }
+
+ @Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.FINGERPRINT_ENROLL_INTRO;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index df32111..6ec419b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -21,12 +21,16 @@
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.Bundle;
+import android.util.FeatureFlagUtils;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -98,6 +102,13 @@
mManager = getLocalBluetoothManager(context);
mCachedDevice = getCachedDevice(mDeviceAddress);
super.onAttach(context);
+
+ if (FeatureFlagUtils.isEnabled(context, FeatureFlags.SLICE_INJECTION)) {
+ final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(context)
+ .getBluetoothFeatureProvider(context);
+ use(SlicePreferenceController.class).setSliceUri(
+ featureProvider.getBluetoothDeviceSettingsUri(mDeviceAddress));
+ }
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
new file mode 100644
index 0000000..2bca038
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -0,0 +1,32 @@
+/*
+ * 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.bluetooth;
+
+import android.net.Uri;
+
+/**
+ * Provider for bluetooth related feature
+ */
+public interface BluetoothFeatureProvider {
+
+ /**
+ * Get the {@link Uri} that represents extra settings for a specific bluetooth device
+ * @param macAddress Bluetooth mac address
+ * @return {@link Uri} for extra settings
+ */
+ Uri getBluetoothDeviceSettingsUri(String macAddress);
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
new file mode 100644
index 0000000..dcdc2fd7
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.bluetooth;
+
+import android.content.Context;
+import android.net.Uri;
+
+import com.android.settings.R;
+
+/**
+ * Impl of {@link BluetoothFeatureProvider}
+ */
+public class BluetoothFeatureProviderImpl implements BluetoothFeatureProvider {
+
+ private Context mContext;
+
+ public BluetoothFeatureProviderImpl(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public Uri getBluetoothDeviceSettingsUri(String macAddress) {
+ final String uriString = mContext.getString(R.string.config_bluetooth_device_settings_uri,
+ macAddress);
+ return Uri.parse(uriString);
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java b/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
index befdf29..0be1438 100644
--- a/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdater.java
@@ -15,9 +15,12 @@
*/
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
import android.content.Context;
import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -43,7 +46,7 @@
UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
(connected, functions, powerRole, dataRole) -> {
if (connected) {
- mUsbPreference.setSummary(getSummary(dataRole == UsbPort.DATA_ROLE_DEVICE
+ mUsbPreference.setSummary(getSummary(dataRole == DATA_ROLE_DEVICE
? functions : UsbManager.FUNCTION_NONE, powerRole));
mDevicePreferenceCallback.onDeviceAdded(mUsbPreference);
} else {
@@ -100,7 +103,7 @@
public static int getSummary(long functions, int power) {
switch (power) {
- case UsbPort.POWER_ROLE_SINK:
+ case POWER_ROLE_SINK:
if (functions == UsbManager.FUNCTION_MTP) {
return R.string.usb_summary_file_transfers;
} else if (functions == UsbManager.FUNCTION_RNDIS) {
@@ -112,7 +115,7 @@
} else {
return R.string.usb_summary_charging_only;
}
- case UsbPort.POWER_ROLE_SOURCE:
+ case POWER_ROLE_SOURCE:
if (functions == UsbManager.FUNCTION_MTP) {
return R.string.usb_summary_file_transfers_power;
} else if (functions == UsbManager.FUNCTION_RNDIS) {
diff --git a/src/com/android/settings/connecteddevice/usb/UsbBackend.java b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
index f68a4a0..556f76d 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbBackend.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
@@ -15,6 +15,13 @@
*/
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+import static android.service.usb.UsbPortStatusProto.DATA_ROLE_HOST;
+import static android.service.usb.UsbPortStatusProto.DATA_ROLE_NONE;
+import static android.service.usb.UsbPortStatusProto.POWER_ROLE_SINK;
+
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -27,6 +34,8 @@
import androidx.annotation.VisibleForTesting;
+import java.util.List;
+
/**
* Provides access to underlying system USB functionality.
*/
@@ -96,30 +105,30 @@
public int getPowerRole() {
updatePorts();
- return mPortStatus == null ? UsbPort.POWER_ROLE_NONE : mPortStatus.getCurrentPowerRole();
+ return mPortStatus == null ? POWER_ROLE_NONE : mPortStatus.getCurrentPowerRole();
}
public int getDataRole() {
updatePorts();
- return mPortStatus == null ? UsbPort.DATA_ROLE_NONE : mPortStatus.getCurrentDataRole();
+ return mPortStatus == null ? DATA_ROLE_NONE : mPortStatus.getCurrentDataRole();
}
public void setPowerRole(int role) {
int newDataRole = getDataRole();
if (!areAllRolesSupported()) {
switch (role) {
- case UsbPort.POWER_ROLE_SINK:
- newDataRole = UsbPort.DATA_ROLE_DEVICE;
+ case POWER_ROLE_SINK:
+ newDataRole = DATA_ROLE_DEVICE;
break;
- case UsbPort.POWER_ROLE_SOURCE:
- newDataRole = UsbPort.DATA_ROLE_HOST;
+ case POWER_ROLE_SOURCE:
+ newDataRole = DATA_ROLE_HOST;
break;
default:
- newDataRole = UsbPort.DATA_ROLE_NONE;
+ newDataRole = DATA_ROLE_NONE;
}
}
if (mPort != null) {
- mUsbManager.setPortRoles(mPort, role, newDataRole);
+ mPort.setRoles(role, newDataRole);
}
}
@@ -127,31 +136,27 @@
int newPowerRole = getPowerRole();
if (!areAllRolesSupported()) {
switch (role) {
- case UsbPort.DATA_ROLE_DEVICE:
- newPowerRole = UsbPort.POWER_ROLE_SINK;
+ case DATA_ROLE_DEVICE:
+ newPowerRole = POWER_ROLE_SINK;
break;
- case UsbPort.DATA_ROLE_HOST:
- newPowerRole = UsbPort.POWER_ROLE_SOURCE;
+ case DATA_ROLE_HOST:
+ newPowerRole = POWER_ROLE_SOURCE;
break;
default:
- newPowerRole = UsbPort.POWER_ROLE_NONE;
+ newPowerRole = POWER_ROLE_NONE;
}
}
if (mPort != null) {
- mUsbManager.setPortRoles(mPort, newPowerRole, role);
+ mPort.setRoles(newPowerRole, role);
}
}
public boolean areAllRolesSupported() {
return mPort != null && mPortStatus != null
- && mPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE)
- && mPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST)
- && mPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE)
- && mPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
+ && mPortStatus.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE)
+ && mPortStatus.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
+ && mPortStatus.isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_DEVICE)
+ && mPortStatus.isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_HOST);
}
public static String usbFunctionsToString(long functions) {
@@ -205,17 +210,14 @@
private void updatePorts() {
mPort = null;
mPortStatus = null;
- UsbPort[] ports = mUsbManager.getPorts();
- if (ports == null) {
- return;
- }
+ List<UsbPort> ports = mUsbManager.getPorts();
// For now look for a connected port, in the future we should identify port in the
// notification and pick based on that.
- final int N = ports.length;
+ final int N = ports.size();
for (int i = 0; i < N; i++) {
- UsbPortStatus status = mUsbManager.getPortStatus(ports[i]);
+ UsbPortStatus status = ports.get(i).getStatus();
if (status.isConnected()) {
- mPort = ports[i];
+ mPort = ports.get(i);
mPortStatus = status;
break;
}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
index 1d43371..beb2375 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java
@@ -49,8 +49,8 @@
mUsbBackend = backend;
mFunctions = UsbManager.FUNCTION_NONE;
- mDataRole = UsbPort.DATA_ROLE_NONE;
- mPowerRole = UsbPort.POWER_ROLE_NONE;
+ mDataRole = UsbPortStatus.DATA_ROLE_NONE;
+ mPowerRole = UsbPortStatus.POWER_ROLE_NONE;
}
@Override
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
index 84576b1..a584c11 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java
@@ -16,6 +16,10 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+
import android.content.Context;
import android.hardware.usb.UsbPort;
@@ -55,23 +59,23 @@
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreferenceCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
- mHostPref = makeRadioPreference(UsbBackend.dataRoleToString(UsbPort.DATA_ROLE_HOST),
+ mHostPref = makeRadioPreference(UsbBackend.dataRoleToString(DATA_ROLE_HOST),
R.string.usb_control_host);
- mDevicePref = makeRadioPreference(UsbBackend.dataRoleToString(UsbPort.DATA_ROLE_DEVICE),
+ mDevicePref = makeRadioPreference(UsbBackend.dataRoleToString(DATA_ROLE_DEVICE),
R.string.usb_control_device);
}
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
- if (dataRole == UsbPort.DATA_ROLE_DEVICE) {
+ if (dataRole == DATA_ROLE_DEVICE) {
mDevicePref.setChecked(true);
mHostPref.setChecked(false);
mPreferenceCategory.setEnabled(true);
- } else if (dataRole == UsbPort.DATA_ROLE_HOST) {
+ } else if (dataRole == DATA_ROLE_HOST) {
mDevicePref.setChecked(false);
mHostPref.setChecked(true);
mPreferenceCategory.setEnabled(true);
- } else if (!connected || dataRole == UsbPort.DATA_ROLE_NONE){
+ } else if (!connected || dataRole == DATA_ROLE_NONE){
mPreferenceCategory.setEnabled(false);
if (mNextRolePref == null) {
// Disconnected with no operation pending, so clear subtexts
@@ -80,7 +84,7 @@
}
}
- if (mNextRolePref != null && dataRole != UsbPort.DATA_ROLE_NONE) {
+ if (mNextRolePref != null && dataRole != DATA_ROLE_NONE) {
if (UsbBackend.dataRoleFromString(mNextRolePref.getKey()) == dataRole) {
// Clear switching text if switch succeeded
mNextRolePref.setSummary("");
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
index f74dc0f..283e56b 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
@@ -16,6 +16,7 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
import static android.net.ConnectivityManager.TETHERING_USB;
import android.content.Context;
@@ -88,7 +89,7 @@
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
- if (!connected || dataRole != UsbPort.DATA_ROLE_DEVICE) {
+ if (!connected || dataRole != DATA_ROLE_DEVICE) {
mProfilesContainer.setEnabled(false);
} else {
// Functions are only available in device mode
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
index 30314f6..b59890a 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleController.java
@@ -16,8 +16,13 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
import android.content.Context;
import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
@@ -40,16 +45,16 @@
private int mNextPowerRole;
private final Runnable mFailureCallback = () -> {
- if (mNextPowerRole != UsbPort.POWER_ROLE_NONE) {
+ if (mNextPowerRole != POWER_ROLE_NONE) {
mSwitchPreference.setSummary(R.string.usb_switching_failed);
- mNextPowerRole = UsbPort.POWER_ROLE_NONE;
+ mNextPowerRole = POWER_ROLE_NONE;
}
};
public UsbDetailsPowerRoleController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
- mNextPowerRole = UsbPort.POWER_ROLE_NONE;
+ mNextPowerRole = POWER_ROLE_NONE;
}
@Override
@@ -70,20 +75,21 @@
} else if (connected && mUsbBackend.areAllRolesSupported()){
mFragment.getPreferenceScreen().addPreference(mPreferenceCategory);
}
- if (powerRole == UsbPort.POWER_ROLE_SOURCE) {
+ if (powerRole == POWER_ROLE_SOURCE) {
mSwitchPreference.setChecked(true);
mPreferenceCategory.setEnabled(true);
- } else if (powerRole == UsbPort.POWER_ROLE_SINK) {
+ } else if (powerRole == POWER_ROLE_SINK) {
mSwitchPreference.setChecked(false);
mPreferenceCategory.setEnabled(true);
- } else if (!connected || powerRole == UsbPort.POWER_ROLE_NONE){
+ } else if (!connected || powerRole == POWER_ROLE_NONE){
mPreferenceCategory.setEnabled(false);
- if (mNextPowerRole == UsbPort.POWER_ROLE_NONE) {
+ if (mNextPowerRole == POWER_ROLE_NONE) {
mSwitchPreference.setSummary("");
}
}
- if (mNextPowerRole != UsbPort.POWER_ROLE_NONE && powerRole != UsbPort.POWER_ROLE_NONE) {
+ if (mNextPowerRole != POWER_ROLE_NONE
+ && powerRole != POWER_ROLE_NONE) {
if (mNextPowerRole == powerRole) {
// Clear switching text if switch succeeded
mSwitchPreference.setSummary("");
@@ -91,16 +97,16 @@
// Set failure text if switch failed
mSwitchPreference.setSummary(R.string.usb_switching_failed);
}
- mNextPowerRole = UsbPort.POWER_ROLE_NONE;
+ mNextPowerRole = POWER_ROLE_NONE;
mHandler.removeCallbacks(mFailureCallback);
}
}
@Override
public boolean onPreferenceClick(Preference preference) {
- int newRole = mSwitchPreference.isChecked() ? UsbPort.POWER_ROLE_SOURCE
- : UsbPort.POWER_ROLE_SINK;
- if (mUsbBackend.getPowerRole() != newRole && mNextPowerRole == UsbPort.POWER_ROLE_NONE
+ int newRole = mSwitchPreference.isChecked() ? POWER_ROLE_SOURCE
+ : POWER_ROLE_SINK;
+ if (mUsbBackend.getPowerRole() != newRole && mNextPowerRole == POWER_ROLE_NONE
&& !Utils.isMonkeyRunning()) {
mUsbBackend.setPowerRole(newRole);
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index b350778..7f14c0d 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -27,4 +27,5 @@
public static final String WIFI_MAC_RANDOMIZATION = "settings_wifi_mac_randomization";
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
public static final String WIFI_SHARING = "settings_wifi_sharing";
+ public static final String SLICE_INJECTION = "settings_slice_injection";
}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 56e9ee5..1916110 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -295,7 +295,13 @@
if (!controller.isAvailable()) {
continue;
}
+
final String key = controller.getPreferenceKey();
+ if (TextUtils.isEmpty(key)) {
+ Log.d(TAG, String.format("Preference key is %s in Controller %s",
+ key, controller.getClass().getSimpleName()));
+ continue;
+ }
final Preference preference = screen.findPreference(key);
if (preference == null) {
diff --git a/src/com/android/settings/fuelgauge/BatterySaverController.java b/src/com/android/settings/fuelgauge/BatterySaverController.java
index 28cc893..cd32c6c 100644
--- a/src/com/android/settings/fuelgauge/BatterySaverController.java
+++ b/src/com/android/settings/fuelgauge/BatterySaverController.java
@@ -15,6 +15,7 @@
*/
package com.android.settings.fuelgauge;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -22,6 +23,7 @@
import android.os.PowerManager;
import android.provider.Settings;
+import android.provider.Settings.Global;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -31,6 +33,7 @@
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.fuelgauge.BatterySaverUtils;
public class BatterySaverController extends BasePreferenceController
implements LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
@@ -45,6 +48,7 @@
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mBatteryStateChangeReceiver = new BatterySaverReceiver(context);
mBatteryStateChangeReceiver.setBatterySaverListener(this);
+ BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
}
@Override
@@ -81,16 +85,23 @@
@Override
public CharSequence getSummary() {
+ final ContentResolver resolver = mContext.getContentResolver();
final boolean isPowerSaveOn = mPowerManager.isPowerSaveMode();
- final int percent = Settings.Global.getInt(mContext.getContentResolver(),
+ final int percent = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ final int mode = Settings.Global.getInt(resolver,
+ Global.AUTOMATIC_POWER_SAVER_MODE, PowerManager.POWER_SAVER_MODE_PERCENTAGE);
if (isPowerSaveOn) {
return mContext.getString(R.string.battery_saver_on_summary);
- } else if (percent != 0) {
- return mContext.getString(R.string.battery_saver_off_scheduled_summary,
- Utils.formatPercentage(percent));
+ } else if (mode == PowerManager.POWER_SAVER_MODE_PERCENTAGE) {
+ if (percent != 0) {
+ return mContext.getString(R.string.battery_saver_off_scheduled_summary,
+ Utils.formatPercentage(percent));
+ } else {
+ return mContext.getString(R.string.battery_saver_off_summary);
+ }
} else {
- return mContext.getString(R.string.battery_saver_off_summary);
+ return mContext.getString(R.string.battery_saver_auto_routine);
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c071284..6f77953 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -449,12 +449,14 @@
final BatteryStats stats = statsHelper.getStats();
BatteryInfo batteryInfo;
- final Estimate estimate;
+ Estimate estimate = null;
// Get enhanced prediction if available
if (mPowerUsageFeatureProvider != null &&
mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {
estimate = mPowerUsageFeatureProvider.getEnhancedBatteryPrediction(mContext);
- } else {
+ }
+
+ if (estimate == null) {
estimate = new Estimate(
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)),
false /* isBasedOnUsage */,
diff --git a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceController.java
deleted file mode 100644
index c0ecbf9..0000000
--- a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceController.java
+++ /dev/null
@@ -1,70 +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.fuelgauge.batterysaver;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.core.TogglePreferenceController;
-import com.android.settingslib.fuelgauge.BatterySaverUtils;
-
-/**
- * Controller that update whether to turn on battery saver automatically
- */
-public class AutoBatterySaverPreferenceController extends TogglePreferenceController implements
- Preference.OnPreferenceChangeListener {
-
- /**
- * Default value for {@link Settings.Global#LOW_POWER_MODE_TRIGGER_LEVEL}.
- */
- static final int DEFAULT_TRIGGER_LEVEL = 0;
-
- /**
- * The default value to set to {@link Settings.Global#LOW_POWER_MODE_TRIGGER_LEVEL} when the
- * user enables battery saver.
- */
- private final int mDefaultTriggerLevelForOn;
-
- @VisibleForTesting
- static final String KEY_AUTO_BATTERY_SAVER = "auto_battery_saver";
-
- public AutoBatterySaverPreferenceController(Context context) {
- super(context, KEY_AUTO_BATTERY_SAVER);
- mDefaultTriggerLevelForOn = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryWarningLevel);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return AVAILABLE;
- }
-
- @Override
- public boolean isChecked() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, DEFAULT_TRIGGER_LEVEL) != 0;
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- BatterySaverUtils.setAutoBatterySaverTriggerLevel(mContext,
- isChecked ? mDefaultTriggerLevelForOn : 0);
- return true;
- }
-}
diff --git a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java
deleted file mode 100644
index 0fbba0b..0000000
--- a/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceController.java
+++ /dev/null
@@ -1,166 +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.fuelgauge.batterysaver;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
-import com.android.settings.widget.SeekBarPreference;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
-
-/**
- * Controller that update the battery saver seekbar
- */
-public class AutoBatterySeekBarPreferenceController extends BasePreferenceController implements
- LifecycleObserver, OnStart, OnStop, SeekBarPreference.OnPreferenceChangeListener {
- private static final String TAG = "AutoBatterySeekBarPreferenceController";
- private static final int INTERVAL = 5;
- @VisibleForTesting
- static final String KEY_AUTO_BATTERY_SEEK_BAR = "battery_saver_seek_bar";
- private SeekBarPreference mPreference;
- private AutoBatterySaverSettingObserver mContentObserver;
-
- public AutoBatterySeekBarPreferenceController(Context context, Lifecycle lifecycle) {
- super(context, KEY_AUTO_BATTERY_SEEK_BAR);
- mContentObserver = new AutoBatterySaverSettingObserver(new Handler(Looper.getMainLooper()));
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = (SeekBarPreference) screen.findPreference(
- KEY_AUTO_BATTERY_SEEK_BAR);
- mPreference.setContinuousUpdates(true);
- mPreference.setAccessibilityRangeInfoType(
- AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_PERCENT);
- updatePreference(mPreference);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return AVAILABLE;
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- updatePreference(preference);
- }
-
- @Override
- public void onStart() {
- mContentObserver.registerContentObserver();
- }
-
- @Override
- public void onStop() {
- mContentObserver.unRegisterContentObserver();
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final int progress = (int) newValue;
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, progress * INTERVAL);
- return true;
- }
-
- @VisibleForTesting
- void updatePreference(Preference preference) {
- final ContentResolver contentResolver = mContext.getContentResolver();
-
- // Override the max value with LOW_POWER_MODE_TRIGGER_LEVEL_MAX, if set.
- final int maxLevel = Settings.Global.getInt(contentResolver,
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 0) / INTERVAL;
- if (maxLevel > 0) {
- if (!(preference instanceof SeekBarPreference)) {
- Log.e(TAG, "Unexpected preference class: " + preference.getClass());
- } else {
- final SeekBarPreference seekBarPreference = (SeekBarPreference) preference;
- if (maxLevel < seekBarPreference.getMin()) {
- Log.e(TAG, "LOW_POWER_MODE_TRIGGER_LEVEL_MAX too low; ignored.");
- } else {
- seekBarPreference.setMax(maxLevel);
- }
- }
- }
-
- // Set the current value.
- final int level = Settings.Global.getInt(contentResolver,
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
- AutoBatterySaverPreferenceController.DEFAULT_TRIGGER_LEVEL);
- if (level == 0) {
- preference.setVisible(false);
- } else {
- preference.setVisible(true);
- preference.setTitle(mContext.getString(R.string.battery_saver_seekbar_title,
- Utils.formatPercentage(level)));
- SeekBarPreference seekBarPreference = (SeekBarPreference) preference;
- seekBarPreference.setProgress(level / INTERVAL);
- seekBarPreference.setSeekBarContentDescription(
- mContext.getString(R.string.battery_saver_turn_on_automatically_title));
- }
- }
-
- /**
- * Observer that listens to change from {@link Settings.Global#LOW_POWER_MODE_TRIGGER_LEVEL}
- */
- private final class AutoBatterySaverSettingObserver extends ContentObserver {
- private final Uri mUri = Settings.Global.getUriFor(
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
- private final ContentResolver mContentResolver;
-
- public AutoBatterySaverSettingObserver(Handler handler) {
- super(handler);
- mContentResolver = mContext.getContentResolver();
- }
-
- public void registerContentObserver() {
- mContentResolver.registerContentObserver(mUri, false, this);
- }
-
- public void unRegisterContentObserver() {
- mContentResolver.unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (mUri.equals(uri)) {
- updatePreference(mPreference);
- }
- }
- }
-}
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java
index cc6aa00..868c73f 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSchedulePreferenceController.java
@@ -26,7 +26,13 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.fuelgauge.BatterySaverUtils;
+/**
+ * Simple controller to navigate users to the scheduling page from
+ * "Settings > Battery > Battery Saver". Also updates the summary for preference based on
+ * the currently selected settings.
+ */
public class BatterySaverSchedulePreferenceController extends BasePreferenceController {
@VisibleForTesting
@@ -36,6 +42,7 @@
public BatterySaverSchedulePreferenceController(Context context) {
super(context, KEY_BATTERY_SAVER_SCHEDULE);
+ BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
new file mode 100644
index 0000000..d49eb0a
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
@@ -0,0 +1,91 @@
+/*
+ * 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.fuelgauge.batterysaver;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+
+/**
+ * Responds to user actions in the Settings > Battery > Set a Schedule Screen
+ *
+ * Note that this is not a preference controller since that screen does not inherit from
+ * DashboardFragment.
+ *
+ * Will call the appropriate power manager APIs and modify the correct settings to enable
+ * users to control their automatic battery saver toggling preferences.
+ * See {@link Settings.Global#AUTOMATIC_POWER_SAVER_MODE} for more details.
+ */
+public class BatterySaverScheduleRadioButtonsController {
+
+ public static final String KEY_NO_SCHEDULE = "key_battery_saver_no_schedule";
+ public static final String KEY_ROUTINE = "key_battery_saver_routine";
+ public static final String KEY_PERCENTAGE = "key_battery_saver_percentage";
+
+ private Context mContext;
+ private BatterySaverScheduleSeekBarController mSeekBarController;
+
+ public BatterySaverScheduleRadioButtonsController(Context context,
+ BatterySaverScheduleSeekBarController seekbar) {
+ mContext = context;
+ mSeekBarController = seekbar;
+ }
+
+ public String getDefaultKey() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ // Note: this can also be obtained via PowerManager.getPowerSaveMode()
+ final int mode = Settings.Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ // if mode is "dynamic" we are in routine mode, percentage with non-zero threshold is
+ // percentage mode, otherwise it is no schedule mode
+ if (mode == PowerManager.POWER_SAVER_MODE_PERCENTAGE) {
+ final int threshold =
+ Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ if (threshold <= 0) {
+ return KEY_NO_SCHEDULE;
+ }
+ return KEY_PERCENTAGE;
+ }
+ return KEY_ROUTINE;
+ }
+
+ public boolean setDefaultKey(String key) {
+ final ContentResolver resolver = mContext.getContentResolver();
+ switch(key) {
+ case KEY_NO_SCHEDULE:
+ Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ break;
+ case KEY_PERCENTAGE:
+ Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
+ break;
+ case KEY_ROUTINE:
+ Settings.Global.putInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Not a valid key for " + this.getClass().getSimpleName());
+ }
+ mSeekBarController.updateSeekBar();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarController.java
new file mode 100644
index 0000000..215f400
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarController.java
@@ -0,0 +1,100 @@
+/*
+ * 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.fuelgauge.batterysaver;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+import androidx.preference.PreferenceScreen;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.widget.SeekBarPreference;
+
+/**
+ * Responds to user actions in the Settings > Battery > Set a Schedule Screen for the seekbar.
+ * Note that this seekbar is only visible when the radio button selected is "Percentage".
+ *
+ * Note that this is not a preference controller since that screen does not inherit from
+ * DashboardFragment.
+ *
+ * Will call the appropriate power manager APIs and modify the correct settings to enable
+ * users to control their automatic battery saver toggling preferences.
+ * See {@link Settings.Global#AUTOMATIC_POWER_SAVER_MODE} for more details.
+ */
+public class BatterySaverScheduleSeekBarController implements
+ OnPreferenceChangeListener {
+
+ public static final int MAX_SEEKBAR_VALUE = 15;
+ public static final int MIN_SEEKBAR_VALUE = 1;
+ public static final String KEY_BATTERY_SAVER_SEEK_BAR = "battery_saver_seek_bar";
+
+ @VisibleForTesting
+ public SeekBarPreference mSeekBarPreference;
+ private Context mContext;
+
+ public BatterySaverScheduleSeekBarController(Context context) {
+ mContext = context;
+ mSeekBarPreference = new SeekBarPreference(context);
+ mSeekBarPreference.setOnPreferenceChangeListener(this);
+ mSeekBarPreference.setMax(BatterySaverScheduleSeekBarController.MAX_SEEKBAR_VALUE);
+ mSeekBarPreference.setMin(BatterySaverScheduleSeekBarController.MIN_SEEKBAR_VALUE);
+ mSeekBarPreference.setKey(KEY_BATTERY_SAVER_SEEK_BAR);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ // The nits are in intervals of 5%
+ final int percentage = ((Integer) newValue) * 5;
+ Settings.Global.putInt(mContext.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+ percentage);
+ preference.setTitle(mContext.getString(
+ R.string.battery_saver_seekbar_title, Utils.formatPercentage(percentage)));
+ return true;
+ }
+
+ public void updateSeekBar() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ // Note: this can also be obtained via PowerManager.getPowerSaveMode()
+ final int mode = Settings.Global.getInt(resolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ // if mode is "dynamic" we are in routine mode, percentage with non-zero threshold is
+ // percentage mode, otherwise it is no schedule mode
+ if (mode == PowerManager.POWER_SAVER_MODE_PERCENTAGE) {
+ final int threshold =
+ Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ if (threshold <= 0) {
+ mSeekBarPreference.setVisible(false);
+ } else {
+ mSeekBarPreference.setVisible(true);
+ mSeekBarPreference.setProgress(MIN_SEEKBAR_VALUE);
+ mSeekBarPreference.setTitle(mContext.getString(
+ R.string.battery_saver_seekbar_title,
+ Utils.formatPercentage(MIN_SEEKBAR_VALUE * 5)));
+ }
+ } else {
+ mSeekBarPreference.setVisible(false);
+ }
+ }
+
+ public void addToScreen(PreferenceScreen screen) {
+ screen.addPreference(mSeekBarPreference);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
index fad9f31..6e9c711 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSettings.java
@@ -18,24 +18,32 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.text.TextUtils;
import android.view.View;
import androidx.preference.PreferenceScreen;
import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settings.R;
import com.android.settings.widget.RadioButtonPreference;
-import com.android.settings.widget.SeekBarPreference;
+import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.widget.CandidateInfo;
import com.google.common.collect.Lists;
import java.util.List;
+/**
+ * Fragment that allows users to customize their automatic battery saver mode settings.
+ *
+ * Location: Settings > Battery > Battery Saver > Set a Schedule
+ * See {@link BatterySaverSchedulePreferenceController} for the controller that manages navigation
+ * to this screen from "Settings > Battery > Battery Saver" and the summary.
+ * See {@link BatterySaverScheduleRadioButtonsController} &
+ * {@link BatterySaverScheduleSeekBarController} for the controller that manages user
+ * interactions in this screen.
+ */
public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
- private static final String KEY_NO_SCHEDULE = "key_battery_saver_no_schedule";
- private static final String KEY_ROUTINE = "key_battery_saver_routine";
- private static final String KEY_PERCENTAGE = "key_battery_saver_percentage";
- public static final int MAX_SEEKBAR_VALUE = 15;
- public static final int MIN_SEEKBAR_VALUE = 1;
- public static final String KEY_BATTERY_SAVER_SEEK_BAR = "battery_saver_seek_bar";
+ public BatterySaverScheduleRadioButtonsController mRadioButtonController;
+ private BatterySaverScheduleSeekBarController mSeekBarController;
@Override
protected int getPreferenceScreenResId() {
@@ -43,23 +51,44 @@
}
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mSeekBarController = new BatterySaverScheduleSeekBarController(context);
+ mRadioButtonController = new BatterySaverScheduleRadioButtonsController(
+ context, mSeekBarController);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
protected List<? extends CandidateInfo> getCandidates() {
Context context = getContext();
List<CandidateInfo> candidates = Lists.newArrayList();
+ String routineProviderApp = getContext().getResources()
+ .getString(com.android.internal.R.string.config_batterySaverScheduleProvider);
candidates.add(new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_no_schedule),
/* summary */ null,
- KEY_NO_SCHEDULE,
+ BatterySaverScheduleRadioButtonsController.KEY_NO_SCHEDULE,
/* enabled */ true));
- candidates.add(new BatterySaverScheduleCandidateInfo(
- context.getText(R.string.battery_saver_auto_routine),
- context.getText(R.string.battery_saver_auto_routine_summary),
- KEY_ROUTINE,
- /* enabled */ true));
+ // only add routine option if an app has been specified
+ if (!TextUtils.isEmpty(routineProviderApp)) {
+ candidates.add(new BatterySaverScheduleCandidateInfo(
+ context.getText(R.string.battery_saver_auto_routine),
+ context.getText(R.string.battery_saver_auto_routine_summary),
+ BatterySaverScheduleRadioButtonsController.KEY_ROUTINE,
+ /* enabled */ true));
+ } else {
+ // Make sure routine is not selected if no provider app is configured
+ BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
+ }
candidates.add(new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_percentage),
/* summary */ null,
- KEY_PERCENTAGE,
+ BatterySaverScheduleRadioButtonsController.KEY_PERCENTAGE,
/* enabled */ true));
return candidates;
@@ -79,22 +108,18 @@
@Override
protected void addStaticPreferences(PreferenceScreen screen) {
- SeekBarPreference seekbar = new SeekBarPreference(getContext());
- seekbar.setMax(MAX_SEEKBAR_VALUE);
- seekbar.setMin(MIN_SEEKBAR_VALUE);
- seekbar.setTitle(R.string.battery_saver_seekbar_title_placeholder);
- seekbar.setKey(KEY_BATTERY_SAVER_SEEK_BAR);
- screen.addPreference(seekbar);
+ mSeekBarController.updateSeekBar();
+ mSeekBarController.addToScreen(screen);
}
@Override
protected String getDefaultKey() {
- return null;
+ return mRadioButtonController.getDefaultKey();
}
@Override
protected boolean setDefaultKey(String key) {
- return false;
+ return mRadioButtonController.setDefaultKey(key);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettings.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettings.java
index 8b0409c..6aef9b5 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettings.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverSettings.java
@@ -61,23 +61,10 @@
}
@Override
- protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getSettingsLifecycle());
- }
-
- @Override
public int getHelpResource() {
return R.string.help_url_battery_saver_settings;
}
- private static List<AbstractPreferenceController> buildPreferenceControllers(
- Context context, Lifecycle lifecycle) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new AutoBatterySaverPreferenceController(context));
- controllers.add(new AutoBatterySeekBarPreferenceController(context, lifecycle));
- return controllers;
- }
-
/**
* For Search.
*/
@@ -90,11 +77,5 @@
sir.xmlResId = R.xml.battery_saver_settings;
return Arrays.asList(sir);
}
-
- @Override
- public List<AbstractPreferenceController> createPreferenceControllers(
- Context context) {
- return buildPreferenceControllers(context, null);
- }
};
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
index 5ebc924..b1e9d33 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProvider.java
@@ -16,24 +16,21 @@
package com.android.settings.homepage.contextualcards;
-import android.content.Context;
-
import java.util.List;
/** Feature provider for the contextual card feature. */
public interface ContextualCardFeatureProvider {
/** Homepage displays. */
- void logHomepageDisplay(Context context, long latency);
+ void logHomepageDisplay(long latency);
/** When user clicks dismiss in contextual card */
- void logContextualCardDismiss(Context context, ContextualCard card);
+ void logContextualCardDismiss(ContextualCard card);
/** After ContextualCardManager decides which cards will be displayed/hidden */
- void logContextualCardDisplay(Context context, List<ContextualCard> showedCards,
+ void logContextualCardDisplay(List<ContextualCard> showedCards,
List<ContextualCard> hiddenCards);
/** When user clicks toggle/title area of a contextual card. */
- void logContextualCardClick(Context context, ContextualCard card, int row,
- int tapTarget);
+ void logContextualCardClick(ContextualCard card, int row, int tapTarget);
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
index dc295fc..12590ff 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImpl.java
@@ -51,6 +51,9 @@
// contextual card name
private static final String EXTRA_CONTEXTUALCARD_NAME = "name";
+ // contextual card uri
+ private static final String EXTRA_CONTEXTUALCARD_URI = "uri";
+
// contextual card score
private static final String EXTRA_CONTEXTUALCARD_SCORE = "score";
@@ -84,51 +87,59 @@
// Click slider
private static final int TARGET_SLIDER = 3;
+ private final Context mContext;
+
+ public ContextualCardFeatureProviderImpl(Context context) {
+ mContext = context;
+ }
+
@Override
- public void logHomepageDisplay(Context context, long latency) {
- sendBroadcast(context, new Intent()
+ public void logHomepageDisplay(long latency) {
+ sendBroadcast(new Intent()
.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_HOME_SHOW)
.putExtra(EXTRA_LATENCY, latency));
}
@Override
- public void logContextualCardDismiss(Context context, ContextualCard card) {
+ public void logContextualCardDismiss(ContextualCard card) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_DISMISS);
intent.putExtra(EXTRA_CONTEXTUALCARD_NAME, card.getName());
+ intent.putExtra(EXTRA_CONTEXTUALCARD_URI, card.getSliceUri().toString());
intent.putExtra(EXTRA_CONTEXTUALCARD_SCORE, card.getRankingScore());
- sendBroadcast(context, intent);
+ sendBroadcast(intent);
}
@Override
- public void logContextualCardDisplay(Context context, List<ContextualCard> visibleCards,
+ public void logContextualCardDisplay(List<ContextualCard> visibleCards,
List<ContextualCard> hiddenCards) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_SHOW);
intent.putExtra(EXTRA_CONTEXTUALCARD_VISIBLE, serialize(visibleCards));
intent.putExtra(EXTRA_CONTEXTUALCARD_HIDDEN, serialize(hiddenCards));
- sendBroadcast(context, intent);
+ sendBroadcast(intent);
}
@Override
- public void logContextualCardClick(Context context, ContextualCard card, int row,
+ public void logContextualCardClick(ContextualCard card, int row,
int actionType) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_CONTEXTUALCARD_ACTION_TYPE, CONTEXTUAL_CARD_CLICK);
intent.putExtra(EXTRA_CONTEXTUALCARD_NAME, card.getName());
+ intent.putExtra(EXTRA_CONTEXTUALCARD_URI, card.getSliceUri().toString());
intent.putExtra(EXTRA_CONTEXTUALCARD_SCORE, card.getRankingScore());
intent.putExtra(EXTRA_CONTEXTUALCARD_ROW, row);
intent.putExtra(EXTRA_CONTEXTUALCARD_TAP_TARGET, actionTypeToTapTarget(actionType));
- sendBroadcast(context, intent);
+ sendBroadcast(intent);
}
@VisibleForTesting
- void sendBroadcast(final Context context, final Intent intent) {
- intent.setPackage(context.getString(R.string.config_settingsintelligence_package_name));
- final String action = context.getString(R.string.config_settingsintelligence_log_action);
+ void sendBroadcast(final Intent intent) {
+ intent.setPackage(mContext.getString(R.string.config_settingsintelligence_package_name));
+ final String action = mContext.getString(R.string.config_settingsintelligence_log_action);
if (!TextUtils.isEmpty(action)) {
intent.setAction(action);
- context.sendBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
index 71b262d..88478e3 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLoader.java
@@ -21,7 +21,7 @@
import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
import static com.android.settings.slices.CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI;
-import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
+import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -149,10 +149,10 @@
// Two large cards
return visibleCards;
} finally {
+ //TODO(b/121196921): Should not call this if user click dismiss
final ContextualCardFeatureProvider contextualCardFeatureProvider =
- FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
- contextualCardFeatureProvider.logContextualCardDisplay(mContext, visibleCards,
- hiddenCards);
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+ contextualCardFeatureProvider.logContextualCardDisplay(visibleCards, hiddenCards);
}
}
@@ -204,7 +204,7 @@
}
private boolean isLargeCard(ContextualCard card) {
- return card.getSliceUri().equals(WIFI_SLICE_URI)
+ return card.getSliceUri().equals(CONTEXTUAL_WIFI_SLICE_URI)
|| card.getSliceUri().equals(BLUETOOTH_DEVICES_SLICE_URI);
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 24266ee..067de7c 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -35,6 +35,7 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import java.util.ArrayList;
import java.util.List;
@@ -56,7 +57,9 @@
* get the page refreshed.
*/
public class ContextualCardManager implements ContextualCardLoader.CardContentLoaderListener,
- ContextualCardUpdateListener {
+ ContextualCardUpdateListener, LifecycleObserver, OnSaveInstanceState {
+
+ private static final String KEY_CONTEXTUAL_CARDS = "key_contextual_cards";
private static final String TAG = "ContextualCardManager";
@@ -68,6 +71,9 @@
final List<ContextualCard> mContextualCards;
@VisibleForTesting
long mStartTime;
+ boolean mIsFirstLaunch;
+ @VisibleForTesting
+ List<String> mSavedCards;
private final Context mContext;
private final ControllerRendererPool mControllerRendererPool;
@@ -76,12 +82,20 @@
private ContextualCardUpdateListener mListener;
- public ContextualCardManager(Context context, Lifecycle lifecycle) {
+ public ContextualCardManager(Context context, Lifecycle lifecycle, Bundle savedInstanceState) {
mContext = context;
mLifecycle = lifecycle;
mContextualCards = new ArrayList<>();
mLifecycleObservers = new ArrayList<>();
mControllerRendererPool = new ControllerRendererPool();
+ mLifecycle.addObserver(this);
+
+ if (savedInstanceState == null) {
+ mIsFirstLaunch = true;
+ mSavedCards = null;
+ } else {
+ mSavedCards = savedInstanceState.getStringArrayList(KEY_CONTEXTUAL_CARDS);
+ }
//for data provided by Settings
for (@ContextualCard.CardType int cardType : SETTINGS_CARDS) {
setupController(cardType);
@@ -172,13 +186,34 @@
@Override
public void onFinishCardLoading(List<ContextualCard> cards) {
final long loadTime = System.currentTimeMillis() - mStartTime;
+ final List<ContextualCard> cardsToKeep = getCardsToKeep(cards);
+
+ //navigate back to the homepage or after card dismissal
+ if (!mIsFirstLaunch) {
+ onContextualCardUpdated(cardsToKeep.stream()
+ .collect(groupingBy(ContextualCard::getCardType)));
+ return;
+ }
+
+ //only log homepage display upon a fresh launch
if (loadTime <= ContextualCardLoader.CARD_CONTENT_LOADER_TIMEOUT_MS) {
- onContextualCardUpdated(
- cards.stream().collect(groupingBy(ContextualCard::getCardType)));
+ onContextualCardUpdated(cards.stream()
+ .collect(groupingBy(ContextualCard::getCardType)));
}
final long totalTime = System.currentTimeMillis() - mStartTime;
- FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider()
- .logHomepageDisplay(mContext, totalTime);
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext)
+ .logHomepageDisplay(totalTime);
+
+ mIsFirstLaunch = false;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ final ArrayList<String> cards = mContextualCards.stream()
+ .map(ContextualCard::getName)
+ .collect(Collectors.toCollection(ArrayList::new));
+
+ outState.putStringArrayList(KEY_CONTEXTUAL_CARDS, cards);
}
public ControllerRendererPool getControllerRendererPool() {
@@ -189,6 +224,22 @@
mListener = listener;
}
+ private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
+ if (mSavedCards != null) {
+ //screen rotate
+ final List<ContextualCard> cardsToKeep = cards.stream()
+ .filter(card -> mSavedCards.contains(card.getName()))
+ .collect(Collectors.toList());
+ mSavedCards = null;
+ return cardsToKeep;
+ } else {
+ //navigate back to the homepage or after dismissing a card
+ return cards.stream()
+ .filter(card -> mContextualCards.contains(card))
+ .collect(Collectors.toList());
+ }
+ }
+
static class CardContentLoaderCallbacks implements
LoaderManager.LoaderCallbacks<List<ContextualCard>> {
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
index 5f9bf0d..e598e4c 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java
@@ -42,7 +42,8 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle());
+ mContextualCardManager = new ContextualCardManager(getContext(), getSettingsLifecycle(),
+ savedInstanceState);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index d5500fb..5797043 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -34,8 +34,8 @@
public ContextualCardList getContextualCards() {
final ContextualCard wifiCard =
ContextualCard.newBuilder()
- .setSliceUri(CustomSliceRegistry.WIFI_SLICE_URI.toString())
- .setCardName(CustomSliceRegistry.WIFI_SLICE_URI.toString())
+ .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString())
+ .setCardName(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString())
.setCardCategory(ContextualCard.Category.IMPORTANT)
.build();
final ContextualCard connectedDeviceCard =
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java
deleted file mode 100644
index bce7c5d..0000000
--- a/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionController.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.homepage.contextualcards.conditional;
-
-import android.content.Context;
-import android.os.PowerManager;
-
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.fuelgauge.BatterySaverReceiver;
-import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
-import com.android.settings.homepage.contextualcards.ContextualCard;
-import com.android.settingslib.fuelgauge.BatterySaverUtils;
-
-import java.util.Objects;
-
-public class BatterySaverConditionController implements ConditionalCardController,
- BatterySaverReceiver.BatterySaverListener {
- static final int ID = Objects.hash("BatterySaverConditionController");
-
- private final Context mAppContext;
- private final ConditionManager mConditionManager;
- private final BatterySaverReceiver mReceiver;
- private final PowerManager mPowerManager;
-
- public BatterySaverConditionController(Context appContext, ConditionManager conditionManager) {
- mAppContext = appContext;
- mConditionManager = conditionManager;
- mPowerManager = appContext.getSystemService(PowerManager.class);
- mReceiver = new BatterySaverReceiver(appContext);
- mReceiver.setBatterySaverListener(this);
- }
-
- @Override
- public long getId() {
- return ID;
- }
-
- @Override
- public boolean isDisplayable() {
- return mPowerManager.isPowerSaveMode();
- }
-
- @Override
- public void onPrimaryClick(Context context) {
- new SubSettingLauncher(context)
- .setDestination(BatterySaverSettings.class.getName())
- .setSourceMetricsCategory(MetricsProto.MetricsEvent.DASHBOARD_SUMMARY)
- .setTitleRes(R.string.battery_saver)
- .launch();
- }
-
- @Override
- public void onActionClick() {
- BatterySaverUtils.setPowerSaveMode(mAppContext, false,
- /*needFirstTimeWarning*/ false);
- }
-
- @Override
- public ContextualCard buildContextualCard() {
- return new ConditionalContextualCard.Builder()
- .setConditionId(ID)
- .setMetricsConstant(MetricsProto.MetricsEvent.SETTINGS_CONDITION_BATTERY_SAVER)
- .setActionText(mAppContext.getText(R.string.condition_turn_off))
- .setName(mAppContext.getPackageName() + "/"
- + mAppContext.getText(R.string.condition_battery_title))
- .setTitleText(mAppContext.getText(R.string.condition_battery_title).toString())
- .setSummaryText(mAppContext.getText(R.string.condition_battery_summary).toString())
- .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_battery_saver_accent_24dp))
- .setIsHalfWidth(true)
- .build();
- }
-
- @Override
- public void startMonitoringStateChange() {
- mReceiver.setListening(true);
- }
-
- @Override
- public void stopMonitoringStateChange() {
- mReceiver.setListening(false);
- }
-
- @Override
- public void onPowerSaveModeChanged() {
- mConditionManager.onConditionChanged();
- }
-
- @Override
- public void onBatteryChanged(boolean pluggedIn) {
-
- }
-}
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java b/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
index c741b98..39f4903 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/ConditionManager.java
@@ -154,7 +154,6 @@
mCardControllers.add(new AirplaneModeConditionController(mAppContext, this /* manager */));
mCardControllers.add(
new BackgroundDataConditionController(mAppContext, this /* manager */));
- mCardControllers.add(new BatterySaverConditionController(mAppContext, this /* manager */));
mCardControllers.add(new CellularDataConditionController(mAppContext, this /* manager */));
mCardControllers.add(new DndConditionCardController(mAppContext, this /* manager */));
mCardControllers.add(new HotspotConditionController(mAppContext, this /* manager */));
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
index 8720a3c..eb062e8 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardController.java
@@ -70,8 +70,8 @@
});
showFeedbackDialog(card);
final ContextualCardFeatureProvider contextualCardFeatureProvider =
- FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
- contextualCardFeatureProvider.logContextualCardDismiss(mContext, card);
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+ contextualCardFeatureProvider.logContextualCardDismiss(card);
}
@Override
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 172c3b2..17e9d48 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -173,8 +173,9 @@
if (sliceItem.getSlice().getUri().toString().startsWith(
card.getSliceUri().toString())) {
ContextualCardFeatureProvider contexualCardFeatureProvider =
- FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider();
- contexualCardFeatureProvider.logContextualCardClick(mContext, card,
+ FeatureFactory.getFactory(mContext)
+ .getContextualCardFeatureProvider(mContext);
+ contexualCardFeatureProvider.logContextualCardClick(card,
eventInfo.rowIndex, eventInfo.actionType);
break;
}
diff --git a/src/com/android/settings/location/AppLocationPermissionPreferenceController.java b/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
index f920fdc..5bfc584 100644
--- a/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
+++ b/src/com/android/settings/location/AppLocationPermissionPreferenceController.java
@@ -1,18 +1,38 @@
package com.android.settings.location;
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
import android.content.Context;
+import android.location.LocationManager;
+import android.permission.RuntimePermissionPresenter;
import android.provider.Settings;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
public class AppLocationPermissionPreferenceController extends
- AbstractPreferenceController implements PreferenceControllerMixin {
+ LocationBasePreferenceController implements PreferenceControllerMixin {
private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
+ /** Total number of apps that has location permission. */
+ private int mNumTotal = -1;
+ /** Total number of apps that has background location permission. */
+ private int mNumBackground = -1;
+ private final LocationManager mLocationManager;
+ private Preference mPreference;
- public AppLocationPermissionPreferenceController(Context context) {
- super(context);
+ public AppLocationPermissionPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context, lifecycle);
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
@Override
@@ -25,4 +45,53 @@
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, 1) == 1;
}
+
+ @Override
+ public CharSequence getSummary() {
+ if (mLocationManager.isLocationEnabled()) {
+ if (mNumTotal == -1 || mNumBackground == -1) {
+ return mContext.getString(R.string.location_settings_loading_app_permission_stats);
+ }
+ return mContext.getResources().getQuantityString(
+ R.plurals.location_app_permission_summary_location_on, mNumBackground,
+ mNumBackground, mNumTotal);
+ } else {
+ return mContext.getString(R.string.location_app_permission_summary_location_off);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ mPreference = preference;
+ final AtomicInteger loadingInProgress = new AtomicInteger(2);
+ refreshSummary(preference);
+ // Bail out if location has been disabled.
+ if (!mLocationManager.isLocationEnabled()) {
+ return;
+ }
+ RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
+ (numApps) -> {
+ mNumTotal = numApps;
+ if (loadingInProgress.decrementAndGet() == 0) {
+ refreshSummary(preference);
+ }
+ }, null);
+
+ RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ Collections.singletonList(ACCESS_BACKGROUND_LOCATION), true, false,
+ (numApps) -> {
+ mNumBackground = numApps;
+ if (loadingInProgress.decrementAndGet() == 0) {
+ refreshSummary(preference);
+ }
+ }, null);
+ }
+
+ @Override
+ public void onLocationModeChanged(int mode, boolean restricted) {
+ // 'null' is checked inside updateState(), so no need to check here.
+ updateState(mPreference);
+ }
}
diff --git a/src/com/android/settings/location/LocationEnabler.java b/src/com/android/settings/location/LocationEnabler.java
index 20c2280..e1bdf16 100644
--- a/src/com/android/settings/location/LocationEnabler.java
+++ b/src/com/android/settings/location/LocationEnabler.java
@@ -35,15 +35,15 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnPause;
-import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
/**
* A class that listens to location settings change and modifies location settings
* settings.
*/
-public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
+public class LocationEnabler implements LifecycleObserver, OnStart, OnStop {
private static final String TAG = "LocationEnabler";
@VisibleForTesting
@@ -73,7 +73,7 @@
}
@Override
- public void onResume() {
+ public void onStart() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
@Override
@@ -90,12 +90,8 @@
}
@Override
- public void onPause() {
- try {
- mContext.unregisterReceiver(mReceiver);
- } catch (RuntimeException e) {
- // Ignore exceptions caused by race condition
- }
+ public void onStop() {
+ mContext.unregisterReceiver(mReceiver);
}
void refreshLocationMode() {
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 53076e8..4112340 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -35,7 +35,7 @@
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.location.RecentLocationApps;
+import com.android.settingslib.location.RecentLocationAccesses;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
@@ -52,7 +52,7 @@
* <li>In switch bar: location master switch. Used to toggle location on and off.
* </li>
* </ul>
- * <li>Recent location requests: automatically populated by {@link RecentLocationApps}</li>
+ * <li>Recent location requests: automatically populated by {@link RecentLocationAccesses}</li>
* <li>Location services: multi-app settings provided from outside the Android framework. Each
* is injected by a system-partition app via the {@link SettingInjectorService} API.</li>
* </ul>
@@ -122,13 +122,11 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, LocationSettings fragment, Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new AppLocationPermissionPreferenceController(context));
+ controllers.add(new AppLocationPermissionPreferenceController(context, lifecycle));
controllers.add(new LocationForWorkPreferenceController(context, lifecycle));
- controllers.add(
- new RecentLocationRequestPreferenceController(context, fragment, lifecycle));
+ controllers.add(new RecentLocationAccessPreferenceController(context));
controllers.add(new LocationScanningPreferenceController(context));
- controllers.add(
- new LocationServicePreferenceController(context, fragment, lifecycle));
+ controllers.add(new LocationServicePreferenceController(context, fragment, lifecycle));
controllers.add(new LocationFooterPreferenceController(context, lifecycle));
return controllers;
}
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
new file mode 100644
index 0000000..0d5cca5
--- /dev/null
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.settings.location;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.location.RecentLocationAccesses;
+import com.android.settingslib.widget.AppEntitiesHeaderController;
+import com.android.settingslib.widget.LayoutPreference;
+
+import java.util.List;
+
+public class RecentLocationAccessPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin {
+ /** Key for the recent location apps dashboard */
+ private static final String KEY_APPS_DASHBOARD = "apps_dashboard";
+ private final RecentLocationAccesses mRecentLocationAccesses;
+ private AppEntitiesHeaderController mController;
+ private static final int MAXIMUM_APP_COUNT = 3;
+
+ public RecentLocationAccessPreferenceController(Context context) {
+ this(context, new RecentLocationAccesses(context));
+ }
+
+ @VisibleForTesting
+ RecentLocationAccessPreferenceController(Context context,
+ RecentLocationAccesses recentAccesses) {
+ super(context);
+ mRecentLocationAccesses = recentAccesses;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_APPS_DASHBOARD;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ final LayoutPreference preference = (LayoutPreference) screen.findPreference(
+ KEY_APPS_DASHBOARD);
+ final View view = preference.findViewById(R.id.app_entities_header);
+ mController = AppEntitiesHeaderController.newInstance(mContext, view)
+ .setHeaderTitleRes(R.string.location_category_recent_location_access)
+ .setHeaderDetailsRes(R.string.location_recent_location_access_view_details)
+ .setHeaderDetailsClickListener((View v) -> {
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
+ intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+ mContext.startActivity(intent);
+ });
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ updateRecentApps();
+ }
+
+ private void updateRecentApps() {
+ final List<RecentLocationAccesses.Access> recentLocationAccesses =
+ mRecentLocationAccesses.getAppListSorted();
+ if (recentLocationAccesses.size() > 0) {
+ // Display the top 3 preferences to container in original order.
+ int i = 0;
+ for (; i < Math.min(recentLocationAccesses.size(), MAXIMUM_APP_COUNT); i++) {
+ final RecentLocationAccesses.Access access = recentLocationAccesses.get(i);
+ mController.setAppEntity(i, access.icon, access.label, access.contentDescription);
+ }
+ for (; i < MAXIMUM_APP_COUNT; i++) {
+ mController.removeAppEntity(i);
+ }
+ } else {
+ // If there's no item to display, add a "No recent apps" item.
+ }
+ mController.apply();
+ }
+}
diff --git a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java
deleted file mode 100644
index 60374eb..0000000
--- a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package com.android.settings.location;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.dashboard.DashboardFragment;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.location.RecentLocationApps;
-import com.android.settingslib.widget.apppreference.AppPreference;
-
-import java.util.List;
-
-public class RecentLocationRequestPreferenceController extends LocationBasePreferenceController {
-
- /** Key for preference category "Recent location requests" */
- private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
- @VisibleForTesting
- static final String KEY_SEE_ALL_BUTTON = "recent_location_requests_see_all_button";
- private final LocationSettings mFragment;
- private final RecentLocationApps mRecentLocationApps;
- private PreferenceCategory mCategoryRecentLocationRequests;
- private Preference mSeeAllButton;
-
- /** Used in this class and {@link RecentLocationRequestSeeAllPreferenceController} */
- static class PackageEntryClickedListener implements Preference.OnPreferenceClickListener {
- private final DashboardFragment mFragment;
- private final String mPackage;
- private final UserHandle mUserHandle;
-
- public PackageEntryClickedListener(DashboardFragment fragment, String packageName,
- UserHandle userHandle) {
- mFragment = fragment;
- mPackage = packageName;
- mUserHandle = userHandle;
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- // start new fragment to display extended information
- final Bundle args = new Bundle();
- args.putString(AppInfoDashboardFragment.ARG_PACKAGE_NAME, mPackage);
-
- new SubSettingLauncher(mFragment.getContext())
- .setDestination(AppInfoDashboardFragment.class.getName())
- .setArguments(args)
- .setTitleRes(R.string.application_info_label)
- .setUserHandle(mUserHandle)
- .setSourceMetricsCategory(mFragment.getMetricsCategory())
- .launch();
- return true;
- }
- }
-
- public RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
- Lifecycle lifecycle) {
- this(context, fragment, lifecycle, new RecentLocationApps(context));
- }
-
- @VisibleForTesting
- RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
- Lifecycle lifecycle, RecentLocationApps recentApps) {
- super(context, lifecycle);
- mFragment = fragment;
- mRecentLocationApps = recentApps;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_RECENT_LOCATION_REQUESTS;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mCategoryRecentLocationRequests =
- (PreferenceCategory) screen.findPreference(KEY_RECENT_LOCATION_REQUESTS);
- mSeeAllButton = screen.findPreference(KEY_SEE_ALL_BUTTON);
-
- }
-
- @Override
- public void updateState(Preference preference) {
- mCategoryRecentLocationRequests.removeAll();
- mSeeAllButton.setVisible(false);
-
- final Context prefContext = preference.getContext();
- final List<RecentLocationApps.Request> recentLocationRequests =
- mRecentLocationApps.getAppListSorted();
-
- if (recentLocationRequests.size() > 3) {
- // Display the top 3 preferences to container in original order.
- for (int i = 0; i < 3; i++) {
- mCategoryRecentLocationRequests.addPreference(
- createAppPreference(prefContext, recentLocationRequests.get(i)));
- }
- // Display a button to list all requests
- mSeeAllButton.setVisible(true);
- } else if (recentLocationRequests.size() > 0) {
- // Add preferences to container in original order (already sorted by recency).
- for (RecentLocationApps.Request request : recentLocationRequests) {
- mCategoryRecentLocationRequests.addPreference(
- createAppPreference(prefContext, request));
- }
- } else {
- // If there's no item to display, add a "No recent apps" item.
- final Preference banner = createAppPreference(prefContext);
- banner.setTitle(R.string.location_no_recent_apps);
- banner.setSelectable(false);
- mCategoryRecentLocationRequests.addPreference(banner);
- }
- }
-
- @Override
- public void onLocationModeChanged(int mode, boolean restricted) {
- mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
- }
-
- @VisibleForTesting
- AppPreference createAppPreference(Context prefContext) {
- return new AppPreference(prefContext);
- }
-
- @VisibleForTesting
- AppPreference createAppPreference(Context prefContext, RecentLocationApps.Request request) {
- final AppPreference pref = createAppPreference(prefContext);
- pref.setSummary(request.contentDescription);
- pref.setIcon(request.icon);
- pref.setTitle(request.label);
- pref.setOnPreferenceClickListener(new PackageEntryClickedListener(
- mFragment, request.packageName, request.userHandle));
- return pref;
- }
-}
diff --git a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java b/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java
deleted file mode 100644
index d256b9b..0000000
--- a/src/com/android/settings/location/RecentLocationRequestSeeAllFragment.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 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.provider.SearchIndexableResource;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.R;
-import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/** Dashboard Fragment to display all recent location requests, sorted by recency. */
-@SearchIndexable
-public class RecentLocationRequestSeeAllFragment extends DashboardFragment {
-
- private static final String TAG = "RecentLocationReqAll";
-
- public static final String PATH =
- "com.android.settings.location.RecentLocationRequestSeeAllFragment";
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.RECENT_LOCATION_REQUESTS_ALL;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.location_recent_requests_see_all;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @Override
- protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getSettingsLifecycle(), this);
- }
-
- private static List<AbstractPreferenceController> buildPreferenceControllers(
- Context context, Lifecycle lifecycle, RecentLocationRequestSeeAllFragment fragment) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(
- new RecentLocationRequestSeeAllPreferenceController(context, lifecycle, fragment));
- return controllers;
- }
-
- /**
- * For Search.
- */
- public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.location_recent_requests_see_all;
- return Arrays.asList(sir);
- }
-
- @Override
- public List<AbstractPreferenceController> getPreferenceControllers(Context
- context) {
- return buildPreferenceControllers(
- context, /* lifecycle = */ null, /* fragment = */ null);
- }
- };
-}
diff --git a/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java
deleted file mode 100644
index 3fa0f00..0000000
--- a/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceController.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 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 androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.location.RecentLocationApps;
-import com.android.settingslib.widget.apppreference.AppPreference;
-
-import java.util.List;
-
-/** Preference controller for preference category displaying all recent location requests. */
-public class RecentLocationRequestSeeAllPreferenceController
- extends LocationBasePreferenceController {
-
- /** Key for preference category "All recent location requests" */
- private static final String KEY_ALL_RECENT_LOCATION_REQUESTS = "all_recent_location_requests";
- private final RecentLocationRequestSeeAllFragment mFragment;
- private PreferenceCategory mCategoryAllRecentLocationRequests;
- private RecentLocationApps mRecentLocationApps;
-
- public RecentLocationRequestSeeAllPreferenceController(
- Context context, Lifecycle lifecycle, RecentLocationRequestSeeAllFragment fragment) {
- this(context, lifecycle, fragment, new RecentLocationApps(context));
- }
-
- @VisibleForTesting
- RecentLocationRequestSeeAllPreferenceController(
- Context context,
- Lifecycle lifecycle,
- RecentLocationRequestSeeAllFragment fragment,
- RecentLocationApps recentLocationApps) {
- super(context, lifecycle);
- mFragment = fragment;
- mRecentLocationApps = recentLocationApps;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_ALL_RECENT_LOCATION_REQUESTS;
- }
-
- @Override
- public void onLocationModeChanged(int mode, boolean restricted) {
- mCategoryAllRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mCategoryAllRecentLocationRequests =
- (PreferenceCategory) screen.findPreference(KEY_ALL_RECENT_LOCATION_REQUESTS);
-
- }
-
- @Override
- public void updateState(Preference preference) {
- mCategoryAllRecentLocationRequests.removeAll();
- List<RecentLocationApps.Request> requests = mRecentLocationApps.getAppListSorted();
- for (RecentLocationApps.Request request : requests) {
- Preference appPreference = createAppPreference(preference.getContext(), request);
- mCategoryAllRecentLocationRequests.addPreference(appPreference);
- }
- }
-
- @VisibleForTesting
- AppPreference createAppPreference(
- Context prefContext, RecentLocationApps.Request request) {
- final AppPreference pref = new AppPreference(prefContext);
- pref.setSummary(request.contentDescription);
- pref.setIcon(request.icon);
- pref.setTitle(request.label);
- pref.setOnPreferenceClickListener(
- new RecentLocationRequestPreferenceController.PackageEntryClickedListener(
- mFragment, request.packageName, request.userHandle));
- return pref;
- }
-}
diff --git a/src/com/android/settings/location/TopLevelLocationPreferenceController.java b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
new file mode 100644
index 0000000..d0bd9a9
--- /dev/null
+++ b/src/com/android/settings/location/TopLevelLocationPreferenceController.java
@@ -0,0 +1,99 @@
+package com.android.settings.location;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.LocationManager;
+import android.permission.RuntimePermissionPresenter;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+public class TopLevelLocationPreferenceController extends BasePreferenceController implements
+ LifecycleObserver, OnStart, OnStop {
+ private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
+ new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
+ private final LocationManager mLocationManager;
+ /** Total number of apps that has location permission. */
+ private int mNumTotal = -1;
+ private BroadcastReceiver mReceiver;
+ private Preference mPreference;
+
+ public TopLevelLocationPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ if (mLocationManager.isLocationEnabled()) {
+ if (mNumTotal == -1) {
+ return mContext.getString(R.string.location_settings_loading_app_permission_stats);
+ }
+ return mContext.getResources().getQuantityString(
+ R.plurals.location_settings_summary_location_on,
+ mNumTotal, mNumTotal);
+ } else {
+ return mContext.getString(R.string.location_settings_summary_location_off);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ mPreference = preference;
+ refreshSummary(preference);
+ // Bail out if location has been disabled.
+ if (!mLocationManager.isLocationEnabled()) {
+ return;
+ }
+ RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
+ Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
+ (numApps) -> {
+ mNumTotal = numApps;
+ refreshSummary(preference);
+ }, null);
+ }
+
+ @Override
+ public void onStart() {
+ if (mReceiver == null) {
+ mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ refreshLocationMode();
+ }
+ };
+ }
+ mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
+ refreshLocationMode();
+ }
+
+ @Override
+ public void onStop() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ private void refreshLocationMode() {
+ // 'null' is checked inside updateState(), so no need to check here.
+ updateState(mPreference);
+ }
+}
diff --git a/src/com/android/settings/network/MultiNetworkHeaderController.java b/src/com/android/settings/network/MultiNetworkHeaderController.java
index 1c0fc74..8860c47 100644
--- a/src/com/android/settings/network/MultiNetworkHeaderController.java
+++ b/src/com/android/settings/network/MultiNetworkHeaderController.java
@@ -18,19 +18,70 @@
import android.content.Context;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.wifi.WifiConnectionPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
// This controls a header at the top of the Network & internet page that only appears when there
// are two or more active mobile subscriptions. It shows an overview of available network
// connections with an entry for wifi (if connected) and an entry for each subscription.
-public class MultiNetworkHeaderController extends BasePreferenceController {
+public class MultiNetworkHeaderController extends BasePreferenceController implements
+ WifiConnectionPreferenceController.UpdateListener,
+ SubscriptionsPreferenceController.UpdateListener {
+ public static final String TAG = "MultiNetworkHdrCtrl";
+
+ private WifiConnectionPreferenceController mWifiController;
+ private SubscriptionsPreferenceController mSubscriptionsController;
+ private PreferenceCategory mPreferenceCategory;
public MultiNetworkHeaderController(Context context, String key) {
- super(context, key);
+ super(context, key);
+ }
+
+ public void init(Lifecycle lifecycle) {
+ mWifiController = createWifiController(lifecycle);
+ mSubscriptionsController = createSubscriptionsController(lifecycle);
+ }
+
+ @VisibleForTesting
+ WifiConnectionPreferenceController createWifiController(Lifecycle lifecycle) {
+ final int prefOrder = 0;
+ return new WifiConnectionPreferenceController(mContext, lifecycle, this, mPreferenceKey,
+ prefOrder, MetricsProto.MetricsEvent.SETTINGS_NETWORK_CATEGORY);
+ }
+
+ @VisibleForTesting
+ SubscriptionsPreferenceController createSubscriptionsController(Lifecycle lifecycle) {
+ final int prefStartOrder = 10;
+ return new SubscriptionsPreferenceController(mContext, lifecycle, this, mPreferenceKey,
+ prefStartOrder);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceCategory = (PreferenceCategory) screen.findPreference(mPreferenceKey);
+ mPreferenceCategory.setVisible(isAvailable());
+ mWifiController.displayPreference(screen);
+ mSubscriptionsController.displayPreference(screen);
}
@Override
public int getAvailabilityStatus() {
- return UNSUPPORTED_ON_DEVICE;
+ if (mSubscriptionsController == null || !mSubscriptionsController.isAvailable()) {
+ return CONDITIONALLY_UNAVAILABLE;
+ } else {
+ return AVAILABLE;
+ }
+ }
+
+ @Override
+ public void onChildrenUpdated() {
+ mPreferenceCategory.setVisible(isAvailable());
}
}
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 70481f1..7d94bba 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -72,6 +72,9 @@
public void onAttach(Context context) {
super.onAttach(context);
+ if (FeatureFlagUtils.isEnabled(context, FeatureFlags.NETWORK_INTERNET_V2)) {
+ use(MultiNetworkHeaderController.class).init(getSettingsLifecycle());
+ }
use(AirplaneModePreferenceController.class).setFragment(this);
}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index cfe27db..6b14759 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -24,8 +24,20 @@
import java.util.Iterator;
import java.util.List;
+import androidx.annotation.VisibleForTesting;
+
public class SubscriptionUtil {
+ private static List<SubscriptionInfo> sResultsForTesting;
+
+ @VisibleForTesting
+ static void setAvailableSubscriptionsForTesting(List<SubscriptionInfo> results) {
+ sResultsForTesting = results;
+ }
+
public static List<SubscriptionInfo> getAvailableSubscriptions(SubscriptionManager manager) {
+ if (sResultsForTesting != null) {
+ return sResultsForTesting;
+ }
List<SubscriptionInfo> subscriptions = manager.getAvailableSubscriptionInfoList();
if (subscriptions == null) {
subscriptions = new ArrayList<>();
diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java
new file mode 100644
index 0000000..9e55341
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.R;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.Map;
+
+import androidx.collection.ArrayMap;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * This manages a set of Preferences it places into a PreferenceGroup owned by some parent
+ * controller class - one for each available subscription. This controller is only considered
+ * available if there are 2 or more subscriptions.
+ */
+public class SubscriptionsPreferenceController extends AbstractPreferenceController implements
+ LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "SubscriptionsPrefCntrlr";
+
+ private UpdateListener mUpdateListener;
+ private String mPreferenceGroupKey;
+ private PreferenceGroup mPreferenceGroup;
+ private SubscriptionManager mManager;
+ private SubscriptionsChangeListener mSubscriptionsListener;
+
+ // Map of subscription id to Preference
+ private Map<Integer, Preference> mSubscriptionPreferences;
+ private int mStartOrder;
+
+ /**
+ * This interface lets a parent of this class know that some change happened - this could
+ * either be because overall availability changed, or because we've added/removed/updated some
+ * preferences.
+ */
+ public interface UpdateListener {
+ void onChildrenUpdated();
+ }
+
+ /**
+ * @param context the context for the UI where we're placing these preferences
+ * @param lifecycle for listening to lifecycle events for the UI
+ * @param updateListener called to let our parent controller know that our availability has
+ * changed, or that one or more of the preferences we've placed in the
+ * PreferenceGroup has changed
+ * @param preferenceGroupKey the key used to lookup the PreferenceGroup where Preferences will
+ * be placed
+ * @param startOrder the order that should be given to the first Preference placed into
+ * the PreferenceGroup; the second will use startOrder+1, third will
+ * use startOrder+2, etc. - this is useful for when the parent wants
+ * to have other preferences in the same PreferenceGroup and wants
+ * a specific ordering relative to this controller's prefs.
+ */
+ public SubscriptionsPreferenceController(Context context, Lifecycle lifecycle,
+ UpdateListener updateListener, String preferenceGroupKey, int startOrder) {
+ super(context);
+ mUpdateListener = updateListener;
+ mPreferenceGroupKey = preferenceGroupKey;
+ mStartOrder = startOrder;
+ mManager = context.getSystemService(SubscriptionManager.class);
+ mSubscriptionPreferences = new ArrayMap<>();
+ mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
+ lifecycle.addObserver(this);
+ }
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ mSubscriptionsListener.start();
+ update();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ mSubscriptionsListener.stop();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceGroup = (PreferenceGroup) screen.findPreference(mPreferenceGroupKey);
+ update();
+ }
+
+ private void update() {
+ if (mPreferenceGroup == null) {
+ return;
+ }
+
+ if (mSubscriptionsListener.isAirplaneModeOn()) {
+ for (Preference pref : mSubscriptionPreferences.values()) {
+ mPreferenceGroup.removePreference(pref);
+ }
+ mSubscriptionPreferences.clear();
+ mUpdateListener.onChildrenUpdated();
+ return;
+ }
+
+ final Map<Integer, Preference> existingPrefs = mSubscriptionPreferences;
+ mSubscriptionPreferences = new ArrayMap<>();
+
+ int order = mStartOrder;
+ for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mManager) ) {
+ final int subId = info.getSubscriptionId();
+ Preference pref = existingPrefs.remove(subId);
+ if (pref == null) {
+ pref = new Preference(mPreferenceGroup.getContext());
+ mPreferenceGroup.addPreference(pref);
+ }
+ pref.setTitle(info.getDisplayName());
+ pref.setIcon(R.drawable.ic_network_cell);
+ pref.setOrder(order++);
+
+ // TODO(asargent) - set summary here to indicate default for calls/sms and data
+
+ pref.setOnPreferenceClickListener(clickedPref -> {
+ // TODO(asargent) - make this start MobileNetworkActivity once we've
+ // added support for it to take a subscription id
+ return true;
+ });
+
+ mSubscriptionPreferences.put(subId, pref);
+ }
+
+ // Remove any old preferences that no longer map to a subscription.
+ for (Preference pref : existingPrefs.values()) {
+ mPreferenceGroup.removePreference(pref);
+ }
+ mUpdateListener.onChildrenUpdated();
+ }
+
+ /**
+ *
+ * @return true if there are at least 2 available subscriptions.
+ */
+ @Override
+ public boolean isAvailable() {
+ if (mSubscriptionsListener.isAirplaneModeOn()) {
+ return false;
+ }
+ return SubscriptionUtil.getAvailableSubscriptions(mManager).size() >= 2;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ update();
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ update();
+ }
+}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 184ccc8..cf7df8d 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -24,6 +24,7 @@
import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
@@ -110,10 +111,12 @@
public abstract PanelFeatureProvider getPanelFeatureProvider();
- public abstract ContextualCardFeatureProvider getContextualCardFeatureProvider();
+ public abstract ContextualCardFeatureProvider getContextualCardFeatureProvider(Context context);
public abstract FaceFeatureProvider getFaceFeatureProvider();
+ public abstract BluetoothFeatureProvider getBluetoothFeatureProvider(Context context);
+
public static final class FactoryNotFoundException extends RuntimeException {
public FactoryNotFoundException(Throwable throwable) {
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index 88c09d0..e10aa41 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -30,6 +30,8 @@
import com.android.settings.applications.ApplicationFeatureProviderImpl;
import com.android.settings.biometrics.face.FaceFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProviderImpl;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
import com.android.settings.core.instrumentation.SettingsMetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
@@ -81,6 +83,7 @@
private PanelFeatureProvider mPanelFeatureProvider;
private ContextualCardFeatureProvider mContextualCardFeatureProvider;
private FaceFeatureProvider mFaceFeatureProvider;
+ private BluetoothFeatureProvider mBluetoothFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -228,9 +231,10 @@
}
@Override
- public ContextualCardFeatureProvider getContextualCardFeatureProvider() {
+ public ContextualCardFeatureProvider getContextualCardFeatureProvider(Context context) {
if (mContextualCardFeatureProvider == null) {
- mContextualCardFeatureProvider = new ContextualCardFeatureProviderImpl();
+ mContextualCardFeatureProvider = new ContextualCardFeatureProviderImpl(
+ context.getApplicationContext());
}
return mContextualCardFeatureProvider;
}
@@ -242,4 +246,13 @@
}
return mFaceFeatureProvider;
}
+
+ @Override
+ public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
+ if (mBluetoothFeatureProvider == null) {
+ mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
+ context.getApplicationContext());
+ }
+ return mBluetoothFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/panel/PanelFeatureProviderImpl.java b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
index 503a5c3..ade2ffd 100644
--- a/src/com/android/settings/panel/PanelFeatureProviderImpl.java
+++ b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
@@ -17,15 +17,16 @@
package com.android.settings.panel;
import android.content.Context;
+import android.provider.Settings;
public class PanelFeatureProviderImpl implements PanelFeatureProvider {
@Override
public PanelContent getPanel(Context context, String panelType) {
switch (panelType) {
- case SettingsPanelActivity.PANEL_TYPE_WIFI:
+ case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
return InternetConnectivityPanel.create(context);
- case SettingsPanelActivity.PANEL_TYPE_VOLUME:
+ case Settings.Panel.ACTION_VOLUME:
return VolumePanel.create(context);
}
diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java
index e61b8f8..7655be8 100644
--- a/src/com/android/settings/panel/PanelFragment.java
+++ b/src/com/android/settings/panel/PanelFragment.java
@@ -69,7 +69,7 @@
mPanelSlices = view.findViewById(R.id.panel_parent_layout);
mSeeMoreButton = view.findViewById(R.id.see_more);
mDoneButton = view.findViewById(R.id.done);
- mTitleView = view.findViewById(R.id.title);
+ mTitleView = view.findViewById(R.id.panel_title);
final Bundle arguments = getArguments();
final String panelType = arguments.getString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT);
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 09bead4..ffe94f8 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,11 +16,9 @@
package com.android.settings.panel;
-import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
-import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
@@ -35,8 +33,6 @@
/**
* Dialog Activity to host Settings Slices.
- *
- * TODO link to action / framework API
*/
public class SettingsPanelActivity extends FragmentActivity {
@@ -47,28 +43,10 @@
*/
public static final String KEY_PANEL_TYPE_ARGUMENT = "PANEL_TYPE_ARGUMENT";
-
- // TODO (b/117804442) move to framework
- public static final String EXTRA_PANEL_TYPE = "com.android.settings.panel.extra";
-
- // TODO (b/117804442) move to framework
- public static final String PANEL_TYPE_WIFI = "wifi_panel";
-
- // TODO (b/117804442) move to framework
- public static final String PANEL_TYPE_VOLUME = "volume_panel";
-
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final ComponentName callingActivityName = getCallingActivity();
-
- if (callingActivityName == null) {
- Log.e(TAG, "Must start with startActivityForResult. Closing.");
- finish();
- return;
- }
-
final Intent callingIntent = getIntent();
if (callingIntent == null) {
Log.e(TAG, "Null intent, closing Panel Activity");
@@ -76,12 +54,6 @@
return;
}
- final String typeExtra = callingIntent.getStringExtra(EXTRA_PANEL_TYPE);
- if (TextUtils.isEmpty(typeExtra)) {
- Log.e(TAG, "No intent passed, closing Panel Activity");
- return;
- }
-
setContentView(R.layout.settings_panel);
// Move the window to the bottom of screen, and make it take up the entire screen width.
@@ -90,9 +62,8 @@
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
-
final Bundle bundle = new Bundle();
- bundle.putString(KEY_PANEL_TYPE_ARGUMENT, typeExtra);
+ bundle.putString(KEY_PANEL_TYPE_ARGUMENT, callingIntent.getAction());
final PanelFragment panelFragment = new PanelFragment();
panelFragment.setArguments(bundle);
diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java
index b96c57df..8454cc5 100644
--- a/src/com/android/settings/password/SetupChooseLockPassword.java
+++ b/src/com/android/settings/password/SetupChooseLockPassword.java
@@ -135,8 +135,9 @@
@Override
protected void updateUi() {
super.updateUi();
- mSkipButton.setVisibility(mForFingerprint ? View.GONE : View.VISIBLE);
+ // Show the skip button during SUW but not during Settings > Biometric Enrollment
+ mSkipButton.setVisibility(View.VISIBLE);
if (mOptionsButton != null) {
mOptionsButton.setVisibility(
mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java
index 696380c..b24936b 100644
--- a/src/com/android/settings/password/SetupChooseLockPattern.java
+++ b/src/com/android/settings/password/SetupChooseLockPattern.java
@@ -70,17 +70,15 @@
ChooseLockTypeDialogFragment.newInstance(mUserId)
.show(getChildFragmentManager(), null));
}
- // enable skip button only during setup wizard and not with fingerprint flow.
- if (!mForFingerprint) {
- Button skipButton = view.findViewById(R.id.skip_button);
- skipButton.setVisibility(View.VISIBLE);
- skipButton.setOnClickListener(v -> {
- SetupSkipDialog dialog = SetupSkipDialog.newInstance(
- getActivity().getIntent()
- .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
- dialog.show(getFragmentManager());
+ // Show the skip button during SUW but not during Settings > Biometric Enrollment
+ Button skipButton = view.findViewById(R.id.skip_button);
+ skipButton.setVisibility(View.VISIBLE);
+ skipButton.setOnClickListener(v -> {
+ SetupSkipDialog dialog = SetupSkipDialog.newInstance(
+ getActivity().getIntent()
+ .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false));
+ dialog.show(getFragmentManager());
});
- }
return view;
}
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 4a9de15..bb47df2 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -32,7 +32,8 @@
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.location.LocationSlice;
-import com.android.settings.wifi.WifiSlice;
+import com.android.settings.wifi.slice.ContextualWifiSlice;
+import com.android.settings.wifi.slice.WifiSlice;
import java.util.Map;
import java.util.WeakHashMap;
@@ -107,6 +108,7 @@
mUriMap.put(CustomSliceRegistry.BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
mUriMap.put(CustomSliceRegistry.BATTERY_INFO_SLICE_URI, BatterySlice.class);
mUriMap.put(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
+ mUriMap.put(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
mUriMap.put(CustomSliceRegistry.DATA_USAGE_SLICE_URI, DataUsageSlice.class);
mUriMap.put(CustomSliceRegistry.DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class);
mUriMap.put(CustomSliceRegistry.EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class);
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index 1b8cffe..bdf8b35 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -80,6 +80,17 @@
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath("bluetooth_devices")
.build();
+
+ /**
+ * Backing Uri for the Wifi Slice.
+ */
+ public static final Uri CONTEXTUAL_WIFI_SLICE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("contextual_wifi")
+ .build();
+
/**
* Backing Uri for the Data usage Slice.
*/
@@ -216,6 +227,7 @@
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(KEY_WIFI)
.build();
+
/**
* Backing Uri for the Zen Mode Slice.
*/
diff --git a/src/com/android/settings/slices/SlicePreference.java b/src/com/android/settings/slices/SlicePreference.java
new file mode 100644
index 0000000..98719f7
--- /dev/null
+++ b/src/com/android/settings/slices/SlicePreference.java
@@ -0,0 +1,48 @@
+/*
+ * 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.slices;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * Preference for {@link SliceView}
+ */
+public class SlicePreference extends LayoutPreference {
+ private SliceView mSliceView;
+
+ public SlicePreference(Context context, AttributeSet attrs) {
+ super(context, attrs, R.attr.slicePreferenceStyle);
+ mSliceView = findViewById(R.id.slice_view);
+ }
+
+ public SlicePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, R.attr.slicePreferenceStyle);
+ mSliceView = findViewById(R.id.slice_view);
+ }
+
+ public void onSliceUpdated(Slice slice) {
+ mSliceView.onChanged(slice);
+ notifyChanged();
+ }
+}
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
new file mode 100644
index 0000000..8c751c8
--- /dev/null
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -0,0 +1,89 @@
+/*
+ * 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.slices;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Observer;
+import androidx.preference.PreferenceScreen;
+import androidx.slice.Slice;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+/**
+ * Default {@link BasePreferenceController} for {@link SliceView}. It will take {@link Uri} for
+ * Slice and display what's inside this {@link Uri}
+ */
+public class SlicePreferenceController extends BasePreferenceController implements
+ LifecycleObserver, OnStart, OnStop, Observer<Slice> {
+ @VisibleForTesting
+ LiveData<Slice> mLiveData;
+ private SlicePreference mSlicePreference;
+ private Uri mUri;
+
+ public SlicePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mSlicePreference = (SlicePreference) screen.findPreference(
+ getPreferenceKey());
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mUri != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ public void setSliceUri(Uri uri) {
+ mUri = uri;
+ mLiveData = SliceLiveData.fromUri(mContext, mUri);
+
+ //TODO(b/120803703): figure out why we need to remove observer first
+ mLiveData.removeObserver(this);
+ }
+
+ @Override
+ public void onStart() {
+ if (mLiveData != null) {
+ mLiveData.observeForever(this);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (mLiveData != null) {
+ mLiveData.removeObserver(this);
+ }
+ }
+
+ @Override
+ public void onChanged(Slice slice) {
+ mSlicePreference.onSliceUpdated(slice);
+ }
+}
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index c627a2e..30c2cd9 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -30,6 +30,7 @@
import android.widget.BaseAdapter;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.internal.PreferenceImageView;
@@ -46,7 +47,10 @@
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.Utils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTrackerFactory;
import java.util.ArrayList;
import java.util.List;
@@ -62,10 +66,14 @@
/** Message sent to us to stop scanning wifi and pop up timeout dialog. */
private static final int MESSAGE_STOP_SCAN_WIFI_LIST = 0;
+ /** Spec defines there should be 5 wifi ap on the list at most. */
+ private static final int MAX_NUMBER_LIST_ITEM = 5;
+
/** Delayed time to stop scanning wifi. */
private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;
private List<AccessPoint> mAccessPointList;
+ private FilterWifiTracker mFilterWifiTracker;
private AccessPointAdapter mDialogAdapter;
private NetworkRequestUserSelectionCallback mUserSelectionCallback;
@@ -159,6 +167,19 @@
if (wifiManager != null) {
wifiManager.unregisterNetworkRequestMatchCallback(this);
}
+
+ if (mFilterWifiTracker != null) {
+ mFilterWifiTracker.onPause();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mFilterWifiTracker != null) {
+ mFilterWifiTracker.onDestroy();
+ mFilterWifiTracker = null;
+ }
}
@Override
@@ -172,6 +193,11 @@
}
// Sets time-out to stop scanning.
mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
+
+ if (mFilterWifiTracker == null) {
+ mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
+ }
+ mFilterWifiTracker.onResume();
}
private final Handler mHandler = new Handler() {
@@ -268,17 +294,33 @@
@Override
public void onMatch(List<ScanResult> scanResults) {
- // TODO(b/119846365): Checks if we could escalate the converting effort.
- // Converts ScanResult to WifiConfiguration.
- List<WifiConfiguration> wifiConfigurations = null;
- final WifiManager wifiManager = getContext().getApplicationContext()
- .getSystemService(WifiManager.class);
- if (wifiManager != null) {
- wifiConfigurations = wifiManager.getAllMatchingWifiConfigs(scanResults);
+ mHandler.removeMessages(MESSAGE_STOP_SCAN_WIFI_LIST);
+ renewAccessPointList(scanResults);
+
+ notifyAdapterRefresh();
+ }
+
+ // Updates internal AccessPoint list from WifiTracker. scanResults are used to update key list
+ // of AccessPoint, and could be null if there is no necessary to update key list.
+ private void renewAccessPointList(List<ScanResult> scanResults) {
+ if (mFilterWifiTracker == null) {
+ return;
}
- setUpAccessPointList(wifiConfigurations);
+ // TODO(b/119846365): Checks if we could escalate the converting effort.
+ // Updates keys of scanResults into FilterWifiTracker for updating matched AccessPoints.
+ if (scanResults != null) {
+ mFilterWifiTracker.updateKeys(scanResults);
+ }
+ // Re-gets matched AccessPoints from WifiTracker.
+ final List<AccessPoint> list = getAccessPointList();
+ list.clear();
+ list.addAll(mFilterWifiTracker.getAccessPoints());
+ }
+
+ @VisibleForTesting
+ void notifyAdapterRefresh() {
if (getDialogAdapter() != null) {
getDialogAdapter().notifyDataSetChanged();
}
@@ -286,48 +328,99 @@
@Override
public void onUserSelectionConnectSuccess(WifiConfiguration wificonfiguration) {
- if (getDialogAdapter() != null) {
- updateAccessPointListItem(wificonfiguration);
- getDialogAdapter().notifyDataSetChanged();
- }
+ // Dismisses current dialog, since connection is success.
+ dismiss();
}
@Override
public void onUserSelectionConnectFailure(WifiConfiguration wificonfiguration) {
- if (mDialogAdapter != null) {
- updateAccessPointListItem(wificonfiguration);
- getDialogAdapter().notifyDataSetChanged();
- }
+ stopScanningAndPopErrorDialog(ERROR_DIALOG_TYPE.ABORT);
}
- private void updateAccessPointListItem(WifiConfiguration wificonfiguration) {
- if (wificonfiguration == null) {
- return;
+ private final class FilterWifiTracker {
+ private final List<String> mAccessPointKeys;
+ private final WifiTracker mWifiTracker;
+
+ public FilterWifiTracker(Context context, Lifecycle lifecycle) {
+ mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
+ lifecycle, /* includeSaved */ true, /* includeScans */ true);
+ mAccessPointKeys = new ArrayList<>();
}
- final List<AccessPoint> accessPointList = getAccessPointList();
- final int accessPointListSize = accessPointList.size();
-
- for (int i = 0; i < accessPointListSize; i++) {
- AccessPoint accessPoint = accessPointList.get(i);
- // It is the same AccessPoint SSID, and should be replaced to update latest properties.
- if (accessPoint.matches(wificonfiguration)) {
- accessPointList.set(i, new AccessPoint(getContext(), wificonfiguration));
- break;
+ /**
+ * Updates key list from input. {@code onMatch()} may be called in multi-times according
+ * wifi scanning result, so needs patchwork here.
+ */
+ public void updateKeys(List<ScanResult> scanResults) {
+ for (ScanResult scanResult : scanResults) {
+ final String key = AccessPoint.getKey(scanResult);
+ if (!mAccessPointKeys.contains(key)) {
+ mAccessPointKeys.add(key);
+ }
}
}
- }
- private void setUpAccessPointList(List<WifiConfiguration> wifiConfigurations) {
- // Grants for zero size input, since maybe current wifi is off or somethings are wrong.
- if (wifiConfigurations == null) {
- return;
+ /**
+ * Returns only AccessPoints whose key is in {@code mAccessPointKeys}.
+ *
+ * @return List of matched AccessPoints.
+ */
+ public List<AccessPoint> getAccessPoints() {
+ final List<AccessPoint> allAccessPoints = mWifiTracker.getAccessPoints();
+ final List<AccessPoint> result = new ArrayList<>();
+
+ // The order should be kept, because order means wifi score (sorting in WifiTracker).
+ int count = 0;
+ for (AccessPoint accessPoint : allAccessPoints) {
+ final String key = accessPoint.getKey();
+ if (mAccessPointKeys.contains(key)) {
+ result.add(accessPoint);
+
+ count++;
+ // Limits how many count of items could show.
+ if (count >= MAX_NUMBER_LIST_ITEM) {
+ break;
+ }
+ }
+ }
+
+ return result;
}
- final List<AccessPoint> accessPointList = getAccessPointList();
- accessPointList.clear();
- for (WifiConfiguration config : wifiConfigurations) {
- accessPointList.add(new AccessPoint(getContext(), config));
+ private WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() {
+
+ @Override
+ public void onWifiStateChanged(int state) {
+ notifyAdapterRefresh();
+ }
+
+ @Override
+ public void onConnectedChanged() {
+ notifyAdapterRefresh();
+ }
+
+ @Override
+ public void onAccessPointsChanged() {
+ notifyAdapterRefresh();
+ }
+ };
+
+ public void onDestroy() {
+ if (mWifiTracker != null) {
+ mWifiTracker.onDestroy();
+ }
+ }
+
+ public void onResume() {
+ if (mWifiTracker != null) {
+ mWifiTracker.onStart();
+ }
+ }
+
+ public void onPause() {
+ if (mWifiTracker != null) {
+ mWifiTracker.onStop();
+ }
}
}
}
diff --git a/src/com/android/settings/wifi/WifiConnectionPreferenceController.java b/src/com/android/settings/wifi/WifiConnectionPreferenceController.java
new file mode 100644
index 0000000..b73bce9
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiConnectionPreferenceController.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.AccessPointPreference;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTrackerFactory;
+
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * This places a preference into a PreferenceGroup owned by some parent
+ * controller class when there is a wifi connection present.
+ */
+public class WifiConnectionPreferenceController extends AbstractPreferenceController implements
+ WifiTracker.WifiListener {
+
+ private static final String TAG = "WifiConnPrefCtrl";
+
+ private static final String KEY = "active_wifi_connection";
+
+ private UpdateListener mUpdateListener;
+ private Context mPrefContext;
+ private String mPreferenceGroupKey;
+ private PreferenceGroup mPreferenceGroup;
+ private WifiTracker mWifiTracker;
+ private AccessPointPreference mPreference;
+ private AccessPointPreference.UserBadgeCache mBadgeCache;
+ private int order;
+ private int mMetricsCategory;
+
+ /**
+ * Used to notify a parent controller that this controller has changed in availability, or has
+ * updated the content in the preference that it manages.
+ */
+ public interface UpdateListener {
+ void onChildrenUpdated();
+ }
+
+ /**
+ * @param context the context for the UI where we're placing the preference
+ * @param lifecycle for listening to lifecycle events for the UI
+ * @param updateListener for notifying a parent controller of changes
+ * @param preferenceGroupKey the key to use to lookup the PreferenceGroup where this controller
+ * will add its preference
+ * @param order the order that the preference added by this controller should use -
+ * useful when this preference needs to be ordered in a specific way
+ * relative to others in the PreferenceGroup
+ * @param metricsCategory - the category to use as the source when handling the click on the
+ * pref to go to the wifi connection detail page
+ */
+ public WifiConnectionPreferenceController(Context context, Lifecycle lifecycle,
+ UpdateListener updateListener, String preferenceGroupKey, int order,
+ int metricsCategory) {
+ super(context);
+ mUpdateListener = updateListener;
+ mPreferenceGroupKey = preferenceGroupKey;
+ mWifiTracker = WifiTrackerFactory.create(context, this, lifecycle, true /* includeSaved */,
+ true /* includeScans */);
+ this.order = order;
+ mMetricsCategory = metricsCategory;
+ mBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager());
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mWifiTracker.isConnected() && getCurrentAccessPoint() != null;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceGroup = (PreferenceGroup) screen.findPreference(mPreferenceGroupKey);
+ mPrefContext = screen.getContext();
+ update();
+ }
+
+ private AccessPoint getCurrentAccessPoint() {
+ for (AccessPoint accessPoint : mWifiTracker.getAccessPoints()) {
+ if (accessPoint.isActive()) {
+ return accessPoint;
+ }
+ }
+ return null;
+ }
+
+ private void updatePreference(AccessPoint accessPoint) {
+ if (mPreference != null) {
+ mPreferenceGroup.removePreference(mPreference);
+ mPreference = null;
+ }
+ if (accessPoint == null) {
+ return;
+ }
+ if (mPrefContext != null) {
+ mPreference = new AccessPointPreference(accessPoint, mPrefContext, mBadgeCache,
+ R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */);
+ mPreference.setKey(KEY);
+ mPreference.refresh();
+ mPreference.setOrder(order);
+
+ mPreference.setOnPreferenceClickListener(pref -> {
+ Bundle args = new Bundle();
+ mPreference.getAccessPoint().saveWifiState(args);
+ new SubSettingLauncher(mPrefContext)
+ .setTitleRes(R.string.pref_title_network_details)
+ .setDestination(WifiNetworkDetailsFragment.class.getName())
+ .setArguments(args)
+ .setSourceMetricsCategory(mMetricsCategory)
+ .launch();
+ return true;
+ });
+ mPreferenceGroup.addPreference(mPreference);
+ }
+ }
+
+ private void update() {
+ AccessPoint connectedAccessPoint = null;
+ if (mWifiTracker.isConnected()) {
+ connectedAccessPoint = getCurrentAccessPoint();
+ }
+ if (connectedAccessPoint == null) {
+ updatePreference(null);
+ } else {
+ if (mPreference == null || !mPreference.getAccessPoint().equals(connectedAccessPoint)) {
+ updatePreference(connectedAccessPoint);
+ } else if (mPreference != null) {
+ mPreference.refresh();
+ }
+ }
+ mUpdateListener.onChildrenUpdated();
+ }
+
+ @Override
+ public void onWifiStateChanged(int state) {
+ update();
+ }
+
+ @Override
+ public void onConnectedChanged() {
+ update();
+ }
+
+ @Override
+ public void onAccessPointsChanged() {
+ update();
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java
index 9ef6a39..c32bcf3 100644
--- a/src/com/android/settings/wifi/WifiDialogActivity.java
+++ b/src/com/android/settings/wifi/WifiDialogActivity.java
@@ -38,6 +38,8 @@
private static final String TAG = "WifiDialogActivity";
+ public static final String KEY_ACCESS_POINT_STATE = "access_point_state";
+
/**
* Boolean extra indicating whether this activity should connect to an access point on the
* caller's behalf. If this is set to false, the caller should check
@@ -46,9 +48,8 @@
*/
@VisibleForTesting
static final String KEY_CONNECT_FOR_CALLER = "connect_for_caller";
- static final String KEY_ACCESS_POINT_STATE = "access_point_state";
- private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration";
+ private static final String KEY_WIFI_CONFIGURATION = "wifi_configuration";
private static final int RESULT_CONNECTED = RESULT_FIRST_USER;
private static final int RESULT_FORGET = RESULT_FIRST_USER + 1;
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 177e79d..8d6aa68 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
/**
@@ -31,6 +32,11 @@
}
@Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
+ }
+
+ @Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index 7d031c1..66bc349 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
/**
@@ -31,6 +32,11 @@
}
@Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
+ }
+
+ @Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index e4ae292..6c95f09 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -27,7 +27,6 @@
import androidx.fragment.app.FragmentTransaction;
import com.android.internal.logging.nano.MetricsProto;
-
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.R;
@@ -67,8 +66,7 @@
@Override
public int getMetricsCategory() {
- //TODO:Should we use a new metrics category for Wi-Fi DPP?
- return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
}
@Override
diff --git a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
index 39d993f..920e736 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppEnrolleeActivity.java
@@ -27,7 +27,6 @@
import androidx.fragment.app.FragmentTransaction;
import com.android.internal.logging.nano.MetricsProto;
-
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.R;
@@ -47,8 +46,7 @@
@Override
public int getMetricsCategory() {
- //TODO:Should we use a new metrics category for Wi-Fi DPP?
- return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
}
@Override
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
index e6427d9..6792dee 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeBaseFragment.java
@@ -18,7 +18,6 @@
import android.os.Bundle;
import android.view.LayoutInflater;
-import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -27,10 +26,7 @@
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.internal.logging.nano.MetricsProto;
-
import com.android.settings.core.InstrumentedFragment;
-import com.android.settings.wifi.qrcode.QrDecorateView;
import com.android.settings.R;
/**
@@ -47,17 +43,12 @@
* {@code WifiDppAddDeviceFragment}
*/
public abstract class WifiDppQrCodeBaseFragment extends InstrumentedFragment {
+ private ImageView mHeaderIcon;
private TextView mTitle;
private TextView mDescription;
- private SurfaceView mPreviewView; //optional, for WifiDppQrCodeScannerFragment
- private QrDecorateView mDecorateViiew; //optional, for WifiDppQrCodeScannerFragment
private TextView mErrorMessage; //optional, for WifiDppQrCodeScannerFragment
-
- private ImageView mBarcodeView; //optional, for WifiDppQrCodeGeneratorFragment
-
private ListView mSavedWifiNetworkList; //optional, for WifiDppChooseSavedWifiNetworkFragment
-
private ProgressBar mProgressBar; //optional, for WifiDppAddDeviceFragment
private ImageView mWifiApPictureView; //optional, for WifiDppAddDeviceFragment
private TextView mChooseDifferentNetwork;//optional, for WifiDppAddDeviceFragment
@@ -70,12 +61,6 @@
abstract protected int getLayout();
@Override
- public int getMetricsCategory() {
- //TODO:Should we use a new metrics category for Wi-Fi DPP?
- return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
- }
-
- @Override
public final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@@ -89,15 +74,11 @@
}
private void initView(View view) {
+ mHeaderIcon = view.findViewById(R.id.header_icon);
mTitle = view.findViewById(R.id.title);
mDescription = view.findViewById(R.id.description);
-
- mPreviewView = view.findViewById(R.id.preview_view);
- mDecorateViiew = view.findViewById(R.id.decorate_view);
mErrorMessage = view.findViewById(R.id.error_message);
- mBarcodeView = view.findViewById(R.id.barcode_view);
-
mSavedWifiNetworkList = view.findViewById(R.id.saved_wifi_network_list);
mProgressBar = view.findViewById(R.id.progress_bar);
@@ -108,6 +89,10 @@
mButtonRight = view.findViewById(R.id.button_right);
}
+ protected void setHeaderIconImageResource(int resId) {
+ mHeaderIcon.setImageResource(resId);
+ }
+
protected void setTitle(String title) {
mTitle.setText(title);
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index b064253..81def9b 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -23,6 +23,7 @@
import android.view.MenuInflater;
import android.view.MenuItem;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
/**
@@ -35,6 +36,11 @@
return R.layout.wifi_dpp_qrcode_generator_fragment;
}
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
+ }
+
// Container Activity must implement this interface
public interface OnQrCodeGeneratorFragmentAddButtonClickedListener {
public void onQrCodeGeneratorFragmentAddButtonClicked();
@@ -45,6 +51,7 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
+ setHeaderIconImageResource(R.drawable.ic_qrcode_24dp);
WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
.getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
@@ -79,7 +86,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.next_label);
- item.setIcon(R.drawable.ic_menu_add);
+ item.setIcon(R.drawable.ic_scan_24dp);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
super.onCreateOptionsMenu(menu, inflater);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index 342e693..8cd3c562 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -21,25 +21,28 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Size;
import android.view.Menu;
import android.view.MenuInflater;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
+import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.wifi.qrcode.QrCamera;
import com.android.settings.wifi.qrcode.QrDecorateView;
public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements
- SurfaceHolder.Callback,
+ SurfaceTextureListener,
QrCamera.ScannerCallback {
private QrCamera mCamera;
- private SurfaceView mSurfaceView;
+ private TextureView mTextureView;
private QrDecorateView mDecorateView;
/** true if the fragment working for configurator, false enrollee*/
@@ -53,6 +56,15 @@
return R.layout.wifi_dpp_qrcode_scanner_fragment;
}
+ @Override
+ public int getMetricsCategory() {
+ if (mConfiguratorMode) {
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_CONFIGURATOR;
+ } else {
+ return MetricsProto.MetricsEvent.SETTINGS_WIFI_DPP_ENROLLEE;
+ }
+ }
+
/**
* Configurator container activity of the fragment should create instance with this constructor.
*/
@@ -77,6 +89,8 @@
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
+ setHeaderIconImageResource(R.drawable.ic_scan_24dp);
+
if (mConfiguratorMode) {
setTitle(getString(R.string.wifi_dpp_add_device_to_network));
@@ -109,23 +123,13 @@
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mSurfaceView = (SurfaceView) view.findViewById(R.id.preview_view);
- final SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
- surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- surfaceHolder.addCallback(this);
+ mTextureView = (TextureView) view.findViewById(R.id.preview_view);
+ mTextureView.setSurfaceTextureListener(this);
mDecorateView = (QrDecorateView) view.findViewById(R.id.decorate_view);
}
@Override
- public void onDestroyView() {
- SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
- surfaceHolder.removeCallback(this);
-
- super.onDestroyView();
- }
-
- @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.removeItem(Menu.FIRST);
@@ -133,23 +137,29 @@
}
@Override
- public void surfaceCreated(final SurfaceHolder holder) {
- initCamera(holder);
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ initCamera(surface);
}
@Override
- public void surfaceDestroyed(SurfaceHolder holder) {
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Do nothing
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
destroyCamera();
+ return true;
}
@Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Do nothing
}
@Override
public Size getViewSize() {
- return new Size(mSurfaceView.getWidth(), mSurfaceView.getHeight());
+ return new Size(mTextureView.getWidth(), mTextureView.getHeight());
}
@Override
@@ -158,6 +168,11 @@
}
@Override
+ public void setTransform(Matrix transform) {
+ mTextureView.setTransform(transform);
+ }
+
+ @Override
public void handleSuccessfulResult(String qrCode) {
destroyCamera();
mDecorateView.setFocused(true);
@@ -169,11 +184,11 @@
destroyCamera();
}
- private void initCamera(SurfaceHolder holder) {
+ private void initCamera(SurfaceTexture surface) {
// Check if the camera has already created.
if (mCamera == null) {
mCamera = new QrCamera(getContext(), this);
- mCamera.start(holder);
+ mCamera.start(surface);
}
}
diff --git a/src/com/android/settings/wifi/qrcode/QrCamera.java b/src/com/android/settings/wifi/qrcode/QrCamera.java
index dc650b9..c60c30e 100644
--- a/src/com/android/settings/wifi/qrcode/QrCamera.java
+++ b/src/com/android/settings/wifi/qrcode/QrCamera.java
@@ -17,7 +17,10 @@
package com.android.settings.wifi.qrcode;
import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
@@ -29,7 +32,6 @@
import android.util.Log;
import android.util.Size;
import android.view.Surface;
-import android.view.SurfaceHolder;
import android.view.WindowManager;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
@@ -50,7 +52,7 @@
/**
* Manage the camera for the QR scanner and help the decoder to get the image inside the scanning
- * frame. Caller prepares a {@link SurfaceHolder} then call {@link #start(SurfaceHolder)} to
+ * frame. Caller prepares a {@link SurfaceTexture} then call {@link #start(SurfaceTexture)} to
* start QR Code scanning. The scanning result will return by ScannerCallback interface. Caller
* can also call {@link #stop()} to halt QR Code scanning before the result returned.
*/
@@ -90,12 +92,11 @@
* The function start camera preview and capture pictures to decode QR code continuously in a
* background task.
*
- * @param surfaceHolder the Surface to be used for live preview, must already contain a surface
- * when this method is called.
+ * @param surface The surface to be used for live preview.
*/
- public void start(SurfaceHolder surfaceHolder) {
+ public void start(SurfaceTexture surface) {
if (mDecodeTask == null) {
- mDecodeTask = new DecodingTask(surfaceHolder);
+ mDecodeTask = new DecodingTask(surface);
// Execute in the separate thread pool to prevent block other AsyncTask.
mDecodeTask.executeOnExecutor(Executors.newSingleThreadExecutor());
}
@@ -144,6 +145,13 @@
* @return The rectangle would like to crop from the camera preview shot.
*/
Rect getFramePosition(Size previewSize, int cameraOrientation);
+
+ /**
+ * Sets the transform to associate with preview area.
+ *
+ * @param transform The transform to apply to the content of preview
+ */
+ void setTransform(Matrix transform);
}
private void setCameraParameter() {
@@ -200,15 +208,15 @@
private class DecodingTask extends AsyncTask<Void, Void, String> {
private QrYuvLuminanceSource mImage;
- private SurfaceHolder mSurfaceHolder;
+ private SurfaceTexture mSurface;
- private DecodingTask(SurfaceHolder surfaceHolder) {
- mSurfaceHolder = surfaceHolder;
+ private DecodingTask(SurfaceTexture surface) {
+ mSurface = surface;
}
@Override
protected String doInBackground(Void... tmp) {
- if (!initCamera(mSurfaceHolder)) {
+ if (!initCamera(mSurface)) {
return null;
}
@@ -253,7 +261,7 @@
}
}
- private boolean initCamera(SurfaceHolder surfaceHolder) {
+ private boolean initCamera(SurfaceTexture surface) {
final int numberOfCameras = Camera.getNumberOfCameras();
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
try {
@@ -261,7 +269,7 @@
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
mCamera = Camera.open(i);
- mCamera.setPreviewDisplay(surfaceHolder);
+ mCamera.setPreviewTexture(surface);
mCameraOrientation = cameraInfo.orientation;
break;
}
@@ -272,6 +280,7 @@
return false;
}
setCameraParameter();
+ setTransformationMatrix(mScannerCallback.getViewSize());
if (!startPreview()) {
Log.e(TAG, "Error to init Camera");
mCamera = null;
@@ -288,6 +297,36 @@
}
}
+ /** Set transfom matrix to crop and center the preview picture */
+ private void setTransformationMatrix(Size viewSize) {
+ // Check aspect ratio, can only handle square view.
+ final int viewRatio = (int)getRatio(viewSize.getWidth(), viewSize.getHeight());
+ if (viewRatio != 1) {
+ throw new IllegalArgumentException("Preview area should be square");
+ }
+
+ final boolean isPortrait = mContext.get().getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT ? true : false;
+
+ final int previewWidth = isPortrait ? mPreviewSize.getWidth() : mPreviewSize.getHeight();
+ final int previewHeight = isPortrait ? mPreviewSize.getHeight() : mPreviewSize.getWidth();
+ final float ratioPreview = (float) getRatio(previewWidth, previewHeight);
+
+ // Calculate transformation matrix.
+ float scaleX = 1.0f;
+ float scaleY = 1.0f;
+ if (previewWidth > previewHeight) {
+ scaleY = scaleX / ratioPreview;
+ } else {
+ scaleX = scaleY / ratioPreview;
+ }
+
+ // Set the transform matrix.
+ final Matrix matrix = new Matrix();
+ matrix.setScale(scaleX, scaleY);
+ mScannerCallback.setTransform(matrix);
+ }
+
private QrYuvLuminanceSource getFrameImage(byte[] imageData) {
final Rect frame = mScannerCallback.getFramePosition(mPreviewSize, mCameraOrientation);
final Camera.Size size = mParameters.getPictureSize();
diff --git a/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java b/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java
new file mode 100644
index 0000000..56566ae
--- /dev/null
+++ b/src/com/android/settings/wifi/qrcode/QrPreviewLayout.java
@@ -0,0 +1,50 @@
+/*
+ * 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.qrcode;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.FrameLayout;
+
+/**
+ * A customize square {@link FrameLayout}.
+ * This is used for camera preview. Choose the smaller size of both dimensions as length and width.
+ */
+public class QrPreviewLayout extends FrameLayout {
+ public QrPreviewLayout(Context context) {
+ super(context);
+ }
+
+ public QrPreviewLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public QrPreviewLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Choose the smaller size of the two dimensions.
+ if (MeasureSpec.getSize(widthMeasureSpec) > MeasureSpec.getSize(heightMeasureSpec)) {
+ super.onMeasure(heightMeasureSpec, heightMeasureSpec);
+ } else {
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
new file mode 100644
index 0000000..fa8c267
--- /dev/null
+++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi.slice;
+
+import android.content.Context;
+import android.net.Uri;
+import android.net.wifi.WifiSsid;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.slice.Slice;
+
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.CustomSliceable;
+
+/**
+ * {@link CustomSliceable} for Wi-Fi, used by contextual homepage.
+ */
+public class ContextualWifiSlice extends WifiSlice {
+
+ private static final String TAG = "ContextualWifiSlice";
+ @VisibleForTesting
+ boolean mPreviouslyDisplayed;
+
+ public ContextualWifiSlice(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Uri getUri() {
+ return CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI;
+ }
+
+ @Override
+ public Slice getSlice() {
+ if (!mPreviouslyDisplayed && !TextUtils.equals(getActiveSSID(), WifiSsid.NONE)) {
+ Log.d(TAG, "Wifi is connected, no point showing any suggestion.");
+ return null;
+ }
+ // Set mPreviouslyDisplayed to true - we will show *something* on the screen. So we should
+ // keep showing this card to keep UI stable, even if wifi connects to a network later.
+ mPreviouslyDisplayed = true;
+
+ return super.getSlice();
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
similarity index 95%
rename from src/com/android/settings/wifi/WifiSlice.java
rename to src/com/android/settings/wifi/slice/WifiSlice.java
index 9f05783..4d3a95a 100644
--- a/src/com/android/settings/wifi/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.wifi;
+package com.android.settings.wifi.slice;
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
import static android.provider.SettingsSlicesContract.KEY_WIFI;
@@ -46,6 +46,8 @@
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settings.wifi.WifiDialogActivity;
+import com.android.settings.wifi.WifiSettings;
import com.android.settings.wifi.details.WifiNetworkDetailsFragment;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.WifiTracker;
@@ -54,15 +56,15 @@
import java.util.List;
/**
- * Utility class to build a Wifi Slice, and handle all associated actions.
+ * {@link CustomSliceable} for Wi-Fi, used by generic clients.
*/
public class WifiSlice implements CustomSliceable {
@VisibleForTesting
static final int DEFAULT_EXPANDED_ROW_COUNT = 3;
+ protected final WifiManager mWifiManager;
private final Context mContext;
- private final WifiManager mWifiManager;
public WifiSlice(Context context) {
mContext = context;
@@ -77,6 +79,7 @@
@Override
public Slice getSlice() {
final boolean isWifiEnabled = isWifiEnabled();
+
final IconCompat icon = IconCompat.createWithResource(mContext,
R.drawable.ic_settings_wireless);
final String title = mContext.getString(R.string.wifi_settings);
@@ -208,6 +211,13 @@
return intent;
}
+ protected String getActiveSSID() {
+ if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED) {
+ return WifiSsid.NONE;
+ }
+ return WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo().getSSID());
+ }
+
private boolean isWifiEnabled() {
switch (mWifiManager.getWifiState()) {
case WifiManager.WIFI_STATE_ENABLED:
@@ -221,8 +231,7 @@
private CharSequence getSummary() {
switch (mWifiManager.getWifiState()) {
case WifiManager.WIFI_STATE_ENABLED:
- final String ssid = WifiInfo.removeDoubleQuotes(mWifiManager.getConnectionInfo()
- .getSSID());
+ final String ssid = getActiveSSID();
if (TextUtils.equals(ssid, WifiSsid.NONE)) {
return mContext.getText(R.string.disconnected);
}
diff --git a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
index befd880..ce03d95 100644
--- a/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
+++ b/tests/robotests/assets/grandfather_invalid_base_preference_controller_constructor
@@ -7,7 +7,6 @@
com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController
com.android.settings.datausage.DataUsageSummaryPreferenceController
com.android.settings.fuelgauge.RestrictAppPreferenceController
-com.android.settings.fuelgauge.batterysaver.AutoBatterySeekBarPreferenceController
com.android.settings.fuelgauge.batterysaver.BatterySaverButtonPreferenceController
com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController
com.android.settings.security.VisiblePatternProfilePreferenceController
diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java
index 21cb09c..388440e 100644
--- a/tests/robotests/src/com/android/settings/MasterClearTest.java
+++ b/tests/robotests/src/com/android/settings/MasterClearTest.java
@@ -51,6 +51,7 @@
import androidx.fragment.app.FragmentActivity;
import com.android.settings.testutils.shadow.ShadowUtils;
+import com.google.android.setupcompat.item.FooterButton;
import org.junit.Before;
import org.junit.Test;
@@ -386,7 +387,7 @@
public void testOnGlobalLayout_shouldNotRemoveListener() {
final ViewTreeObserver viewTreeObserver = mock(ViewTreeObserver.class);
mMasterClear.mScrollView = mScrollView;
- mMasterClear.mInitiateButton = mock(Button.class);
+ mMasterClear.mInitiateButton = mock(FooterButton.class);
doReturn(true).when(mMasterClear).hasReachedBottom(any());
when(mScrollView.getViewTreeObserver()).thenReturn(viewTreeObserver);
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java
new file mode 100644
index 0000000..39a05cb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/financialapps/FinancialAppsControllerTest.java
@@ -0,0 +1,125 @@
+package com.android.settings.applications.specialaccess.financialapps;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import static android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS;
+import static android.Manifest.permission.READ_SMS;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+public class FinancialAppsControllerTest {
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private PreferenceScreen mRoot;
+ @Mock
+ private Preference mPreference;
+
+ private Context mContext;
+ private PackageInfo mPackageInfoNoPermissionRequested;
+ private PackageInfo mPackageInfoPermissionRequestedQPlus;
+ private PackageInfo mPackageInfoPermissionRequestedPreQ;
+ private FinancialAppsController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
+
+ initializePackageInfos();
+
+ mController = new FinancialAppsController(mContext, "key");
+ mController.displayPreference(mRoot);
+ }
+
+ private void initializePackageInfos() {
+ mPackageInfoNoPermissionRequested = new PackageInfo();
+ mPackageInfoNoPermissionRequested.applicationInfo = new ApplicationInfo();
+
+ mPackageInfoPermissionRequestedQPlus = new PackageInfo();
+ mPackageInfoPermissionRequestedQPlus.applicationInfo = new ApplicationInfo();
+ // TODO(b/121161546): update after robolectric test support Q
+ //mPackageInfoPermissionRequestedQPlus.applicationInfo.targetSdkVersion =
+ // Build.VERSION_CODES.Q;
+ mPackageInfoPermissionRequestedQPlus.applicationInfo.uid = 2001;
+ mPackageInfoPermissionRequestedQPlus.applicationInfo.nonLocalizedLabel = "QPLUS Package";
+ mPackageInfoPermissionRequestedQPlus.packageName = "QPLUS";
+ mPackageInfoPermissionRequestedQPlus.requestedPermissions =
+ new String[] {SMS_FINANCIAL_TRANSACTIONS};
+
+ mPackageInfoPermissionRequestedPreQ = new PackageInfo();
+ mPackageInfoPermissionRequestedPreQ.applicationInfo = new ApplicationInfo();
+ mPackageInfoPermissionRequestedPreQ.applicationInfo.targetSdkVersion = Build.VERSION_CODES.M;
+ mPackageInfoPermissionRequestedPreQ.applicationInfo.uid = 2002;
+ mPackageInfoPermissionRequestedPreQ.applicationInfo.nonLocalizedLabel = "PREQ Package";
+ mPackageInfoPermissionRequestedPreQ.packageName = "PREQ";
+ mPackageInfoPermissionRequestedPreQ.requestedPermissions = new String[] {READ_SMS};
+ }
+
+ @Test
+ public void isAvailable_true() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void noPreferenceAddedWhenNoPackageRequestPermission() {
+ when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+ .thenReturn(new ArrayList<PackageInfo>(
+ Arrays.asList(mPackageInfoNoPermissionRequested)));
+ mController.updateState(null);
+ assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(0);
+ }
+
+ //TODO(b/121161546): Add these tests after robolectric test support Q
+ /*
+ @Test
+ public void preferenceAddedWhenPreQPackageRequestPermission() {
+ when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+ .thenReturn(new ArrayList<PackageInfo>(
+ Arrays.asList(mPackageInfoPermissionRequestedPreQ)));
+ mController.updateState(null);
+ assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
+ SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
+ assertThat(pref).isNotNull();
+ }
+
+ @Test
+ public void preferenceAddedWhenQPlusPackageRequestPermission() {
+ when(mPackageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS))
+ .thenReturn(new ArrayList<PackageInfo>(
+ Arrays.asList(mPackageInfoPermissionRequestedQPlus)));
+ mController.updateState(null);
+ assertThat(mController.mRoot.getPreferenceCount()).isEqualTo(1);
+ SwitchPreference pref = (SwitchPreference) mController.mRoot.getPreference(0);
+ assertThat(pref).isNotNull();
+ }*/
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.java
new file mode 100644
index 0000000..887f58c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFeatureProviderImplTest.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.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BluetoothFeatureProviderImplTest {
+ private static final String PARAMETER_KEY = "addr";
+ private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+ private BluetoothFeatureProvider mBluetoothFeatureProvider;
+
+ @Before
+ public void setUp() {
+ mBluetoothFeatureProvider = new BluetoothFeatureProviderImpl(
+ RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getBluetoothDeviceSettingsUri_containCorrectMacAddress() {
+ final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(MAC_ADDRESS);
+ assertThat(uri.getQueryParameterNames()).containsExactly(PARAMETER_KEY);
+ assertThat(uri.getQueryParameter(PARAMETER_KEY)).isEqualTo(MAC_ADDRESS);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
index b698b3a..7c6a305 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/ConnectedUsbDeviceUpdaterTest.java
@@ -15,6 +15,11 @@
*/
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -22,7 +27,6 @@
import android.content.Context;
import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
import com.android.settings.R;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
@@ -78,7 +82,7 @@
public void initUsbPreference_usbConnected_preferenceAdded() {
mDeviceUpdater.initUsbPreference(mContext);
mDeviceUpdater.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */,
- UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ UsbManager.FUNCTION_NONE, POWER_ROLE_SINK, DATA_ROLE_DEVICE);
verify(mDevicePreferenceCallback).onDeviceAdded(mDeviceUpdater.mUsbPreference);
}
@@ -87,7 +91,7 @@
public void initUsbPreference_usbDisconnected_preferenceRemoved() {
mDeviceUpdater.initUsbPreference(mContext);
mDeviceUpdater.mUsbConnectionListener.onUsbConnectionChanged(false /* connected */,
- UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ UsbManager.FUNCTION_NONE, POWER_ROLE_NONE, DATA_ROLE_NONE);
verify(mDevicePreferenceCallback).onDeviceRemoved(mDeviceUpdater.mUsbPreference);
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
index 333d2b6..4e5897d 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbBackendTest.java
@@ -16,6 +16,11 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
@@ -40,6 +45,8 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import java.util.Collections;
+
@RunWith(RobolectricTestRunner.class)
public class UsbBackendTest {
@@ -64,9 +71,9 @@
when((Object) mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE))
.thenReturn(mConnectivityManager);
- when(mUsbManager.getPorts()).thenReturn(new UsbPort[] {mUsbPort});
+ when(mUsbManager.getPorts()).thenReturn(Collections.singletonList(mUsbPort));
when(mUsbPortStatus.isConnected()).thenReturn(true);
- when(mUsbManager.getPortStatus(mUsbPort)).thenReturn(mUsbPortStatus);
+ when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
}
@Test
@@ -74,22 +81,22 @@
final UsbBackend usbBackend = new UsbBackend(mContext, mUserManager);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_HOST))
.thenReturn(true);
- when(mUsbPortStatus.getCurrentPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbPortStatus.getCurrentPowerRole()).thenReturn(POWER_ROLE_SINK);
- usbBackend.setDataRole(UsbPort.DATA_ROLE_HOST);
+ usbBackend.setDataRole(DATA_ROLE_HOST);
- verify(mUsbManager).setPortRoles(mUsbPort, UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST);
+ verify(mUsbPort).setRoles(POWER_ROLE_SINK, DATA_ROLE_HOST);
}
@Test
@@ -97,17 +104,16 @@
final UsbBackend usbBackend = new UsbBackend(mContext, mUserManager);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_HOST))
.thenReturn(true);
- when(mUsbPortStatus.getCurrentPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbPortStatus.getCurrentPowerRole()).thenReturn(POWER_ROLE_SINK);
- usbBackend.setDataRole(UsbPort.DATA_ROLE_HOST);
+ usbBackend.setDataRole(DATA_ROLE_HOST);
- verify(mUsbManager)
- .setPortRoles(mUsbPort, UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
+ verify(mUsbPort).setRoles(POWER_ROLE_SOURCE, DATA_ROLE_HOST);
}
@Test
@@ -115,23 +121,22 @@
final UsbBackend usbBackend = new UsbBackend(mContext, mUserManager);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_HOST))
.thenReturn(true);
- when(mUsbPortStatus.getCurrentDataRole()).thenReturn(UsbPort.DATA_ROLE_DEVICE);
+ when(mUsbPortStatus.getCurrentDataRole()).thenReturn(DATA_ROLE_DEVICE);
- usbBackend.setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ usbBackend.setPowerRole(POWER_ROLE_SOURCE);
- verify(mUsbManager)
- .setPortRoles(mUsbPort, UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbPort).setRoles(POWER_ROLE_SOURCE, DATA_ROLE_DEVICE);
}
@Test
@@ -139,17 +144,16 @@
final UsbBackend usbBackend = new UsbBackend(mContext, mUserManager);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE))
+ .isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE))
.thenReturn(true);
when(mUsbPortStatus
- .isRoleCombinationSupported(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST))
+ .isRoleCombinationSupported(POWER_ROLE_SOURCE, DATA_ROLE_HOST))
.thenReturn(true);
- when(mUsbPortStatus.getCurrentDataRole()).thenReturn(UsbPort.DATA_ROLE_DEVICE);
+ when(mUsbPortStatus.getCurrentDataRole()).thenReturn(DATA_ROLE_DEVICE);
- usbBackend.setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ usbBackend.setPowerRole(POWER_ROLE_SOURCE);
- verify(mUsbManager)
- .setPortRoles(mUsbPort, UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
+ verify(mUsbPort).setRoles(POWER_ROLE_SOURCE, DATA_ROLE_HOST);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
index 1689ee7..1da97f5 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiverTest.java
@@ -15,6 +15,11 @@
*/
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
@@ -22,7 +27,6 @@
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import org.junit.Before;
@@ -63,7 +67,7 @@
mReceiver.onReceive(mContext, intent);
verify(mListener).onUsbConnectionChanged(true /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
}
@Test
@@ -75,7 +79,7 @@
mReceiver.onReceive(mContext, intent);
verify(mListener).onUsbConnectionChanged(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
}
@Test
@@ -89,21 +93,21 @@
mReceiver.onReceive(mContext, intent);
verify(mListener).onUsbConnectionChanged(true /* connected */, UsbManager.FUNCTION_MTP,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
}
@Test
public void onReceive_usbPortStatus_invokeCallback() {
final Intent intent = new Intent();
intent.setAction(UsbManager.ACTION_USB_PORT_CHANGED);
- final UsbPortStatus status = new UsbPortStatus(0, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE, 0);
+ final UsbPortStatus status = new UsbPortStatus(0, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE, 0);
intent.putExtra(UsbManager.EXTRA_PORT_STATUS, status);
mReceiver.onReceive(mContext, intent);
verify(mListener).onUsbConnectionChanged(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SINK, DATA_ROLE_DEVICE);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
index 3eda3d1..91e680b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java
@@ -16,6 +16,12 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -24,7 +30,6 @@
import android.content.Context;
import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
import android.os.Handler;
import androidx.fragment.app.FragmentActivity;
@@ -92,11 +97,11 @@
public void displayRefresh_deviceRole_shouldCheckDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
- mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
- final RadioButtonPreference hostPref = getRadioPreference(UsbPort.DATA_ROLE_HOST);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
+ final RadioButtonPreference hostPref = getRadioPreference(DATA_ROLE_HOST);
assertThat(devicePref.isChecked()).isTrue();
assertThat(hostPref.isChecked()).isFalse();
}
@@ -105,11 +110,11 @@
public void displayRefresh_hostRole_shouldCheckHost() {
mDetailsDataRoleController.displayPreference(mScreen);
- mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_HOST);
+ mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
- final RadioButtonPreference hostPref = getRadioPreference(UsbPort.DATA_ROLE_HOST);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
+ final RadioButtonPreference hostPref = getRadioPreference(DATA_ROLE_HOST);
assertThat(devicePref.isChecked()).isFalse();
assertThat(hostPref.isChecked()).isTrue();
}
@@ -118,8 +123,8 @@
public void displayRefresh_disconnected_shouldDisable() {
mDetailsDataRoleController.displayPreference(mScreen);
- mDetailsDataRoleController.refresh(false, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsDataRoleController.refresh(false, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
assertThat(mPreference.isEnabled()).isFalse();
}
@@ -127,12 +132,12 @@
@Test
public void onClickDevice_hostEnabled_shouldSetDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
- when(mUsbBackend.getDataRole()).thenReturn(UsbPort.DATA_ROLE_HOST);
+ when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
devicePref.performClick();
- verify(mUsbBackend).setDataRole(UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbBackend).setDataRole(DATA_ROLE_DEVICE);
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
}
@@ -140,50 +145,50 @@
@Test
public void onClickDeviceTwice_hostEnabled_shouldSetDeviceOnce() {
mDetailsDataRoleController.displayPreference(mScreen);
- when(mUsbBackend.getDataRole()).thenReturn(UsbPort.DATA_ROLE_HOST);
+ when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
devicePref.performClick();
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
devicePref.performClick();
- verify(mUsbBackend).setDataRole(UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbBackend).setDataRole(DATA_ROLE_DEVICE);
}
@Test
public void onClickDeviceAndRefresh_success_shouldClearSubtext() {
mDetailsDataRoleController.displayPreference(mScreen);
- when(mUsbBackend.getDataRole()).thenReturn(UsbPort.DATA_ROLE_HOST);
+ when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
devicePref.performClick();
- verify(mUsbBackend).setDataRole(UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbBackend).setDataRole(DATA_ROLE_DEVICE);
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsDataRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
mDetailsDataRoleController.refresh(true /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SINK, DATA_ROLE_DEVICE);
assertThat(devicePref.getSummary()).isEqualTo("");
}
@Test
public void onClickDeviceAndRefresh_failed_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
- when(mUsbBackend.getDataRole()).thenReturn(UsbPort.DATA_ROLE_HOST);
+ when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
devicePref.performClick();
- verify(mUsbBackend).setDataRole(UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbBackend).setDataRole(DATA_ROLE_DEVICE);
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsDataRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
mDetailsDataRoleController.refresh(true /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST);
+ POWER_ROLE_SINK, DATA_ROLE_HOST);
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching_failed));
}
@@ -191,18 +196,18 @@
@Test
public void onClickDevice_timedOut_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
- when(mUsbBackend.getDataRole()).thenReturn(UsbPort.DATA_ROLE_HOST);
+ when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
- final RadioButtonPreference devicePref = getRadioPreference(UsbPort.DATA_ROLE_DEVICE);
+ final RadioButtonPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
devicePref.performClick();
- verify(mUsbBackend).setDataRole(UsbPort.DATA_ROLE_DEVICE);
+ verify(mUsbBackend).setDataRole(DATA_ROLE_DEVICE);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
verify(mHandler).postDelayed(captor.capture(), anyLong());
assertThat(devicePref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsDataRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
captor.getValue().run();
assertThat(devicePref.getSummary())
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
index fc93a58..11fa613 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.net.ConnectivityManager.TETHERING_USB;
import static com.google.common.truth.Truth.assertThat;
@@ -105,8 +107,8 @@
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
List<RadioButtonPreference> prefs = getRadioPreferences();
Iterator<Long> iter = UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet().iterator();
@@ -120,7 +122,7 @@
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.refresh(false, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SINK, DATA_ROLE_DEVICE);
assertThat(mPreferenceCategory.isEnabled()).isFalse();
}
@@ -131,8 +133,8 @@
when(mUsbBackend.areFunctionsSupported(UsbManager.FUNCTION_PTP)).thenReturn(false);
when(mUsbBackend.areFunctionsSupported(UsbManager.FUNCTION_RNDIS)).thenReturn(false);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
List<RadioButtonPreference> prefs = getRadioPreferences();
assertThat(prefs.size()).isEqualTo(1);
assertThat(prefs.get(0).getKey())
@@ -143,8 +145,8 @@
public void displayRefresh_mtpEnabled_shouldCheckSwitches() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
List<RadioButtonPreference> prefs = getRadioPreferences();
assertThat(prefs.get(0).getKey())
@@ -156,8 +158,8 @@
public void onClickMtp_noneEnabled_shouldEnableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_NONE);
List<RadioButtonPreference> prefs = getRadioPreferences();
prefs.get(0).performClick();
@@ -165,8 +167,8 @@
assertThat(prefs.get(0).getKey())
.isEqualTo(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_MTP));
verify(mUsbBackend).setCurrentFunctions(UsbManager.FUNCTION_MTP);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
assertThat(prefs.get(0).isChecked()).isTrue();
}
@@ -174,8 +176,8 @@
public void onClickMtp_ptpEnabled_shouldEnableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_PTP, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_PTP, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_PTP);
List<RadioButtonPreference> prefs = getRadioPreferences();
prefs.get(0).performClick();
@@ -183,8 +185,8 @@
assertThat(prefs.get(0).getKey())
.isEqualTo(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_MTP));
verify(mUsbBackend).setCurrentFunctions(UsbManager.FUNCTION_MTP);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
assertThat(prefs.get(0).isChecked()).isTrue();
assertThat(prefs.get(3).getKey())
.isEqualTo(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
@@ -195,8 +197,8 @@
public void onClickNone_mtpEnabled_shouldDisableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_MTP);
List<RadioButtonPreference> prefs = getRadioPreferences();
prefs.get(4).performClick();
@@ -204,8 +206,8 @@
assertThat(prefs.get(4).getKey())
.isEqualTo(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_NONE));
verify(mUsbBackend).setCurrentFunctions(UsbManager.FUNCTION_NONE);
- mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
assertThat(prefs.get(0).isChecked()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
index d72214f..280b8d4 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsHeaderControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -101,8 +104,8 @@
@Test
public void displayRefresh_charging_shouldSetHeader() {
mDetailsHeaderController.displayPreference(mScreen);
- mDetailsHeaderController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsHeaderController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
verify(mHeaderController).setLabel(mContext.getString(R.string.usb_pref));
verify(mHeaderController).setIcon(argThat((ArgumentMatcher<Drawable>) t -> {
DrawableTestHelper.assertDrawableResId(t, R.drawable.ic_usb);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
index b16a453..aa62741 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsPowerRoleControllerTest.java
@@ -16,6 +16,13 @@
package com.android.settings.connecteddevice.usb;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST;
+import static android.hardware.usb.UsbPortStatus.DATA_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
+import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -25,7 +32,6 @@
import android.content.Context;
import android.hardware.usb.UsbManager;
-import android.hardware.usb.UsbPort;
import android.os.Handler;
import androidx.fragment.app.FragmentActivity;
@@ -95,8 +101,8 @@
mDetailsPowerRoleController.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
- mDetailsPowerRoleController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsPowerRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
SwitchPreference pref = getPreference();
assertThat(pref.isChecked()).isFalse();
@@ -108,7 +114,7 @@
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mDetailsPowerRoleController.refresh(true, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
+ POWER_ROLE_SOURCE, DATA_ROLE_HOST);
SwitchPreference pref = getPreference();
assertThat(pref.isChecked()).isTrue();
@@ -120,7 +126,7 @@
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mDetailsPowerRoleController.refresh(false, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SINK, DATA_ROLE_DEVICE);
assertThat(mPreference.isEnabled()).isFalse();
assertThat((Preference) mScreen.findPreference(
@@ -132,8 +138,8 @@
mDetailsPowerRoleController.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(false);
- mDetailsPowerRoleController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
- UsbPort.DATA_ROLE_DEVICE);
+ mDetailsPowerRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
+ DATA_ROLE_DEVICE);
assertThat((Preference) mScreen.findPreference(
mDetailsPowerRoleController.getPreferenceKey())).isNull();
@@ -142,12 +148,12 @@
@Test
public void onClick_sink_shouldSetSource() {
mDetailsPowerRoleController.displayPreference(mScreen);
- when(mUsbBackend.getPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbBackend.getPowerRole()).thenReturn(POWER_ROLE_SINK);
SwitchPreference pref = getPreference();
pref.performClick();
- verify(mUsbBackend).setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ verify(mUsbBackend).setPowerRole(POWER_ROLE_SOURCE);
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
}
@@ -155,7 +161,7 @@
@Test
public void onClickTwice_sink_shouldSetSourceOnce() {
mDetailsPowerRoleController.displayPreference(mScreen);
- when(mUsbBackend.getPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbBackend.getPowerRole()).thenReturn(POWER_ROLE_SINK);
SwitchPreference pref = getPreference();
pref.performClick();
@@ -163,42 +169,42 @@
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
pref.performClick();
- verify(mUsbBackend, times(1)).setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ verify(mUsbBackend, times(1)).setPowerRole(POWER_ROLE_SOURCE);
}
@Test
public void onClickDeviceAndRefresh_success_shouldClearSubtext() {
mDetailsPowerRoleController.displayPreference(mScreen);
- when(mUsbBackend.getPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbBackend.getPowerRole()).thenReturn(POWER_ROLE_SINK);
SwitchPreference pref = getPreference();
pref.performClick();
- verify(mUsbBackend).setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ verify(mUsbBackend).setPowerRole(POWER_ROLE_SOURCE);
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsPowerRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
mDetailsPowerRoleController.refresh(true /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SOURCE, DATA_ROLE_DEVICE);
assertThat(pref.getSummary()).isEqualTo("");
}
@Test
public void onClickDeviceAndRefresh_failed_shouldShowFailureText() {
mDetailsPowerRoleController.displayPreference(mScreen);
- when(mUsbBackend.getPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbBackend.getPowerRole()).thenReturn(POWER_ROLE_SINK);
SwitchPreference pref = getPreference();
pref.performClick();
- verify(mUsbBackend).setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ verify(mUsbBackend).setPowerRole(POWER_ROLE_SOURCE);
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsPowerRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
mDetailsPowerRoleController.refresh(true /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
+ POWER_ROLE_SINK, DATA_ROLE_DEVICE);
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching_failed));
}
@@ -206,18 +212,18 @@
@Test
public void onClickDevice_timedOut_shouldShowFailureText() {
mDetailsPowerRoleController.displayPreference(mScreen);
- when(mUsbBackend.getPowerRole()).thenReturn(UsbPort.POWER_ROLE_SINK);
+ when(mUsbBackend.getPowerRole()).thenReturn(POWER_ROLE_SINK);
SwitchPreference pref = getPreference();
pref.performClick();
- verify(mUsbBackend).setPowerRole(UsbPort.POWER_ROLE_SOURCE);
+ verify(mUsbBackend).setPowerRole(POWER_ROLE_SOURCE);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
verify(mHandler).postDelayed(captor.capture(), anyLong());
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching));
mDetailsPowerRoleController.refresh(false /* connected */, UsbManager.FUNCTION_NONE,
- UsbPort.POWER_ROLE_NONE, UsbPort.DATA_ROLE_NONE);
+ POWER_ROLE_NONE, DATA_ROLE_NONE);
captor.getValue().run();
assertThat(pref.getSummary())
.isEqualTo(mContext.getString(R.string.usb_switching_failed));
diff --git a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java
index ce438b0..28e394f 100644
--- a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java
+++ b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerSignatureInspector.java
@@ -71,7 +71,9 @@
.that(badClasses.toString())
.isEmpty();
- assertWithMessage("Something in the grandfather list is no longer relevant. Please remove")
+ assertWithMessage("Something in the grandfather list is no longer relevant. Please remove"
+ + "it from packages/apps/Settings/tests/robotests/assets/"
+ + "grandfather_invalid_base_preference_controller_constructor")
.that(grandfather)
.isEmpty();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 7c455bb..a60460b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -38,7 +39,10 @@
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -75,6 +79,8 @@
@RunWith(RobolectricTestRunner.class)
public class BatteryUtilsTest {
+ private static final String TAG = "BatteryUtilsTest";
+
// unit that used to converted ms to us
private static final long UNIT = 1000;
private static final long TIME_STATE_TOP = 1500 * UNIT;
@@ -160,6 +166,7 @@
private FakeFeatureFactory mFeatureFactory;
private PowerUsageFeatureProvider mProvider;
private List<BatterySipper> mUsageList;
+ private Context mContext;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
@@ -214,10 +221,10 @@
mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
- final Context shadowContext = spy(RuntimeEnvironment.application);
- doReturn(mPackageManager).when(shadowContext).getPackageManager();
- doReturn(mAppOpsManager).when(shadowContext).getSystemService(Context.APP_OPS_SERVICE);
- mBatteryUtils = spy(new BatteryUtils(shadowContext));
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE);
+ mBatteryUtils = spy(new BatteryUtils(mContext));
mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
doReturn(0L).when(mBatteryUtils)
.getForegroundServiceTotalTimeUs(any(BatteryStats.Uid.class), anyLong());
@@ -710,4 +717,15 @@
verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID,
PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
}
+
+ @Test
+ public void getBatteryInfo_providerNull_shouldNotCrash() {
+ when(mProvider.isEnhancedBatteryPredictionEnabled(mContext)).thenReturn(true);
+ when(mProvider.getEnhancedBatteryPrediction(mContext)).thenReturn(null);
+ when(mContext.registerReceiver(nullable(BroadcastReceiver.class),
+ any(IntentFilter.class))).thenReturn(new Intent());
+
+ //Should not crash
+ assertThat(mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG)).isNotNull();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceControllerTest.java
deleted file mode 100644
index df1d909..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySaverPreferenceControllerTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package com.android.settings.fuelgauge.batterysaver;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.SwitchPreference;
-
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class AutoBatterySaverPreferenceControllerTest {
-
- private AutoBatterySaverPreferenceController mController;
- private Context mContext;
- private SwitchPreference mPreference;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mContext = RuntimeEnvironment.application;
- mPreference = new SwitchPreference(mContext);
- mController = new AutoBatterySaverPreferenceController(mContext);
- }
-
- @Test
- public void testUpdateState_lowPowerLevelZero_preferenceNotChecked() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testUpdateState_lowPowerLevelZero_preferenceChecked() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15);
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testOnPreferenceChange_turnOn_setValueNotZero() {
- mController.onPreferenceChange(mPreference, true);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isNotEqualTo(0);
- }
-
- @Test
- public void testOnPreferenceChange_turnOff_setValueZero() {
- mController.onPreferenceChange(mPreference, false);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isEqualTo(0);
- }
-
- @Test
- public void testIsChecked_useDefaultValue_returnFalse() {
- assertThat(mController.isChecked()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java
deleted file mode 100644
index c13b913..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/AutoBatterySeekBarPreferenceControllerTest.java
+++ /dev/null
@@ -1,117 +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.fuelgauge.batterysaver;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.lifecycle.LifecycleOwner;
-
-import com.android.settings.widget.SeekBarPreference;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class AutoBatterySeekBarPreferenceControllerTest {
-
- private static final int TRIGGER_LEVEL = 20;
- private static final int INTERVAL = 5;
-
- private AutoBatterySeekBarPreferenceController mController;
- private Context mContext;
- private SeekBarPreference mPreference;
- private Lifecycle mLifecycle;
- private LifecycleOwner mLifecycleOwner;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mLifecycleOwner = () -> mLifecycle;
- mLifecycle = new Lifecycle(mLifecycleOwner);
-
- mContext = RuntimeEnvironment.application;
- mPreference = new SeekBarPreference(mContext);
- mPreference.setMax(100);
- mController = new AutoBatterySeekBarPreferenceController(mContext, mLifecycle);
- }
-
- @Test
- public void testPreference_lowPowerLevelZero_preferenceInvisible() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isVisible()).isFalse();
- }
-
- @Test
- public void testPreference_defaultValue_preferenceNotVisible() {
- mController.updateState(mPreference);
-
- assertThat(mPreference.isVisible()).isFalse();
- }
-
- @Test
- public void testPreference_lowPowerLevelNotZero_updatePreference() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, TRIGGER_LEVEL);
- mController.updateState(mPreference);
-
- assertThat(mPreference.isVisible()).isTrue();
- assertThat(mPreference.getTitle()).isEqualTo("20%");
- assertThat(mPreference.getProgress()).isEqualTo(TRIGGER_LEVEL / INTERVAL);
- }
-
- @Test
- public void testOnPreferenceChange_updateValue() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-
- mController.onPreferenceChange(mPreference, TRIGGER_LEVEL / INTERVAL);
-
- assertThat(Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)).isEqualTo(TRIGGER_LEVEL);
- }
-
- @Test
- public void testOnPreferenceChange_changeMax() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 50);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.getMax()).isEqualTo(50 / INTERVAL);
- }
-
- @Test
- public void testOnPreferenceChange_noChangeMax() {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, 0);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.getMax()).isEqualTo(100);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsControllerTest.java
new file mode 100644
index 0000000..6d412ee
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsControllerTest.java
@@ -0,0 +1,57 @@
+package com.android.settings.fuelgauge.batterysaver;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatterySaverScheduleRadioButtonsControllerTest {
+ private Context mContext;
+ private ContentResolver mResolver;
+ private BatterySaverScheduleRadioButtonsController mController;
+ private BatterySaverScheduleSeekBarController mSeekBarController;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mSeekBarController = new BatterySaverScheduleSeekBarController(mContext);
+ mController = new BatterySaverScheduleRadioButtonsController(
+ mContext, mSeekBarController);
+ mResolver = mContext.getContentResolver();
+ }
+
+ @Test
+ public void getDefaultKey_routine_returnsCorrectValue() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
+ assertThat(mController.getDefaultKey())
+ .isEqualTo(BatterySaverScheduleRadioButtonsController.KEY_ROUTINE);
+ }
+
+ @Test
+ public void getDefaultKey_automatic_returnsCorrectValue() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
+ assertThat(mController.getDefaultKey())
+ .isEqualTo(BatterySaverScheduleRadioButtonsController.KEY_PERCENTAGE);
+ }
+
+ @Test
+ public void getDefaultKey_none_returnsCorrectValue() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ assertThat(mController.getDefaultKey())
+ .isEqualTo(BatterySaverScheduleRadioButtonsController.KEY_NO_SCHEDULE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarControllerTest.java
new file mode 100644
index 0000000..8aac9d8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleSeekBarControllerTest.java
@@ -0,0 +1,65 @@
+package com.android.settings.fuelgauge.batterysaver;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatterySaverScheduleSeekBarControllerTest {
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private BatterySaverScheduleSeekBarController mController;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mController = new BatterySaverScheduleSeekBarController(mContext);
+ mResolver = mContext.getContentResolver();
+ }
+
+ @Test
+ public void onPreferenceChange_updatesSettingsGlobal() {
+ Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
+ mController.onPreferenceChange(mController.mSeekBarPreference, 10);
+ assertThat(Settings.Global.getInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1))
+ .isEqualTo(50);
+
+ assertThat(mController.mSeekBarPreference.getTitle()).isEqualTo("50%");
+ }
+
+ @Test
+ public void updateSeekBar_routineMode_hasCorrectProperties() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
+ mController.updateSeekBar();
+ assertThat(mController.mSeekBarPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void updateSeekBar_percentageMode_hasCorrectProperties() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 5);
+ mController.updateSeekBar();
+ assertThat(mController.mSeekBarPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateSeekBar_noneMode_hasCorrectProperties() {
+ Settings.Global.putInt(mResolver, Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ Settings.Global.putInt(mResolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ mController.updateSeekBar();
+ assertThat(mController.mSeekBarPreference.isVisible()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
index f1bb3ed..2db7f3f 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardFeatureProviderImplTest.java
@@ -49,13 +49,13 @@
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
- mImpl = new ContextualCardFeatureProviderImpl();
+ mImpl = new ContextualCardFeatureProviderImpl(mContext);
}
@Test
public void sendBroadcast_emptyAction_notSendBroadcast() {
final Intent intent = new Intent();
- mImpl.sendBroadcast(mContext, intent);
+ mImpl.sendBroadcast(intent);
verify(mContext, never()).sendBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -64,7 +64,7 @@
@Config(qualifiers = "mcc999")
public void sendBroadcast_hasAction_sendBroadcast() {
final Intent intent = new Intent();
- mImpl.sendBroadcast(mContext, intent);
+ mImpl.sendBroadcast(intent);
verify(mContext).sendBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -72,7 +72,7 @@
@Test
@Config(qualifiers = "mcc999")
public void logContextualCardDisplay_hasAction_sendBroadcast() {
- mImpl.logContextualCardDisplay(mContext, new ArrayList<>(), new ArrayList<>());
+ mImpl.logContextualCardDisplay(new ArrayList<>(), new ArrayList<>());
verify(mContext).sendBroadcastAsUser(any(Intent.class), any());
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index 101ca75..c62a6bb 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -145,7 +145,7 @@
cards.add(new ContextualCard.Builder()
.setName("test_wifi")
.setCardType(ContextualCard.CardType.SLICE)
- .setSliceUri(CustomSliceRegistry.WIFI_SLICE_URI)
+ .setSliceUri(CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI)
.build());
cards.add(new ContextualCard.Builder()
.setName("test_flashlight")
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index 2af84f9..c405ffc 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -42,13 +42,16 @@
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
@RunWith(RobolectricTestRunner.class)
public class ContextualCardManagerTest {
private static final String TEST_SLICE_URI = "context://test/test";
+ private static final String TEST_SLICE_NAME = "test_name";
@Mock
ContextualCardUpdateListener mListener;
@@ -61,7 +64,8 @@
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
final ContextualCardsFragment fragment = new ContextualCardsFragment();
- mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle());
+ mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle(),
+ null /* bundle */);
}
@Test
@@ -135,9 +139,74 @@
verify(manager, never()).onContextualCardUpdated(anyMap());
}
+ @Test
+ public void onFinishCardLoading_newLaunch_twoLoadedCards_shouldShowTwoCards() {
+ mManager.mStartTime = System.currentTimeMillis();
+ mManager.setListener(mListener);
+ final List<ContextualCard> cards = new ArrayList<>();
+ cards.add(buildContextualCard(TEST_SLICE_URI));
+ cards.add(buildContextualCard(TEST_SLICE_URI));
+
+ mManager.onFinishCardLoading(cards);
+
+ assertThat(mManager.mContextualCards).hasSize(2);
+ }
+
+ @Test
+ public void onFinishCardLoading_hasSavedCard_shouldOnlyShowSavedCard() {
+ mManager.setListener(mListener);
+ final List<String> savedCardNames = new ArrayList<>();
+ savedCardNames.add(TEST_SLICE_NAME);
+ mManager.mIsFirstLaunch = false;
+ mManager.mSavedCards = savedCardNames;
+ final ContextualCard newCard =
+ new ContextualCard.Builder()
+ .setName("test_name2")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(Uri.parse("content://test/test2"))
+ .build();
+ final List<ContextualCard> loadedCards = new ArrayList<>();
+ loadedCards.add(buildContextualCard(TEST_SLICE_URI));
+ loadedCards.add(newCard);
+
+ mManager.onFinishCardLoading(loadedCards);
+
+ final List<String> actualCards = mManager.mContextualCards.stream()
+ .map(ContextualCard::getName)
+ .collect(Collectors.toList());
+ final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
+ assertThat(actualCards).containsExactlyElementsIn(expectedCards);
+ }
+
+ @Test
+ public void onFinishCardLoading_reloadData_shouldOnlyShowOldCard() {
+ mManager.setListener(mListener);
+ mManager.mIsFirstLaunch = false;
+ //old card
+ mManager.mContextualCards.add(buildContextualCard(TEST_SLICE_URI));
+ final ContextualCard newCard =
+ new ContextualCard.Builder()
+ .setName("test_name2")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(Uri.parse("content://test/test2"))
+ .build();
+ final List<ContextualCard> loadedCards = new ArrayList<>();
+ loadedCards.add(buildContextualCard(TEST_SLICE_URI));
+ loadedCards.add(newCard);
+
+ mManager.onFinishCardLoading(loadedCards);
+
+ final List<String> actualCards = mManager.mContextualCards.stream()
+ .map(ContextualCard::getName)
+ .collect(Collectors.toList());
+ final List<String> expectedCards = Arrays.asList(TEST_SLICE_NAME);
+ assertThat(actualCards).containsExactlyElementsIn(expectedCards);
+ }
+
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
- .setName("test_name")
+ .setName(TEST_SLICE_NAME)
+ .setCardType(ContextualCard.CardType.SLICE)
.setSliceUri(Uri.parse(sliceUri))
.build();
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
index 8f36ea5..d4b67f5 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java
@@ -70,11 +70,12 @@
}
@Test
- public void getContextualCards_wifiSlice_shouldGetCorrectCategory() {
+ public void getContextualCards_wifiSlice_shouldGetImportantCategory() {
final ContextualCardList cards = mProvider.getContextualCards();
ContextualCard wifiCard = null;
for (ContextualCard card : cards.getCardList()) {
- if (card.getSliceUri().equals(CustomSliceRegistry.WIFI_SLICE_URI.toString())) {
+ if (card.getSliceUri().equals(
+ CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI.toString())) {
wifiCard = card;
}
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionControllerTest.java
deleted file mode 100644
index e4ca6c0..0000000
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/conditional/BatterySaverConditionControllerTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.homepage.contextualcards.conditional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.IntentFilter;
-import android.os.PowerManager;
-
-import com.android.settings.fuelgauge.BatterySaverReceiver;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
-import org.robolectric.shadows.ShadowPowerManager;
-
-@RunWith(RobolectricTestRunner.class)
-public class BatterySaverConditionControllerTest {
- @Mock
- private ConditionManager mConditionManager;
-
- private ShadowPowerManager mPowerManager;
- private Context mContext;
- private BatterySaverConditionController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- mPowerManager = Shadows.shadowOf(mContext.getSystemService(PowerManager.class));
- mController = new BatterySaverConditionController(mContext, mConditionManager);
- }
-
- @Test
- public void startMonitor_shouldRegisterReceiver() {
- mController.startMonitoringStateChange();
-
- verify(mContext).registerReceiver(any(BatterySaverReceiver.class), any(IntentFilter.class));
- }
-
- @Test
- public void stopMonitor_shouldUnregisterReceiver() {
- mController.startMonitoringStateChange();
- mController.stopMonitoringStateChange();
-
- verify(mContext).unregisterReceiver(any(BatterySaverReceiver.class));
- }
-
- @Test
- public void isDisplayable_PowerSaverOn_true() {
- mPowerManager.setIsPowerSaveMode(true);
-
- assertThat(mController.isDisplayable()).isTrue();
- }
-
- @Test
- public void isDisplayable_PowerSaverOff_false() {
- mPowerManager.setIsPowerSaveMode(false);
-
- assertThat(mController.isDisplayable()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
index 5bc3698..7e1a32c 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardControllerTest.java
@@ -91,8 +91,7 @@
cr.close();
assertThat(qryDismissed).isEqualTo(1);
- verify(mFeatureFactory.mContextualCardFeatureProvider).logContextualCardDismiss(
- mContext, card);
+ verify(mFeatureFactory.mContextualCardFeatureProvider).logContextualCardDismiss(card);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
index eff5d43..6379e44 100644
--- a/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/AppLocationPermissionPreferenceControllerTest.java
@@ -5,6 +5,10 @@
import android.content.Context;
import android.provider.Settings;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -21,11 +25,16 @@
@Mock
private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mController = new AppLocationPermissionPreferenceController(mContext);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
+ mController = new AppLocationPermissionPreferenceController(mContext, mLifecycle);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java b/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
index e380830..806e2ec 100644
--- a/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
@@ -84,30 +84,31 @@
}
@Test
- public void onResume_shouldSetActiveAndRegisterListener() {
- mEnabler.onResume();
+ public void onStart_shouldSetActiveAndRegisterListener() {
+ mEnabler.onStart();
verify(mContext).registerReceiver(eq(mEnabler.mReceiver),
eq(LocationEnabler.INTENT_FILTER_LOCATION_MODE_CHANGED));
}
@Test
- public void onResume_shouldRefreshLocationMode() {
- mEnabler.onResume();
+ public void onStart_shouldRefreshLocationMode() {
+ mEnabler.onStart();
verify(mEnabler).refreshLocationMode();
}
@Test
- public void onPause_shouldUnregisterListener() {
- mEnabler.onPause();
+ public void onStop_shouldUnregisterListener() {
+ mEnabler.onStart();
+ mEnabler.onStop();
verify(mContext).unregisterReceiver(mEnabler.mReceiver);
}
@Test
public void onReceive_shouldRefreshLocationMode() {
- mEnabler.onResume();
+ mEnabler.onStart();
reset(mListener);
mEnabler.mReceiver.onReceive(mContext, new Intent());
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java
deleted file mode 100644
index d4b4ac3..0000000
--- a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.settings.location;
-
-import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
-import android.text.TextUtils;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.location.RecentLocationApps;
-import com.android.settingslib.location.RecentLocationApps.Request;
-import com.android.settingslib.widget.apppreference.AppPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class RecentLocationRequestPreferenceControllerTest {
-
- @Mock
- private LocationSettings mFragment;
- @Mock
- private PreferenceCategory mCategory;
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private RecentLocationApps mRecentLocationApps;
- @Mock
- private Preference mSeeAllButton;
-
- private Context mContext;
- private RecentLocationRequestPreferenceController mController;
- private LifecycleOwner mLifecycleOwner;
- private Lifecycle mLifecycle;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- mLifecycleOwner = () -> mLifecycle;
- mLifecycle = new Lifecycle(mLifecycleOwner);
- mController = spy(new RecentLocationRequestPreferenceController(
- mContext, mFragment, mLifecycle, mRecentLocationApps));
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
- when(mScreen.findPreference(mController.KEY_SEE_ALL_BUTTON)).thenReturn(mSeeAllButton);
- final String key = mController.getPreferenceKey();
- when(mCategory.getKey()).thenReturn(key);
- when(mCategory.getContext()).thenReturn(mContext);
- }
-
- @Test
- public void onLocationModeChanged_LocationOn_shouldEnablePreference() {
- mController.displayPreference(mScreen);
-
- mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
-
- verify(mCategory).setEnabled(true);
- }
-
- @Test
- public void onLocationModeChanged_LocationOff_shouldDisablePreference() {
- mController.displayPreference(mScreen);
-
- mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
-
- verify(mCategory).setEnabled(false);
- }
-
- @Test
- public void updateState_noRecentRequest_shouldRemoveAllAndAddBanner() {
- doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted();
- mController.displayPreference(mScreen);
-
- mController.updateState(mCategory);
-
- verify(mCategory).removeAll();
- final String title = mContext.getString(R.string.location_no_recent_apps);
- verify(mCategory).addPreference(argThat(titleMatches(title)));
- }
-
- @Test
- public void updateState_hasRecentRequest_shouldRemoveAllAndAddInjectedSettings() {
- List<Request> requests = createMockRequests(2);
- doReturn(requests).when(mRecentLocationApps).getAppListSorted();
-
- mController.displayPreference(mScreen);
- mController.updateState(mCategory);
-
- verify(mCategory).removeAll();
- // Verifies two preferences are added in original order
- InOrder inOrder = Mockito.inOrder(mCategory);
- inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle0")));
- inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle1")));
- }
-
- @Test
- public void updateState_hasOverThreeRequests_shouldDisplaySeeAllButton() {
- List<Request> requests = createMockRequests(6);
- when(mRecentLocationApps.getAppListSorted()).thenReturn(requests);
-
- mController.displayPreference(mScreen);
- mController.updateState(mCategory);
-
- verify(mCategory).removeAll();
- // Verifies the first three preferences are added
- InOrder inOrder = Mockito.inOrder(mCategory);
- inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle0")));
- inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle1")));
- inOrder.verify(mCategory).addPreference(argThat(titleMatches("appTitle2")));
- verify(mCategory, never()).addPreference(argThat(titleMatches("appTitle3")));
- // Verifies the "See all" preference is visible
- verify(mSeeAllButton).setVisible(true);
- }
-
- @Test
- public void createAppPreference_shouldAddClickListener() {
- final Request request = mock(Request.class);
- final AppPreference preference = mock(AppPreference.class);
- doReturn(preference).when(mController).createAppPreference(any(Context.class));
-
- mController.createAppPreference(mContext, request);
-
- verify(preference).setOnPreferenceClickListener(
- any(RecentLocationRequestPreferenceController.PackageEntryClickedListener.class));
- }
-
- @Test
- public void onPreferenceClick_shouldLaunchAppDetails() {
- final Context context = mock(Context.class);
- when(mFragment.getContext()).thenReturn(context);
-
- final List<RecentLocationApps.Request> requests = new ArrayList<>();
- final Request request = mock(Request.class);
- requests.add(request);
- doReturn(requests).when(mRecentLocationApps).getAppListSorted();
- final AppPreference preference = new AppPreference(mContext);
- doReturn(preference).when(mController).createAppPreference(any(Context.class));
- mController.displayPreference(mScreen);
- mController.updateState(mCategory);
-
- final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
-
- preference.performClick();
-
- verify(context).startActivity(intent.capture());
-
- assertThat(intent.getValue().getStringExtra(EXTRA_SHOW_FRAGMENT))
- .isEqualTo(AppInfoDashboardFragment.class.getName());
- }
-
- private static ArgumentMatcher<Preference> titleMatches(String expected) {
- return preference -> TextUtils.equals(expected, preference.getTitle());
- }
-
- private List<RecentLocationApps.Request> createMockRequests(int count) {
- List<RecentLocationApps.Request> requests = new ArrayList<>();
- for (int i = 0; i < count; i++) {
- // Add mock requests
- Request req = mock(Request.class, "request" + i);
- requests.add(req);
- // Map mock AppPreferences with mock requests
- String title = "appTitle" + i;
- AppPreference appPreference = mock(AppPreference.class, "AppPreference" + i);
- doReturn(title).when(appPreference).getTitle();
- doReturn(appPreference)
- .when(mController).createAppPreference(any(Context.class), eq(req));
- }
- return requests;
- }
-}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceControllerTest.java
deleted file mode 100644
index 7411afe..0000000
--- a/tests/robotests/src/com/android/settings/location/RecentLocationRequestSeeAllPreferenceControllerTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 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 org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.provider.Settings.Secure;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.location.RecentLocationApps;
-import com.android.settingslib.location.RecentLocationApps.Request;
-import com.android.settingslib.widget.apppreference.AppPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.Collections;
-
-/** Unit tests for {@link RecentLocationRequestSeeAllPreferenceController} */
-@RunWith(RobolectricTestRunner.class)
-public class RecentLocationRequestSeeAllPreferenceControllerTest {
-
- @Mock
- RecentLocationRequestSeeAllFragment mFragment;
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private PreferenceCategory mCategory;
- @Mock
- private RecentLocationApps mRecentLocationApps;
-
- private Context mContext;
- private LifecycleOwner mLifecycleOwner;
- private Lifecycle mLifecycle;
- private RecentLocationRequestSeeAllPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- mLifecycleOwner = () -> mLifecycle;
- mLifecycle = new Lifecycle(mLifecycleOwner);
- mController = spy(
- new RecentLocationRequestSeeAllPreferenceController(
- mContext, mLifecycle, mFragment, mRecentLocationApps));
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
- final String key = mController.getPreferenceKey();
- when(mCategory.getKey()).thenReturn(key);
- when(mCategory.getContext()).thenReturn(mContext);
- }
-
- @Test
- public void onLocationModeChanged_locationOn_shouldEnablePreference() {
- mController.displayPreference(mScreen);
-
- mController.onLocationModeChanged(Secure.LOCATION_MODE_HIGH_ACCURACY, false);
-
- verify(mCategory).setEnabled(true);
- }
-
- @Test
- public void onLocationModeChanged_locationOff_shouldDisablePreference() {
- mController.displayPreference(mScreen);
-
- mController.onLocationModeChanged(Secure.LOCATION_MODE_OFF, false);
-
- verify(mCategory).setEnabled(false);
- }
-
- @Test
- public void updateState_shouldRemoveAll() {
- doReturn(Collections.EMPTY_LIST).when(mRecentLocationApps).getAppListSorted();
-
- mController.displayPreference(mScreen);
- mController.updateState(mCategory);
-
- verify(mCategory).removeAll();
- }
-
- @Test
- public void updateState_hasRecentLocationRequest_shouldAddPreference() {
- Request request = mock(Request.class);
- AppPreference appPreference = mock(AppPreference.class);
- doReturn(appPreference)
- .when(mController).createAppPreference(any(Context.class), eq(request));
- when(mRecentLocationApps.getAppListSorted())
- .thenReturn(new ArrayList<>(Collections.singletonList(request)));
-
- mController.displayPreference(mScreen);
- mController.updateState(mCategory);
-
- verify(mCategory).removeAll();
- verify(mCategory).addPreference(appPreference);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java b/tests/robotests/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java
new file mode 100644
index 0000000..b4ebcc4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/MultiNetworkHeaderControllerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.wifi.WifiConnectionPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class MultiNetworkHeaderControllerTest {
+ private static final String KEY_HEADER = "multi_network_header";
+
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private PreferenceCategory mPreferenceCategory;
+ @Mock
+ private WifiConnectionPreferenceController mWifiController;
+ @Mock
+ private SubscriptionsPreferenceController mSubscriptionsController;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+
+ private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
+ private MultiNetworkHeaderController mHeaderController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mPreferenceScreen.findPreference(eq(KEY_HEADER))).thenReturn(mPreferenceCategory);
+
+ mHeaderController = spy(new MultiNetworkHeaderController(mContext, KEY_HEADER));
+ doReturn(mWifiController).when(mHeaderController).createWifiController(mLifecycle);
+ doReturn(mSubscriptionsController).when(mHeaderController).createSubscriptionsController(
+ mLifecycle);
+ }
+
+ @Test
+ public void isAvailable_beforeInitIsCalled_notAvailable() {
+ assertThat(mHeaderController.isAvailable()).isFalse();
+ }
+
+ // When calling displayPreference, the header itself should only be visible if the
+ // subscriptions controller says it is available. This is a helper for test cases of this logic.
+ private void displayPreferenceTest(boolean wifiAvailable, boolean subscriptionsAvailable,
+ boolean setVisibleExpectedValue) {
+ when(mWifiController.isAvailable()).thenReturn(wifiAvailable);
+ when(mSubscriptionsController.isAvailable()).thenReturn(subscriptionsAvailable);
+
+ mHeaderController.init(mLifecycle);
+ mHeaderController.displayPreference(mPreferenceScreen);
+ verify(mPreferenceCategory, never()).setVisible(eq(!setVisibleExpectedValue));
+ verify(mPreferenceCategory, atLeastOnce()).setVisible(eq(setVisibleExpectedValue));
+ }
+
+ @Test
+ public void displayPreference_bothNotAvailable_categoryIsNotVisible() {
+ displayPreferenceTest(false, false, false);
+ }
+
+ @Test
+ public void displayPreference_wifiAvailableButNotSubscriptions_categoryIsNotVisible() {
+ displayPreferenceTest(true, false, false);
+ }
+
+ @Test
+ public void displayPreference_subscriptionsAvailableButNotWifi_categoryIsVisible() {
+ displayPreferenceTest(false, true, true);
+ }
+
+ @Test
+ public void displayPreference_bothAvailable_categoryIsVisible() {
+ displayPreferenceTest(true, true, true);
+ }
+
+ @Test
+ public void onChildUpdated_subscriptionsBecameAvailable_categoryIsVisible() {
+ when(mSubscriptionsController.isAvailable()).thenReturn(false);
+ mHeaderController.init(mLifecycle);
+ mHeaderController.displayPreference(mPreferenceScreen);
+
+ when(mSubscriptionsController.isAvailable()).thenReturn(true);
+ mHeaderController.onChildrenUpdated();
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+
+ verify(mPreferenceCategory, atLeastOnce()).setVisible(captor.capture());
+ List<Boolean> values = captor.getAllValues();
+ assertThat(values.get(values.size()-1)).isEqualTo(Boolean.TRUE);
+ }
+
+ @Test
+ public void onChildUpdated_subscriptionsBecameUnavailable_categoryIsNotVisible() {
+ when(mSubscriptionsController.isAvailable()).thenReturn(true);
+ mHeaderController.init(mLifecycle);
+ mHeaderController.displayPreference(mPreferenceScreen);
+
+ when(mSubscriptionsController.isAvailable()).thenReturn(false);
+ mHeaderController.onChildrenUpdated();
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+
+ verify(mPreferenceCategory, atLeastOnce()).setVisible(captor.capture());
+ List<Boolean> values = captor.getAllValues();
+ assertThat(values.get(values.size()-1)).isEqualTo(Boolean.FALSE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
new file mode 100644
index 0000000..016a885
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class SubscriptionsPreferenceControllerTest {
+ private static final String KEY = "preference_group";
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private PreferenceCategory mPreferenceCategory;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+
+ private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
+ private SubscriptionsPreferenceController mController;
+ private int mOnChildUpdatedCount;
+ private SubscriptionsPreferenceController.UpdateListener mUpdateListener;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory);
+ when(mPreferenceCategory.getContext()).thenReturn(mContext);
+ mOnChildUpdatedCount = 0;
+ mUpdateListener = () -> mOnChildUpdatedCount++;
+
+ mController = new SubscriptionsPreferenceController(mContext, mLifecycle, mUpdateListener,
+ KEY, 5);
+ }
+
+ @Test
+ public void isAvailable_oneSubscription_availableFalse() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(
+ Arrays.asList(mock(SubscriptionInfo.class)));
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_twoSubscriptions_availableTrue() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(
+ Arrays.asList(mock(SubscriptionInfo.class), mock(SubscriptionInfo.class)));
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_fiveSubscriptions_availableTrue() {
+ final ArrayList<SubscriptionInfo> subs = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ subs.add(mock(SubscriptionInfo.class));
+ }
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(subs);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_airplaneModeOn_availableFalse() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(
+ Arrays.asList(mock(SubscriptionInfo.class), mock(SubscriptionInfo.class)));
+ assertThat(mController.isAvailable()).isTrue();
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void onAirplaneModeChanged_airplaneModeTurnedOn_eventFired() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(
+ Arrays.asList(mock(SubscriptionInfo.class), mock(SubscriptionInfo.class)));
+ mController.onResume();
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isTrue();
+
+ final int updateCountBeforeModeChange = mOnChildUpdatedCount;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ mController.onAirplaneModeChanged(true);
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
+ }
+
+ @Test
+ public void onAirplaneModeChanged_airplaneModeTurnedOff_eventFired() {
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(
+ Arrays.asList(mock(SubscriptionInfo.class), mock(SubscriptionInfo.class)));
+ mController.onResume();
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isFalse();
+
+ final int updateCountBeforeModeChange = mOnChildUpdatedCount;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
+ mController.onAirplaneModeChanged(false);
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeModeChange + 1);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_countBecameTwo_eventFired() {
+ final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+ mController.onResume();
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isFalse();
+
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mController.onSubscriptionsChanged();
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_countBecameOne_eventFired() {
+ final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mController.onResume();
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isTrue();
+
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+ mController.onSubscriptionsChanged();
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+ }
+
+
+ @Test
+ public void onSubscriptionsChanged_subscriptionReplaced_preferencesChanged() {
+ final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo sub2 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo sub3 = mock(SubscriptionInfo.class);
+ when(sub1.getDisplayName()).thenReturn("sub1");
+ when(sub2.getDisplayName()).thenReturn("sub2");
+ when(sub3.getDisplayName()).thenReturn("sub3");
+ when(sub1.getSubscriptionId()).thenReturn(1);
+ when(sub2.getSubscriptionId()).thenReturn(2);
+ when(sub3.getSubscriptionId()).thenReturn(3);
+
+ // Start out with only sub1 and sub2.
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mController.onResume();
+ mController.displayPreference(mScreen);
+ final ArgumentCaptor<Preference> captor = ArgumentCaptor.forClass(Preference.class);
+ verify(mPreferenceCategory, times(2)).addPreference(captor.capture());
+ assertThat(captor.getAllValues().size()).isEqualTo(2);
+ assertThat(captor.getAllValues().get(0).getTitle()).isEqualTo("sub1");
+ assertThat(captor.getAllValues().get(1).getTitle()).isEqualTo("sub2");
+
+ // Now replace sub2 with sub3, and make sure the old preference was removed and the new
+ // preference was added.
+ final int updateCountBeforeSubscriptionChange = mOnChildUpdatedCount;
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub3));
+ mController.onSubscriptionsChanged();
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mOnChildUpdatedCount).isEqualTo(updateCountBeforeSubscriptionChange + 1);
+
+ verify(mPreferenceCategory).removePreference(captor.capture());
+ assertThat(captor.getValue().getTitle()).isEqualTo("sub2");
+ verify(mPreferenceCategory, times(3)).addPreference(captor.capture());
+ assertThat(captor.getValue().getTitle()).isEqualTo("sub3");
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java
new file mode 100644
index 0000000..7037318
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/WifiConnectionPreferenceControllerTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import com.android.settings.wifi.WifiConnectionPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.AccessPointPreference;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTrackerFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiConnectionPreferenceControllerTest {
+ private static final String KEY = "wifi_connection";
+
+ @Mock
+ WifiTracker mWifiTracker;
+ @Mock
+ PreferenceScreen mScreen;
+ @Mock
+ PreferenceCategory mPreferenceCategory;
+
+ private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
+ private WifiConnectionPreferenceController mController;
+ private int mOnChildUpdatedCount;
+ private WifiConnectionPreferenceController.UpdateListener mUpdateListener;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
+ when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory);
+ when(mScreen.getContext()).thenReturn(mContext);
+ mUpdateListener = () -> mOnChildUpdatedCount++;
+
+ mController = new WifiConnectionPreferenceController(mContext, mLifecycle, mUpdateListener,
+ KEY, 0, 0);
+ }
+
+ @Test
+ public void isAvailable_noWiFiConnection_availableIsFalse() {
+ when(mWifiTracker.isConnected()).thenReturn(false);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void displayPreference_noWiFiConnection_noPreferenceAdded() {
+ when(mWifiTracker.isConnected()).thenReturn(false);
+ when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>());
+ mController.displayPreference(mScreen);
+ verify(mPreferenceCategory, never()).addPreference(any());
+ }
+
+ @Test
+ public void displayPreference_hasWiFiConnection_preferenceAdded() {
+ when(mWifiTracker.isConnected()).thenReturn(true);
+ final AccessPoint accessPoint = mock(AccessPoint.class);
+ when(accessPoint.isActive()).thenReturn(true);
+ when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint));
+ mController.displayPreference(mScreen);
+ verify(mPreferenceCategory).addPreference(any(AccessPointPreference.class));
+ }
+
+ @Test
+ public void onConnectedChanged_wifiBecameDisconnected_preferenceRemoved() {
+ when(mWifiTracker.isConnected()).thenReturn(true);
+ final AccessPoint accessPoint = mock(AccessPoint.class);
+
+ when(accessPoint.isActive()).thenReturn(true);
+ when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint));
+ mController.displayPreference(mScreen);
+ final ArgumentCaptor<AccessPointPreference> captor = ArgumentCaptor.forClass(
+ AccessPointPreference.class);
+ verify(mPreferenceCategory).addPreference(captor.capture());
+ final AccessPointPreference pref = captor.getValue();
+
+ when(mWifiTracker.isConnected()).thenReturn(false);
+ when(mWifiTracker.getAccessPoints()).thenReturn(new ArrayList<>());
+ final int onUpdatedCountBefore = mOnChildUpdatedCount;
+ mController.onConnectedChanged();
+ verify(mPreferenceCategory).removePreference(pref);
+ assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1);
+ }
+
+
+ @Test
+ public void onAccessPointsChanged_wifiBecameConnectedToDifferentAP_preferenceReplaced() {
+ when(mWifiTracker.isConnected()).thenReturn(true);
+ final AccessPoint accessPoint1 = mock(AccessPoint.class);
+
+ when(accessPoint1.isActive()).thenReturn(true);
+ when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1));
+ mController.displayPreference(mScreen);
+ final ArgumentCaptor<AccessPointPreference> captor = ArgumentCaptor.forClass(
+ AccessPointPreference.class);
+
+
+ final AccessPoint accessPoint2 = mock(AccessPoint.class);
+ when(accessPoint1.isActive()).thenReturn(false);
+ when(accessPoint2.isActive()).thenReturn(true);
+ when(mWifiTracker.getAccessPoints()).thenReturn(Arrays.asList(accessPoint1, accessPoint2));
+ final int onUpdatedCountBefore = mOnChildUpdatedCount;
+ mController.onAccessPointsChanged();
+
+ verify(mPreferenceCategory, times(2)).addPreference(captor.capture());
+ final AccessPointPreference pref1 = captor.getAllValues().get(0);
+ final AccessPointPreference pref2 = captor.getAllValues().get(1);
+ assertThat(pref1.getAccessPoint()).isEqualTo(accessPoint1);
+ assertThat(pref2.getAccessPoint()).isEqualTo(accessPoint2);
+ verify(mPreferenceCategory).removePreference(eq(pref1));
+ assertThat(mOnChildUpdatedCount).isEqualTo(onUpdatedCountBefore + 1);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/FakePanelContent.java b/tests/robotests/src/com/android/settings/panel/FakePanelContent.java
index 60f0d5d..1d79952 100644
--- a/tests/robotests/src/com/android/settings/panel/FakePanelContent.java
+++ b/tests/robotests/src/com/android/settings/panel/FakePanelContent.java
@@ -29,7 +29,7 @@
*/
public class FakePanelContent implements PanelContent {
- public static final String FAKE_KEY = "fake_key";
+ public static final String FAKE_ACTION = "fake_action";
public static final CharSequence TITLE = "title";
diff --git a/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java b/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java
index afd0bec..2a62b54 100644
--- a/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java
+++ b/tests/robotests/src/com/android/settings/panel/FakeSettingsPanelActivity.java
@@ -27,8 +27,7 @@
@Override
public Intent getIntent() {
- final Intent intent = new Intent();
- intent.putExtra(SettingsPanelActivity.EXTRA_PANEL_TYPE, FakePanelContent.FAKE_KEY);
+ final Intent intent = new Intent(FakePanelContent.FAKE_ACTION);
return intent;
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
index 754c937..99d5d6c 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
@@ -20,6 +20,7 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.provider.Settings;
import org.junit.Before;
import org.junit.Test;
@@ -43,8 +44,16 @@
@Test
public void getPanel_internetConnectivityKey_returnsCorrectPanel() {
final PanelContent panel = mProvider.getPanel(mContext,
- SettingsPanelActivity.PANEL_TYPE_WIFI);
+ Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
assertThat(panel).isInstanceOf(InternetConnectivityPanel.class);
}
+
+ @Test
+ public void getPanel_volume_returnsCorrectPanel() {
+ final PanelContent panel = mProvider.getPanel(mContext,
+ Settings.Panel.ACTION_VOLUME);
+
+ assertThat(panel).isInstanceOf(VolumePanel.class);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index c11d7eb..649a1ba 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -164,23 +164,6 @@
assertThat(findFragment(mActivity).mChosenPattern).isNull();
}
- @Test
- public void skipButton_shouldNotBeVisible_duringFingerprintFlow() {
- final Intent intent =
- SetupChooseLockPattern.modifyIntentForSetup(
- application,
- new IntentBuilder(application)
- .setUserId(UserHandle.myUserId())
- .setForFingerprint(true)
- .build());
-
- mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get();
- Button skipButton = mActivity.findViewById(R.id.skip_button);
-
- assertThat(skipButton).isNotNull();
- assertThat(skipButton.getVisibility()).isEqualTo(View.GONE);
- }
-
private ChooseLockPatternFragment findFragment(FragmentActivity activity) {
return (ChooseLockPatternFragment)
activity.getSupportFragmentManager().findFragmentById(R.id.main_content);
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index b129267..7eae3e4 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -55,7 +55,7 @@
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
-import com.android.settings.wifi.WifiSlice;
+import com.android.settings.wifi.slice.WifiSlice;
import com.android.settingslib.wifi.WifiTracker;
import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
new file mode 100644
index 0000000..364fb60
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.slices;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SlicePreferenceControllerTest {
+ private static final String KEY = "slice_preference_key";
+
+ @Mock
+ private LiveData<Slice> mLiveData;
+ private Context mContext;
+ private SlicePreferenceController mController;
+ private Uri mUri;
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ mController = new SlicePreferenceController(mContext, KEY);
+ mController.mLiveData = mLiveData;
+ mUri = Uri.EMPTY;
+ }
+
+ @Test
+ public void isAvailable_uriNull_returnFalse() {
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_uriNotNull_returnTrue() {
+ mController.setSliceUri(mUri);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void onStart_registerObserver() {
+ mController.onStart();
+ verify(mLiveData).observeForever(mController);
+ }
+
+ @Test
+ public void onStop_unregisterObserver() {
+ mController.onStop();
+ verify(mLiveData).removeObserver(mController);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index e0b8646..bf86898 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -24,6 +24,7 @@
import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
+import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
@@ -66,6 +67,7 @@
public final AccountFeatureProvider mAccountFeatureProvider;
public final ContextualCardFeatureProvider mContextualCardFeatureProvider;
public final FaceFeatureProvider mFaceFeatureProvider;
+ public final BluetoothFeatureProvider mBluetoothFeatureProvider;
public PanelFeatureProvider panelFeatureProvider;
public SlicesFeatureProvider slicesFeatureProvider;
@@ -111,6 +113,7 @@
mContextualCardFeatureProvider = mock(ContextualCardFeatureProvider.class);
panelFeatureProvider = mock(PanelFeatureProvider.class);
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
+ mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
}
@Override
@@ -198,8 +201,7 @@
return panelFeatureProvider;
}
- @Override
- public ContextualCardFeatureProvider getContextualCardFeatureProvider() {
+ public ContextualCardFeatureProvider getContextualCardFeatureProvider(Context context) {
return mContextualCardFeatureProvider;
}
@@ -207,4 +209,9 @@
public FaceFeatureProvider getFaceFeatureProvider() {
return mFaceFeatureProvider;
}
+
+ @Override
+ public BluetoothFeatureProvider getBluetoothFeatureProvider(Context context) {
+ return mBluetoothFeatureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogActivityTest.java
index 48f8ec0..107da79 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogActivityTest.java
@@ -18,9 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+
import androidx.appcompat.app.AlertDialog;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTrackerFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,6 +38,10 @@
@Test
public void LaunchActivity_shouldShowNetworkRequestDialog() {
+ // Mocks fake WifiTracker, in case of exception in NetworkRequestDialogFragment.onResume().
+ WifiTracker wifiTracker = mock(WifiTracker.class);
+ WifiTrackerFactory.setTestingWifiTracker(wifiTracker);
+
Robolectric.setupActivity(NetworkRequestDialogActivity.class);
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index 343d170..e64fae7 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -51,6 +51,10 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+
+import com.android.settingslib.wifi.WifiTracker;
+import com.android.settingslib.wifi.WifiTrackerFactory;
+
import org.robolectric.shadows.ShadowLooper;
@RunWith(RobolectricTestRunner.class)
@@ -58,16 +62,21 @@
public class NetworkRequestDialogFragmentTest {
private static final String KEY_SSID = "key_ssid";
+ private static final String KEY_SECURITY = "key_security";
private FragmentActivity mActivity;
private NetworkRequestDialogFragment networkRequestDialogFragment;
private Context mContext;
+ private WifiTracker mWifiTracker;
@Before
public void setUp() {
mActivity = Robolectric.setupActivity(FragmentActivity.class);
networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
mContext = spy(RuntimeEnvironment.application);
+
+ mWifiTracker = mock(WifiTracker.class);
+ WifiTrackerFactory.setTestingWifiTracker(mWifiTracker);
}
@Test
@@ -140,71 +149,47 @@
}
@Test
- public void updateAccessPointList_onUserSelectionConnectSuccess_updateCorrectly() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 3");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
-
+ public void updateAccessPointList_onUserSelectionConnectSuccess_shouldCloseTheDialog() {
+ List<AccessPoint> accessPointList = createAccessPointList();
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog.isShowing()).isTrue();
// Test if config would update list.
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Test AP 3";
networkRequestDialogFragment.onUserSelectionConnectSuccess(config);
- AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
- verify(accessPointList, times(1)).set(2, verifyAccessPoint);
+ assertThat(alertDialog.isShowing()).isFalse();
}
@Test
- public void updateAccessPointList_onUserSelectionConnectFailure_updateCorrectly() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 3");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
+ public void updateAccessPointList_onUserSelectionConnectFailure_shouldCallTimeoutDialog() {
+ FakeNetworkRequestDialogFragment fakeFragment = new FakeNetworkRequestDialogFragment();
+ FakeNetworkRequestDialogFragment spyFakeFragment = spy(fakeFragment);
+ List<AccessPoint> accessPointList = createAccessPointList();
+ when(spyFakeFragment.getAccessPointList()).thenReturn(accessPointList);
+ spyFakeFragment.show(mActivity.getSupportFragmentManager(), null);
- when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
- networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
+ AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+ assertThat(alertDialog.isShowing()).isTrue();
// Test if config would update list.
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Test AP 3";
- networkRequestDialogFragment.onUserSelectionConnectFailure(config);
+ fakeFragment.onUserSelectionConnectFailure(config);
- AccessPoint verifyAccessPoint = new AccessPoint(mContext, config);
- verify(accessPointList, times(1)).set(2, verifyAccessPoint);
+ assertThat(fakeFragment.bCalledStopAndPop).isTrue();
}
@Test
- public void onUserSelectionCallbackRegistration_shouldCallSelect() {
- List<AccessPoint> accessPointList = spy(new ArrayList<>());
- Bundle bundle = new Bundle();
- bundle.putString(KEY_SSID, "Test AP 1");
- accessPointList.add(new AccessPoint(mContext, bundle));
- bundle.putString(KEY_SSID, "Test AP 2");
- accessPointList.add(new AccessPoint(mContext, bundle));
-
- bundle.putString(KEY_SSID, "Test AP 3");
- AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
+ public void onUserSelectionCallbackRegistration_onClick_shouldCallSelect() {
+ // Assert.
+ final int indexClickItem = 3;
+ List<AccessPoint> accessPointList = createAccessPointList();
+ AccessPoint clickedAccessPoint = accessPointList.get(indexClickItem);
clickedAccessPoint.generateOpenNetworkConfig();
- accessPointList.add(clickedAccessPoint);
-
- bundle.putString(KEY_SSID, "Test AP 4");
- accessPointList.add(new AccessPoint(mContext, bundle));
when(networkRequestDialogFragment.getAccessPointList()).thenReturn(accessPointList);
NetworkRequestUserSelectionCallback selectionCallback = mock(
@@ -212,40 +197,66 @@
AlertDialog dialog = mock(AlertDialog.class);
networkRequestDialogFragment.onUserSelectionCallbackRegistration(selectionCallback);
- networkRequestDialogFragment.onClick(dialog, 2);
+ // Act.
+ networkRequestDialogFragment.onClick(dialog, indexClickItem);
+ // Check.
verify(selectionCallback, times(1)).select(clickedAccessPoint.getConfig());
}
@Test
public void onMatch_shouldUpdatedList() {
- // Prepares WifiManager.
+ // Assert.
when(networkRequestDialogFragment.getContext()).thenReturn(mContext);
Context applicationContext = spy(RuntimeEnvironment.application.getApplicationContext());
when(mContext.getApplicationContext()).thenReturn(applicationContext);
WifiManager wifiManager = mock(WifiManager.class);
when(applicationContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(wifiManager);
+ networkRequestDialogFragment.onResume();
- List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
- WifiConfiguration config = new WifiConfiguration();
+ List<AccessPoint> accessPointList = createAccessPointList();
+ when(mWifiTracker.getAccessPoints()).thenReturn(accessPointList);
+
final String SSID_AP1 = "Test AP 1";
- config.SSID = SSID_AP1;
- wifiConfigurationList.add(config);
- config = new WifiConfiguration();
final String SSID_AP2 = "Test AP 2";
- config.SSID = SSID_AP2;
- wifiConfigurationList.add(config);
-
- // Prepares callback converted data.
List<ScanResult> scanResults = new ArrayList<>();
- when(wifiManager.getAllMatchingWifiConfigs(scanResults)).thenReturn(wifiConfigurationList);
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = SSID_AP1;
+ scanResult.capabilities = "WEP";
+ scanResults.add(scanResult);
+ scanResult = new ScanResult();
+ scanResult.SSID = SSID_AP2;
+ scanResult.capabilities = "WEP";
+ scanResults.add(scanResult);
+ // Act.
networkRequestDialogFragment.onMatch(scanResults);
- List<AccessPoint> accessPointList = networkRequestDialogFragment.getAccessPointList();
- assertThat(accessPointList).isNotEmpty();
- assertThat(accessPointList.size()).isEqualTo(2);
- assertThat(accessPointList.get(0).getSsid()).isEqualTo(SSID_AP1);
- assertThat(accessPointList.get(1).getSsid()).isEqualTo(SSID_AP2);
+ // Check.
+ List<AccessPoint> returnList = networkRequestDialogFragment.getAccessPointList();
+ assertThat(returnList).isNotEmpty();
+ assertThat(returnList.size()).isEqualTo(2);
+ assertThat(returnList.get(0).getSsid()).isEqualTo(SSID_AP1);
+ assertThat(returnList.get(1).getSsid()).isEqualTo(SSID_AP2);
+ }
+
+ private List<AccessPoint> createAccessPointList() {
+ List<AccessPoint> accessPointList = spy(new ArrayList<>());
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_SSID, "Test AP 1");
+ bundle.putInt(KEY_SECURITY, 1);
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 2");
+ bundle.putInt(KEY_SECURITY, 1);
+ accessPointList.add(new AccessPoint(mContext, bundle));
+ bundle.putString(KEY_SSID, "Test AP 3");
+ bundle.putInt(KEY_SECURITY, 2);
+ AccessPoint clickedAccessPoint = new AccessPoint(mContext, bundle);
+ accessPointList.add(clickedAccessPoint);
+ bundle.putString(KEY_SSID, "Test AP 4");
+ bundle.putInt(KEY_SECURITY, 0);
+ accessPointList.add(new AccessPoint(mContext, bundle));
+
+ return accessPointList;
}
}
diff --git a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
index e32ac6b..0ef0273 100644
--- a/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/qrcode/QrCameraTest.java
@@ -22,9 +22,11 @@
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.util.Size;
-import android.view.SurfaceHolder;
import com.android.settings.R;
@@ -48,7 +50,7 @@
public class QrCameraTest {
@Mock
- private SurfaceHolder mSurfaceHolder;
+ private SurfaceTexture mSurfaceTexture;
private QrCamera mCamera;
private Context mContext;
@@ -78,6 +80,11 @@
mCameraCallbacked = true;
mCallbackSignal.countDown();
}
+
+ @Override
+ public void setTransform(Matrix transform) {
+ // Do nothing
+ }
}
private ScannerTestCallback mScannerCallback;
@@ -87,7 +94,7 @@
mContext = RuntimeEnvironment.application;
mScannerCallback = new ScannerTestCallback();
mCamera = new QrCamera(mContext, mScannerCallback);
- mSurfaceHolder = mock(SurfaceHolder.class);
+ mSurfaceTexture = mock(SurfaceTexture.class);
mQrCode = "";
mCameraCallbacked = false;
mCallbackSignal = null;
@@ -96,7 +103,7 @@
@Test
public void testCamera_Init_Callback() throws InterruptedException {
mCallbackSignal = new CountDownLatch(1);
- mCamera.start(mSurfaceHolder);
+ mCamera.start(mSurfaceTexture);
mCallbackSignal.await(5000, TimeUnit.MILLISECONDS);
assertThat(mCameraCallbacked).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
new file mode 100644
index 0000000..bf5fba8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiSliceTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.slice;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SliceTester;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class ContextualWifiSliceTest {
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private WifiManager mWifiManager;
+ private ContextualWifiSlice mWifiSlice;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ mResolver = mock(ContentResolver.class);
+ doReturn(mResolver).when(mContext).getContentResolver();
+ mWifiManager = mContext.getSystemService(WifiManager.class);
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mWifiManager.setWifiEnabled(true);
+
+ mWifiSlice = new ContextualWifiSlice(mContext);
+ }
+
+ @Test
+ public void getWifiSlice_hasActiveConnection_shouldReturnNull() {
+ final WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "123";
+ mWifiManager.connect(config, null /* listener */);
+
+ final Slice wifiSlice = mWifiSlice.getSlice();
+
+ assertThat(wifiSlice).isNull();
+ }
+
+ @Test
+ public void getWifiSlice_previousDisplayed_hasActiveConnection_shouldHaveTitleAndToggle() {
+ mWifiSlice.mPreviouslyDisplayed = true;
+ final WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "123";
+ mWifiManager.connect(config, null /* listener */);
+
+ final Slice wifiSlice = mWifiSlice.getSlice();
+ final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice);
+
+ final List<SliceAction> toggles = metadata.getToggles();
+ assertThat(toggles).hasSize(1);
+
+ final SliceAction primaryAction = metadata.getPrimaryAction();
+ final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
+ R.drawable.ic_settings_wireless);
+ assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
+
+ final List<SliceItem> sliceItems = wifiSlice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
similarity index 96%
rename from tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
rename to tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index 2d4dd04..3c78749 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -12,16 +12,15 @@
* 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;
+package com.android.settings.wifi.slice;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI;
-import static com.android.settings.wifi.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
+import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
import static com.google.common.truth.Truth.assertThat;
@@ -29,7 +28,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;