Merge "Remove EXTRA_USER_HANDLE from startSpaActivityForApp"
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index 17fd4d5..c824a6a 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -329,6 +329,24 @@
<string name="fingerprint_last_delete_message" product="tablet">You won\'t be able to use your fingerprint to unlock your tablet or verify it\'s you in apps.</string>
<!-- Message shown in a dialog which asks the user to confirm when the last fingerprint gets deleted by them. [CHAR LIMIT=NONE]-->
<string name="fingerprint_last_delete_message" product="device">You won\'t be able to use your fingerprint to unlock your device or verify it\'s you in apps.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_unlock_title" product="default">You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_unlock_title" product="tablet">You can unlock your tablet using your fingerprint. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
+ <string name="fingerprint_unlock_title" product="device">You can unlock your device using your fingerprint. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+ <string name="face_unlock_title" product="default">You can unlock your phone using your face. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+ <string name="face_unlock_title" product="tablet">You can unlock your tablet using your face. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
+ <string name="face_unlock_title" product="device">You can unlock your device using your face. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+ <string name="biometrics_unlock_title" product="default">You can unlock your phone using your face or fingerprint. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+ <string name="biometrics_unlock_title" product="tablet">You can unlock your tablet using your face or fingerprint. For security, this option requires a backup screen lock.</string>
+ <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
+ <string name="biometrics_unlock_title" product="device">You can unlock your device using your face or fingerprint. For security, this option requires a backup screen lock.</string>
<!-- Title of the preferences item to control encryption -->
<string name="encrypt_title" product="tablet">Encrypt tablet</string>
<!-- Title of the preferences item to control encryption -->
diff --git a/res/layout/preference_spinner.xml b/res/layout/preference_spinner.xml
new file mode 100644
index 0000000..4129303
--- /dev/null
+++ b/res/layout/preference_spinner.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<Spinner
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginTop="8dp"
+ android:theme="@style/Widget.PopupWindow.Settings" />
diff --git a/res/layout/preference_tab.xml b/res/layout/preference_tab.xml
deleted file mode 100644
index f9a7881..0000000
--- a/res/layout/preference_tab.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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:theme="@style/Theme.TabTheme"
- android:id="@+id/tab_container"
- android:clipToPadding="true"
- android:clipChildren="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <com.google.android.material.tabs.TabLayout
- android:id="@+id/tabs"
- style="@style/SettingsLibTabsStyle" />
-
- <androidx.viewpager2.widget.ViewPager2
- android:id="@+id/view_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</LinearLayout>
diff --git a/res/layout/preference_widget_tick.xml b/res/layout/preference_widget_tick.xml
new file mode 100644
index 0000000..d67a93a
--- /dev/null
+++ b/res/layout/preference_widget_tick.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+
+ -->
+
+<!-- Settings button -->
+<ImageView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tick_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:scaleType="center"
+ android:src="@drawable/ic_check_24dp" />
\ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 4d9a001..e41b8c1 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1360,4 +1360,39 @@
[CHAR LIMIT=NONE] -->
<string-array name="allowlist_hide_summary_in_battery_usage" translatable="false">
</string-array>
+
+ <!-- A list for all temperature units. [CHAR LIMIT=NONE] -->
+ <string-array name="temperature_units">
+ <item>default</item>
+ <item>celsius</item>
+ <item>fahrenheit</item>
+ <item>kelvin</item>
+ </string-array>
+
+ <!-- A list for all days of a week. [CHAR LIMIT=NONE] -->
+ <string-array name="first_day_of_week">
+ <item>default</item>
+ <item>sun</item>
+ <item>mon</item>
+ <item>tue</item>
+ <item>wed</item>
+ <item>thu</item>
+ <item>fri</item>
+ <item>sat</item>
+ </string-array>
+
+ <!-- A list for all supported calendar types. [CHAR LIMIT=NONE] -->
+ <string-array name="calendar_type">
+ <item>default</item>
+ <item>chinese</item>
+ <item>dangi</item>
+ <item>hebrew</item>
+ <item>indian</item>
+ <item>islamic</item>
+ <item>islamic-rgsa</item>
+ <item>islamic-tbla</item>
+ <item>islamic-umalqura</item>
+ <item>persian</item>
+ </string-array>
+
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index bbacc5c..40ca07f 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -603,9 +603,6 @@
<!-- Whether to show communal settings at the top level. -->
<bool name="config_show_communal_settings">false</bool>
- <!-- Whether to put the apps with system UID into system component bucket or not -->
- <bool name="config_battery_combine_system_components">false</bool>
-
<!-- The extra value for battery tip -->
<integer name="config_battery_extra_tip_value">12</integer>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 927f84d..1988d9d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -371,6 +371,26 @@
<string name="numbers_preferences_title">Numbers</string>
<!-- The summary of default string for each regional preference. [CHAR LIMIT=50] -->
<string name="default_string_of_regional_preference">[No preference]</string>
+ <!-- The title of Celsius for preference of temperature unit. [CHAR LIMIT=50] -->
+ <string name="celsius_temperature_unit">Celsius</string>
+ <!-- The title of Fahrenheit for preference of temperature unit. [CHAR LIMIT=50] -->
+ <string name="fahrenheit_temperature_unit">Fahrenheit</string>
+ <!-- The title of Kevin for preference of temperature unit. [CHAR LIMIT=50] -->
+ <string name="kevin_temperature_unit">Kevin</string>
+ <!-- The title of sunday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="sunday_first_day_of_week">Sunday</string>
+ <!-- The title of monday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="monday_first_day_of_week">Monday</string>
+ <!-- The title of tuesday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="tuesday_first_day_of_week">Tuesday</string>
+ <!-- The title of wednesday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="wednesday_first_day_of_week">Wednesday</string>
+ <!-- The title of thursday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="thursday_first_day_of_week">Thursday</string>
+ <!-- The title of friday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="friday_first_day_of_week">Friday</string>
+ <!-- The title of saturday for preference of first day of week. [CHAR LIMIT=50] -->
+ <string name="saturday_first_day_of_week">Saturday</string>
<!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
<string name="dlg_remove_locales_title">{count, plural,
@@ -1034,8 +1054,6 @@
<string name="fingerprint_unlock_set_unlock_password">Fingerprint + Password</string>
<!-- Title for preference that guides the user to skip fingerprint setup [CHAR LIMIT=60]-->
<string name="fingerprint_unlock_skip_fingerprint">Continue without fingerprint</string>
- <!-- Message shown in screen lock picker while setting up the new screen lock with fingerprint option. [CHAR LIMIT=NONE]-->
- <string name="fingerprint_unlock_title">You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock.</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for Face Unlock [CHAR LIMIT=45]-->
<string name="face_unlock_set_unlock_pattern">Face Unlock + Pattern</string>
@@ -1045,8 +1063,6 @@
<string name="face_unlock_set_unlock_password">Face Unlock + Password</string>
<!-- Title for preference that guides the user to skip Face Unlock setup [CHAR LIMIT=60]-->
<string name="face_unlock_skip_face">Continue without Face Unlock</string>
- <!-- Message shown in screen lock picker while setting up the new screen lock with face unlock option. [CHAR LIMIT=NONE] -->
- <string name="face_unlock_title">You can unlock your phone using your face. For security, this option requires a backup screen lock.</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for biometrics unlock [CHAR LIMIT=45]-->
<string name="biometrics_unlock_set_unlock_pattern">Pattern \u2022 Face \u2022 Fingerprint</string>
@@ -1056,8 +1072,6 @@
<string name="biometrics_unlock_set_unlock_password">Password \u2022 Face \u2022 Fingerprint</string>
<!-- Title for preference that guides the user to skip face unlock setup [CHAR LIMIT=60]-->
<string name="biometrics_unlock_skip_biometrics">Continue without face or fingerprint</string>
- <!-- Message shown in screen lock picker while setting up the new screen lock with biometrics option. [CHAR LIMIT=NONE] -->
- <string name="biometrics_unlock_title">You can unlock your phone using your face or fingerprint. For security, this option requires a backup screen lock.</string>
<!-- Summary for "Configure lockscreen" when lock screen is off [CHAR LIMIT=45] -->
<string name="unlock_set_unlock_mode_off">None</string>
@@ -2436,7 +2450,7 @@
<!-- About phone, title of EID -->
<string name="status_eid">EID</string>
<!-- About phone, title of EID for multi-sim devices -->
- <string name="eid_multi_sim">EID (sim slot %1$d)</string>
+ <string name="eid_multi_sim">EID (sim slot <xliff:g id="eid_slot_id">%1$d</xliff:g>)</string>
<!-- About phone screen, title for IMEI for multi-sim devices -->
<string name="imei_multi_sim">IMEI (sim slot %1$d)</string>
<!-- About phone screen, summary of the MAC address [CHAR LIMIT=80] -->
@@ -5065,6 +5079,10 @@
<string name="battery_not_usage_24hr">No usage for past 24 hr</string>
<!-- Description for no usage time but have battery usage [CHAR LIMIT=120] -->
<string name="battery_usage_without_time"></string>
+ <!-- Description for system apps aggregated battery usage data [CHAR LIMIT=120] -->
+ <string name="battery_usage_system_apps">System apps</string>
+ <!-- Description for others battery usage data [CHAR LIMIT=120] -->
+ <string name="battery_usage_others">Others</string>
<!-- Description for battery time left, i.e. 50min Estimated time left. [CHAR LIMIT=80]-->
<string name="estimated_time_left">Estimated time left</string>
@@ -5175,13 +5193,13 @@
<!-- [CHAR_LIMIT=NONE] Accessibility content description for hourly battery chart view. -->
<string name="hourly_battery_usage_chart">Hourly battery usage chart</string>
<!-- [CHAR_LIMIT=NONE] Battery usage breakdown title since last full charge -->
- <string name="battery_usage_breakdown_title_since_last_full_charge">Usage proportional breakdown since last full charge</string>
+ <string name="battery_usage_breakdown_title_since_last_full_charge">Battery usage since last full charge</string>
<!-- [CHAR_LIMIT=NONE] Battery usage breakdown title for a selected slot -->
- <string name="battery_usage_breakdown_title_for_slot">Usage proportional breakdown for <xliff:g id="slot">%s</xliff:g></string>
- <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. -->
- <string name="battery_usage_app_tab">App</string>
- <!-- [CHAR_LIMIT=NONE] The tab title in the battery usage breakdown. -->
- <string name="battery_usage_system_tab">System</string>
+ <string name="battery_usage_breakdown_title_for_slot">Battery usage for <xliff:g id="slot">%s</xliff:g></string>
+ <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. -->
+ <string name="battery_usage_spinner_breakdown_by_apps">Breakdown by apps</string>
+ <!-- [CHAR_LIMIT=NONE] The spinner item text in the battery usage breakdown. -->
+ <string name="battery_usage_spinner_breakdown_by_system">Breakdown by system</string>
<!-- Process Stats strings -->
<skip />
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 4371995..af6152a 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -32,8 +32,8 @@
"com.android.settings.fuelgauge.batteryusage.BatteryUsageBreakdownController"
settings:isPreferenceVisible="false">
- <com.android.settings.fuelgauge.batteryusage.TabPreference
- android:key="battery_usage_tab"
+ <com.android.settings.fuelgauge.batteryusage.SpinnerPreference
+ android:key="battery_usage_spinner"
settings:isPreferenceVisible="false" />
<PreferenceCategory
diff --git a/res/xml/regional_preference_content_page.xml b/res/xml/regional_preference_content_page.xml
new file mode 100644
index 0000000..ed60eba
--- /dev/null
+++ b/res/xml/regional_preference_content_page.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index c37b609..143c92d 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -572,6 +572,11 @@
@VisibleForTesting
void launchSettingFragment(String initialFragmentName, Intent intent) {
if (initialFragmentName != null) {
+ if (SettingsActivityUtil.launchSpaActivity(this, initialFragmentName, intent)) {
+ finish();
+ return;
+ }
+
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
diff --git a/src/com/android/settings/SettingsActivityUtil.kt b/src/com/android/settings/SettingsActivityUtil.kt
new file mode 100644
index 0000000..cac341f
--- /dev/null
+++ b/src/com/android/settings/SettingsActivityUtil.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 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
+
+import android.content.Context
+import android.content.Intent
+import android.util.FeatureFlagUtils
+import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails
+import com.android.settings.applications.appinfo.DrawOverlayDetails
+import com.android.settings.applications.appinfo.ExternalSourcesDetails
+import com.android.settings.applications.appinfo.ManageExternalStorageDetails
+import com.android.settings.applications.appinfo.MediaManagementAppsDetails
+import com.android.settings.applications.appinfo.WriteSettingsDetails
+import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureDetails
+import com.android.settings.applications.specialaccess.pictureinpicture.PictureInPictureSettings
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
+import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
+import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
+import com.android.settings.spa.app.specialaccess.AllFilesAccessAppListProvider
+import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
+import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
+import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
+import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
+import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
+import com.android.settings.wifi.ChangeWifiStateDetails
+
+object SettingsActivityUtil {
+ private val FRAGMENT_TO_SPA_DESTINATION_MAP = mapOf(
+ PictureInPictureSettings::class.qualifiedName to
+ PictureInPictureListProvider.getAppListRoute(),
+ )
+
+ private val FRAGMENT_TO_SPA_APP_DESTINATION_PREFIX_MAP = mapOf(
+ PictureInPictureDetails::class.qualifiedName to
+ PictureInPictureListProvider.getAppInfoRoutePrefix(),
+ DrawOverlayDetails::class.qualifiedName to
+ DisplayOverOtherAppsAppListProvider.getAppInfoRoutePrefix(),
+ WriteSettingsDetails::class.qualifiedName to
+ ModifySystemSettingsAppListProvider.getAppInfoRoutePrefix(),
+ AlarmsAndRemindersDetails::class.qualifiedName to
+ AlarmsAndRemindersAppListProvider.getAppInfoRoutePrefix(),
+ ExternalSourcesDetails::class.qualifiedName to
+ InstallUnknownAppsListProvider.getAppInfoRoutePrefix(),
+ ManageExternalStorageDetails::class.qualifiedName to
+ AllFilesAccessAppListProvider.getAppInfoRoutePrefix(),
+ MediaManagementAppsDetails::class.qualifiedName to
+ MediaManagementAppsAppListProvider.getAppInfoRoutePrefix(),
+ ChangeWifiStateDetails::class.qualifiedName to
+ WifiControlAppListProvider.getAppInfoRoutePrefix(),
+ )
+
+ @JvmStatic
+ fun Context.launchSpaActivity(fragmentName: String, intent: Intent): Boolean {
+ if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) {
+ return false
+ }
+ FRAGMENT_TO_SPA_DESTINATION_MAP[fragmentName]?.let { destination ->
+ startSpaActivity(destination)
+ return true
+ }
+ FRAGMENT_TO_SPA_APP_DESTINATION_PREFIX_MAP[fragmentName]?.let { appDestinationPrefix ->
+ startSpaActivityForApp(appDestinationPrefix, intent)
+ return true
+ }
+ return false
+ }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 4a00260..06b25d6 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -415,7 +415,13 @@
return;
}
super.onPrepareOptionsMenu(menu);
- menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
+ final MenuItem uninstallAllUsersItem = menu.findItem(UNINSTALL_ALL_USERS_MENU);
+ uninstallAllUsersItem.setVisible(
+ shouldShowUninstallForAll(mAppEntry) && !mAppsControlDisallowedBySystem);
+ if (uninstallAllUsersItem.isVisible()) {
+ RestrictedLockUtilsInternal.setMenuItemAsDisabledByAdmin(getActivity(),
+ uninstallAllUsersItem, mAppsControlDisallowedAdmin);
+ }
menu.findItem(ACCESS_RESTRICTED_SETTINGS).setVisible(shouldShowAccessRestrictedSettings());
mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
index c869fc5..8c4c41d 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
+++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt
@@ -59,6 +59,7 @@
import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
import com.android.settings.spa.app.specialaccess.MediaManagementAppsAppListProvider
import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.notification.AppListNotificationsPageProvider
import com.android.settings.spa.system.AppLanguagesPageProvider
@@ -101,6 +102,7 @@
LIST_MANAGE_EXTERNAL_STORAGE -> AllFilesAccessAppListProvider.getAppListRoute()
LIST_TYPE_MEDIA_MANAGEMENT_APPS -> MediaManagementAppsAppListProvider.getAppListRoute()
LIST_TYPE_ALARMS_AND_REMINDERS -> AlarmsAndRemindersAppListProvider.getAppListRoute()
+ LIST_TYPE_WIFI_ACCESS -> WifiControlAppListProvider.getAppListRoute()
LIST_TYPE_NOTIFICATION -> AppListNotificationsPageProvider.name
LIST_TYPE_APPS_LOCALE -> AppLanguagesPageProvider.name
LIST_TYPE_MAIN -> AllAppListPageProvider.name
diff --git a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
index 034230e..d794de6 100644
--- a/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
+++ b/src/com/android/settings/applications/specialaccess/pictureinpicture/PictureInPictureSettings.java
@@ -28,7 +28,6 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import android.util.FeatureFlagUtils;
import android.util.IconDrawableFactory;
import android.util.Pair;
import android.view.View;
@@ -41,8 +40,6 @@
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.spa.SpaActivity;
-import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider;
import com.android.settings.widget.EmptyTextSettings;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.AppPreference;
@@ -130,16 +127,6 @@
}
@Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) {
- SpaActivity.startSpaActivity(
- context, PictureInPictureListProvider.INSTANCE.getAppListRoute());
- finish();
- }
- }
-
- @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
diff --git a/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
index cdf5310..e7d97f7 100644
--- a/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
+++ b/src/com/android/settings/bluetooth/BluetoothLengthDeviceNameFilter.java
@@ -17,7 +17,7 @@
package com.android.settings.bluetooth;
/**
- * Filter to max the length of a Bluetotoh device name to 248 bytes, as defined by the spec.
+ * Filter to max the length of a Bluetooth device name to 248 bytes, as defined by the spec.
*/
public class BluetoothLengthDeviceNameFilter extends Utf8ByteLengthFilter {
private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248;
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
index a9e89e9..535e040 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingController.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -31,6 +31,7 @@
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -238,8 +239,8 @@
case BluetoothDevice.ACCESS_REJECTED:
return false;
default:
- if (mDevice.getBluetoothClass().getDeviceClass()
- == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE) {
+ if (BluetoothUtils.isDeviceClassMatched(
+ mDevice, BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE)) {
return BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND == mInitiator;
}
return false;
@@ -250,11 +251,12 @@
* Update Phone book permission
*
*/
- public void setContactSharingState() {
+ public void setContactSharingState() {
final int permission = mDevice.getPhonebookAccessPermission();
if (permission == BluetoothDevice.ACCESS_ALLOWED
- || (permission == BluetoothDevice.ACCESS_UNKNOWN && mDevice.getBluetoothClass().
- getDeviceClass() == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE)) {
+ || (permission == BluetoothDevice.ACCESS_UNKNOWN
+ && BluetoothUtils.isDeviceClassMatched(mDevice,
+ BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE))) {
onCheckedChanged(null, true);
} else {
onCheckedChanged(null, false);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 676af2c..db9a8bd 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -22,6 +22,7 @@
import com.android.settingslib.fuelgauge.Estimate;
+import java.util.List;
import java.util.Set;
/**
@@ -35,6 +36,11 @@
boolean isBatteryUsageEnabled(Context context);
/**
+ * Returns an allowlist of app names combined into the system-apps item
+ */
+ List<String> getSystemAppsAllowlist(Context context);
+
+ /**
* Check whether location setting is enabled
*/
boolean isLocationSettingEnabled(String[] packages);
@@ -127,6 +133,11 @@
Intent getResumeChargeIntent(boolean isDockDefender);
/**
+ * Returns {@link Set} for the system component ids which are combined into others.
+ */
+ Set<Integer> getOthersSystemComponentSet(Context context);
+
+ /**
* Returns {@link Set} for hiding system component ids in the usage screen.
*/
Set<Integer> getHideSystemComponentSet(Context context);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 6e4ff95..06cb8be 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -26,6 +26,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.settingslib.fuelgauge.Estimate;
+import java.util.List;
import java.util.Set;
/** Implementation of {@code PowerUsageFeatureProvider} */
@@ -71,6 +72,11 @@
}
@Override
+ public List<String> getSystemAppsAllowlist(Context context) {
+ return null;
+ }
+
+ @Override
public boolean isLocationSettingEnabled(String[] packages) {
return false;
}
@@ -147,6 +153,11 @@
}
@Override
+ public Set<Integer> getOthersSystemComponentSet(Context context) {
+ return new ArraySet<>();
+ }
+
+ @Override
public Set<Integer> getHideSystemComponentSet(Context context) {
return new ArraySet<>();
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index 2c23bb3..9e0c6d7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -15,12 +15,12 @@
*/
package com.android.settings.fuelgauge.batteryusage;
+import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -62,10 +62,10 @@
// A BatteryHistEntry corresponding to this diff usage data.
public final BatteryHistEntry mBatteryHistEntry;
+ protected Context mContext;
+
private double mTotalConsumePower;
private double mPercentOfTotal;
-
- private Context mContext;
private UserManager mUserManager;
private String mDefaultPackageName = null;
@@ -111,6 +111,11 @@
? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
}
+ /** Gets the total consumed power in a specific time slot. */
+ public double getTotalConsumePower() {
+ return mTotalConsumePower;
+ }
+
/** Gets the percentage of total consumed power. */
public double getPercentOfTotal() {
return mPercentOfTotal;
@@ -176,23 +181,17 @@
/** Whether the current BatteryDiffEntry is system component or not. */
public boolean isSystemEntry() {
+ if (mBatteryHistEntry.mIsHidden) {
+ return false;
+ }
switch (mBatteryHistEntry.mConsumerType) {
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
return true;
case ConvertUtils.CONSUMER_TYPE_UID_BATTERY:
- final int uid = (int) mBatteryHistEntry.mUid;
- if (mBatteryHistEntry.mIsHidden
- || uid == BatteryUtils.UID_REMOVED_APPS
- || uid == BatteryUtils.UID_TETHERING) {
- return true;
- }
- final boolean combineSystemComponents =
- mContext.getResources().getBoolean(
- R.bool.config_battery_combine_system_components);
- return combineSystemComponents && isSystemUid(uid);
+ default:
+ return false;
}
- return false;
}
void loadLabelAndIcon() {
@@ -396,8 +395,85 @@
mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
}
- private static boolean isSystemUid(int uid) {
- final int appUid = UserHandle.getAppId(uid);
- return appUid >= Process.SYSTEM_UID && appUid < Process.FIRST_APPLICATION_UID;
+ /** Specific battery diff entry for system apps. */
+ static class SystemAppsBatteryDiffEntry extends BatteryDiffEntry {
+ SystemAppsBatteryDiffEntry(Context context) {
+ super(context,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*screenOnTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
+ new BatteryHistEntry(new ContentValues()));
+ }
+
+ @Override
+ public String getKey() {
+ return "A|SystemApps";
+ }
+
+ @Override
+ public String getAppLabel() {
+ return mContext.getString(R.string.battery_usage_system_apps);
+ }
+
+ @Override
+ public Drawable getAppIcon() {
+ return mContext.getDrawable(R.drawable.ic_power_system);
+ }
+
+ @Override
+ public boolean validForRestriction() {
+ return false;
+ }
+
+ @Override
+ public boolean isSystemEntry() {
+ return false;
+ }
+ }
+
+ /** Specific battery diff entry for others. */
+ static class OthersBatteryDiffEntry extends BatteryDiffEntry {
+ OthersBatteryDiffEntry(Context context) {
+ super(context,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*screenOnTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
+ new BatteryHistEntry(new ContentValues()));
+ }
+
+ @Override
+ public String getKey() {
+ return "S|Others";
+ }
+
+ @Override
+ public String getAppLabel() {
+ return mContext.getString(R.string.battery_usage_others);
+ }
+
+ @Override
+ public Drawable getAppIcon() {
+ return mContext.getDrawable(R.drawable.ic_settings_ethernet);
+ }
+
+ @Override
+ public boolean validForRestriction() {
+ return false;
+ }
+
+ @Override
+ public boolean isSystemEntry() {
+ return true;
+ }
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
index ba1ebab..acf62c2 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryEntry.java
@@ -200,11 +200,11 @@
/** Battery entry for a power component of AggregateBatteryConsumer */
public BatteryEntry(Context context, int powerComponentId, double devicePowerMah,
- long usageDurationMs) {
+ long usageDurationMs, boolean isHidden) {
mContext = context;
mBatteryConsumer = null;
mUid = Process.INVALID_UID;
- mIsHidden = false;
+ mIsHidden = isHidden;
mPowerComponentId = powerComponentId;
mConsumedPower = devicePowerMah;
mUsageDurationMs = usageDurationMs;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 1452b54..10cfd39 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -24,12 +24,13 @@
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
-import androidx.viewpager2.widget.ViewPager2;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
@@ -55,7 +56,7 @@
private static final String TAG = "BatteryUsageBreakdownController";
private static final String ROOT_PREFERENCE_KEY = "battery_usage_breakdown";
private static final String FOOTER_PREFERENCE_KEY = "battery_usage_footer";
- private static final String TAB_PREFERENCE_KEY = "battery_usage_tab";
+ private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner";
private static final String APP_LIST_PREFERENCE_KEY = "app_list";
private static final String PACKAGE_NAME_NONE = "none";
private static final int ENABLED_ICON_ALPHA = 255;
@@ -69,7 +70,7 @@
@VisibleForTesting
final Map<String, Preference> mPreferenceCache = new HashMap<>();
- private int mTabPosition;
+ private int mSpinnerPosition;
private String mSlotTimestamp;
@VisibleForTesting
@@ -77,7 +78,7 @@
@VisibleForTesting
PreferenceCategory mRootPreference;
@VisibleForTesting
- TabPreference mTabPreference;
+ SpinnerPreference mSpinnerPreference;
@VisibleForTesting
PreferenceGroup mAppListPreferenceGroup;
@VisibleForTesting
@@ -145,26 +146,33 @@
super.displayPreference(screen);
mPrefContext = screen.getContext();
mRootPreference = screen.findPreference(ROOT_PREFERENCE_KEY);
- mTabPreference = screen.findPreference(TAB_PREFERENCE_KEY);
+ mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY);
mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY);
mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
mAppListPreferenceGroup.setOrderingAsAdded(false);
- mTabPreference.initializeTabs(mFragment, new String[]{
- mPrefContext.getString(R.string.battery_usage_app_tab),
- mPrefContext.getString(R.string.battery_usage_system_tab)
- });
- mTabPreference.setOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
- @Override
- public void onPageSelected(int position) {
- super.onPageSelected(position);
- mTabPosition = position;
- mHandler.post(() -> {
- removeAndCacheAllPreferences();
- addAllPreferences();
+ mSpinnerPreference.initializeSpinner(
+ new String[]{
+ mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_apps),
+ mPrefContext.getString(R.string.battery_usage_spinner_breakdown_by_system)
+ },
+ new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(
+ AdapterView<?> parent, View view, int position, long id) {
+ if (mSpinnerPosition != position) {
+ mSpinnerPosition = position;
+ mHandler.post(() -> {
+ removeAndCacheAllPreferences();
+ addAllPreferences();
+ });
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
});
- }
- });
}
/**
@@ -182,7 +190,7 @@
mSlotTimestamp = slotTimestamp;
showCategoryTitle(slotTimestamp);
- showTabAndAppList();
+ showSpinnerAndAppList();
showFooterPreference(isAllUsageDataEmpty);
}
@@ -204,12 +212,12 @@
mFooterPreference.setVisible(true);
}
- private void showTabAndAppList() {
+ private void showSpinnerAndAppList() {
removeAndCacheAllPreferences();
if (mBatteryDiffData == null) {
return;
}
- mTabPreference.setVisible(true);
+ mSpinnerPreference.setVisible(true);
mAppListPreferenceGroup.setVisible(true);
mHandler.post(() -> {
addAllPreferences();
@@ -222,7 +230,7 @@
return;
}
final long start = System.currentTimeMillis();
- final List<BatteryDiffEntry> entries = mTabPosition == 0
+ final List<BatteryDiffEntry> entries = mSpinnerPosition == 0
? mBatteryDiffData.getAppDiffEntryList()
: mBatteryDiffData.getSystemDiffEntryList();
int prefIndex = mAppListPreferenceGroup.getPreferenceCount();
@@ -234,7 +242,7 @@
Log.w(TAG, "cannot find app resource for:" + entry.getPackageName());
continue;
}
- final String prefKey = entry.mBatteryHistEntry.getKey();
+ final String prefKey = entry.getKey();
PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
if (pref != null) {
isAdded = true;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index ff52774..649adbe 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -19,6 +19,7 @@
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName;
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTime;
+import android.app.Application;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
@@ -52,6 +53,7 @@
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.fuelgauge.BatteryStatus;
import java.time.Duration;
@@ -75,6 +77,8 @@
public final class DataProcessor {
private static final boolean DEBUG = false;
private static final String TAG = "DataProcessor";
+ private static final int POWER_COMPONENT_SYSTEM_SERVICES = 7;
+ private static final int POWER_COMPONENT_WAKELOCK = 12;
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
private static final int MIN_DAILY_DATA_SIZE = 2;
private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
@@ -1448,6 +1452,9 @@
// Calculates all packages diff usage data in a specific time slot.
for (String key : allBatteryHistEntryKeys) {
+ if (key == null) {
+ continue;
+ }
final BatteryHistEntry currentEntry =
currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
final BatteryHistEntry nextEntry =
@@ -1711,6 +1718,8 @@
hideBackgroundUsageTimeSet);
batteryDiffData.setTotalConsumePower();
batteryDiffData.sortEntries();
+ combineIntoSystemApps(context, batteryDiffData);
+ combineSystemItemsIntoOthers(context, batteryDiffData);
});
});
}
@@ -1736,6 +1745,91 @@
}
}
+ private static void combineSystemItemsIntoOthers(
+ final Context context, final BatteryDiffData batteryDiffData) {
+ final Set<Integer> othersSystemComponentSet =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getOthersSystemComponentSet(context);
+
+ BatteryDiffEntry.OthersBatteryDiffEntry othersDiffEntry = null;
+ final Iterator<BatteryDiffEntry> systemListIterator =
+ batteryDiffData.getSystemDiffEntryList().iterator();
+ while (systemListIterator.hasNext()) {
+ final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
+ if (othersSystemComponentSet.contains(batteryDiffEntry.mBatteryHistEntry.mDrainType)) {
+ if (othersDiffEntry == null) {
+ othersDiffEntry = new BatteryDiffEntry.OthersBatteryDiffEntry(context);
+ }
+ othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
+ othersDiffEntry.setTotalConsumePower(
+ batteryDiffEntry.getTotalConsumePower());
+ systemListIterator.remove();
+ }
+ }
+ if (othersDiffEntry != null) {
+ batteryDiffData.getSystemDiffEntryList().add(othersDiffEntry);
+ }
+ }
+
+ private static void combineIntoSystemApps(
+ final Context context, final BatteryDiffData batteryDiffData) {
+ final List<String> systemAppsAllowlist =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getSystemAppsAllowlist(context);
+ final Application application = (Application) context.getApplicationContext();
+ final ApplicationsState applicationsState =
+ application == null ? null : ApplicationsState.getInstance(application);
+
+ BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
+ final Iterator<BatteryDiffEntry> appListIterator =
+ batteryDiffData.getAppDiffEntryList().iterator();
+ while (appListIterator.hasNext()) {
+ final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
+ if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist, applicationsState)) {
+ if (systemAppsDiffEntry == null) {
+ systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
+ }
+ systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
+ systemAppsDiffEntry.setTotalConsumePower(
+ batteryDiffEntry.getTotalConsumePower());
+ appListIterator.remove();
+ }
+ }
+ if (systemAppsDiffEntry != null) {
+ batteryDiffData.getAppDiffEntryList().add(systemAppsDiffEntry);
+ }
+ }
+
+ @VisibleForTesting
+ static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry,
+ final List<String> systemAppsAllowlist, final ApplicationsState applicationsState) {
+ if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
+ return true;
+ }
+
+ final String packageName = batteryDiffEntry.getPackageName();
+ if (packageName == null || packageName.isEmpty()) {
+ return false;
+ }
+
+ if (systemAppsAllowlist != null && systemAppsAllowlist.contains(packageName)) {
+ return true;
+ }
+
+ if (applicationsState == null) {
+ return false;
+ }
+ final ApplicationsState.AppEntry appEntry =
+ applicationsState.getEntry(packageName, /* userId= */ 0);
+ if (appEntry == null || appEntry.info == null) {
+ return false;
+ }
+ return !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT.filterApp(
+ appEntry);
+ }
+
private static boolean shouldShowBatteryAttributionList(final Context context) {
final PowerProfile powerProfile = new PowerProfile(context);
// Cheap hack to try to figure out if the power_profile.xml was populated.
@@ -1801,7 +1895,9 @@
componentId++) {
results.add(new BatteryEntry(context, componentId,
deviceConsumer.getConsumedPower(componentId),
- deviceConsumer.getUsageDurationMillis(componentId)));
+ deviceConsumer.getUsageDurationMillis(componentId),
+ componentId == POWER_COMPONENT_SYSTEM_SERVICES
+ || componentId == POWER_COMPONENT_WAKELOCK));
}
for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
diff --git a/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
new file mode 100644
index 0000000..47e051c
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreference.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 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.batteryusage;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settingslib.widget.SettingsSpinnerAdapter;
+
+/** A preference which contains a spinner. */
+public class SpinnerPreference extends Preference {
+ private static final String TAG = "SpinnerPreference";
+
+ private AdapterView.OnItemSelectedListener mOnItemSelectedListener;
+
+ @VisibleForTesting
+ Spinner mSpinner;
+ @VisibleForTesting
+ String[] mItems;
+ @VisibleForTesting
+ int mSavedSpinnerPosition;
+
+ public SpinnerPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.preference_spinner);
+ }
+
+ void initializeSpinner(
+ String[] items, AdapterView.OnItemSelectedListener onItemSelectedListener) {
+ mItems = items;
+ mOnItemSelectedListener = onItemSelectedListener;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ mSpinner = (Spinner) view.findViewById(R.id.spinner);
+ mSpinner.setAdapter(new SpinnerAdapter(getContext(), mItems));
+ mSpinner.setSelection(mSavedSpinnerPosition);
+ if (mOnItemSelectedListener != null) {
+ mSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Log.d(TAG, "onSaveInstanceState() spinnerPosition=" + mSpinner.getSelectedItemPosition());
+ return new SavedState(super.onSaveInstanceState(), mSpinner.getSelectedItemPosition());
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state == null || !state.getClass().equals(SavedState.class)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+ SavedState savedState = (SavedState) state;
+ super.onRestoreInstanceState(savedState.getSuperState());
+ mSavedSpinnerPosition = savedState.getSpinnerPosition();
+ if (mOnItemSelectedListener != null) {
+ mOnItemSelectedListener.onItemSelected(/* parent= */null, /* view= */null,
+ savedState.getSpinnerPosition(), /* id= */ 0);
+ }
+ Log.d(TAG, "onRestoreInstanceState() spinnerPosition=" + savedState.getSpinnerPosition());
+ }
+
+ @VisibleForTesting
+ static class SavedState extends BaseSavedState {
+ private int mSpinnerPosition;
+
+ SavedState(Parcelable superState, int spinnerPosition) {
+ super(superState);
+ mSpinnerPosition = spinnerPosition;
+ }
+
+ int getSpinnerPosition() {
+ return mSpinnerPosition;
+ }
+ }
+
+ private static class SpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {
+ private final String[] mItems;
+
+ SpinnerAdapter(Context context, String[] items) {
+ super(context);
+ mItems = items;
+ }
+
+ @Override
+ public int getCount() {
+ return mItems.length;
+ }
+
+ @Override
+ public CharSequence getItem(int position) {
+ return mItems[position];
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java b/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java
deleted file mode 100644
index 0c5a699..0000000
--- a/src/com/android/settings/fuelgauge/batteryusage/TabPreference.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2022 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.batteryusage;
-
-import android.content.Context;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.settings.R;
-
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-/** A preference which contains a tab selection. */
-public class TabPreference extends Preference {
- private static final String TAG = "TabPreference";
-
- private Fragment mRootFragment;
- private ViewPager2 mViewPager;
- private ViewPager2.OnPageChangeCallback mOnPageChangeCallback;
-
- @VisibleForTesting
- String[] mTabTitles;
- @VisibleForTesting
- int mSavedTabPosition;
- @VisibleForTesting
- TabLayout mTabLayout;
-
- public TabPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- setLayoutResource(R.layout.preference_tab);
- }
-
- void initializeTabs(Fragment rootFragment, String[] tabTitles) {
- mRootFragment = rootFragment;
- mTabTitles = tabTitles;
- }
-
- void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback callback) {
- mOnPageChangeCallback = callback;
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder view) {
- super.onBindViewHolder(view);
- if (mViewPager != null && mTabLayout != null) {
- return;
- }
-
- mViewPager = (ViewPager2) view.findViewById(R.id.view_pager);
- mViewPager.setAdapter(new FragmentAdapter(mRootFragment, mTabTitles.length));
- mViewPager.setUserInputEnabled(false);
- if (mOnPageChangeCallback != null) {
- mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
- }
-
- mTabLayout = (TabLayout) view.findViewById(R.id.tabs);
- new TabLayoutMediator(
- mTabLayout, mViewPager, /* autoRefresh= */ true, /* smoothScroll= */ false,
- (tab, position) -> tab.setText(mTabTitles[position])).attach();
- mTabLayout.getTabAt(mSavedTabPosition).select();
- }
-
- @Override
- public void onDetached() {
- super.onDetached();
- if (mViewPager != null && mOnPageChangeCallback != null) {
- mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
- }
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- Log.d(TAG, "onSaveInstanceState() tabPosition=" + mTabLayout.getSelectedTabPosition());
- return new SavedState(super.onSaveInstanceState(), mTabLayout.getSelectedTabPosition());
- }
-
- @Override
- protected void onRestoreInstanceState(Parcelable state) {
- if (state == null || !state.getClass().equals(SavedState.class)) {
- super.onRestoreInstanceState(state);
- return;
- }
- SavedState savedState = (SavedState) state;
- super.onRestoreInstanceState(savedState.getSuperState());
- mSavedTabPosition = savedState.getTabPosition();
- Log.d(TAG, "onRestoreInstanceState() tabPosition=" + savedState.getTabPosition());
- }
-
- @VisibleForTesting
- static class SavedState extends BaseSavedState {
- private int mTabPosition;
-
- SavedState(Parcelable superState, int tabPosition) {
- super(superState);
- mTabPosition = tabPosition;
- }
-
- int getTabPosition() {
- return mTabPosition;
- }
- }
-
- private static class FragmentAdapter extends FragmentStateAdapter {
- private final int mItemCount;
- private final Fragment[] mItemFragments;
-
- FragmentAdapter(@NonNull Fragment rootFragment, int itemCount) {
- super(rootFragment);
- mItemCount = itemCount;
- mItemFragments = new Fragment[mItemCount];
- for (int i = 0; i < mItemCount; i++) {
- // Empty tab pages.
- mItemFragments[i] = new Fragment();
- }
- }
-
- @NonNull
- @Override
- public Fragment createFragment(int position) {
- return mItemFragments[position];
- }
-
- @Override
- public int getItemCount() {
- return mItemCount;
- }
- }
-}
diff --git a/src/com/android/settings/regionalpreferences/CalendarTypeController.java b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
index ea59191..1a81e7f 100644
--- a/src/com/android/settings/regionalpreferences/CalendarTypeController.java
+++ b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
@@ -16,11 +16,17 @@
package com.android.settings.regionalpreferences;
+import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
-import com.android.settings.R;
+import androidx.preference.Preference;
+
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
import java.util.Locale;
@@ -28,6 +34,7 @@
* A controller for the entry of Calendar types' page
*/
public class CalendarTypeController extends BasePreferenceController {
+ private static final String TAG = CalendarTypeController.class.getSimpleName();
public CalendarTypeController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@@ -60,7 +67,26 @@
if (result.isEmpty()) {
result = LocalePreferences.getCalendarType(false);
}
- return result.isEmpty()
- ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+
+ String inputStr = result.isEmpty() ? RegionalPreferencesFragment.TYPE_DEFAULT : result;
+ return RegionalPreferencesDataUtils.calendarConverter(mContext, inputStr);
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+ Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+ return false;
+ }
+
+ final Bundle extra = new Bundle();
+ extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+ RegionalPreferencesFragment.TYPE_CALENDAR);
+ new SubSettingLauncher(preference.getContext())
+ .setDestination(RegionalPreferencesFragment.class.getName())
+ .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+ .setArguments(extra)
+ .launch();
+ return true;
}
}
diff --git a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
index 3fb8a1e..22823d7 100644
--- a/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
+++ b/src/com/android/settings/regionalpreferences/FirstDayOfWeekController.java
@@ -16,16 +16,25 @@
package com.android.settings.regionalpreferences;
+import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
import java.util.Locale;
/** A controller for the entry of First Day of Week's page */
public class FirstDayOfWeekController extends BasePreferenceController {
+ private static final String TAG = FirstDayOfWeekController.class.getSimpleName();
+
public FirstDayOfWeekController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@@ -59,6 +68,25 @@
result = LocalePreferences.getFirstDayOfWeek(false);
}
return result.isEmpty()
- ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+ ? mContext.getString(R.string.default_string_of_regional_preference)
+ : RegionalPreferencesDataUtils.dayConverter(mContext, result);
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+ Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+ return false;
+ }
+
+ final Bundle extra = new Bundle();
+ extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+ RegionalPreferencesFragment.TYPE_FIRST_DAY_OF_WEEK);
+ new SubSettingLauncher(preference.getContext())
+ .setDestination(RegionalPreferencesFragment.class.getName())
+ .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+ .setArguments(extra)
+ .launch();
+ return true;
}
}
diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemController.java b/src/com/android/settings/regionalpreferences/NumberingSystemController.java
index e951fc2..80a2250 100644
--- a/src/com/android/settings/regionalpreferences/NumberingSystemController.java
+++ b/src/com/android/settings/regionalpreferences/NumberingSystemController.java
@@ -16,18 +16,26 @@
package com.android.settings.regionalpreferences;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.icu.text.NumberingSystem;
+import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
import java.util.Locale;
/** A controller for the entry of Numbering System's page */
public class NumberingSystemController extends BasePreferenceController {
+ private static final String TAG = NumberingSystemController.class.getSimpleName();
+
private static final String UNICODE_EXTENSION_NUMBERING_SYSTEM = "nu";
public NumberingSystemController(Context context, String preferenceKey) {
@@ -47,7 +55,8 @@
*/
@Override
public int getAvailabilityStatus() {
- return AVAILABLE;
+ // Hide this , and waiting for next implementation.
+ return CONDITIONALLY_UNAVAILABLE;
}
@Override
@@ -73,4 +82,22 @@
.build();
return NumberingSystem.getInstance(locale).getName();
}
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+ Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+ return false;
+ }
+
+ final Bundle extra = new Bundle();
+ extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+ RegionalPreferencesFragment.TYPE_NUMBERING_SYSTEM);
+ new SubSettingLauncher(preference.getContext())
+ .setDestination(RegionalPreferencesFragment.class.getName())
+ .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+ .setArguments(extra)
+ .launch();
+ return true;
+ }
}
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
new file mode 100644
index 0000000..25dc8e1
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtils.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import android.content.Context;
+import android.icu.util.ULocale;
+import android.os.LocaleList;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.app.LocalePicker;
+import com.android.settings.R;
+
+import java.util.Locale;
+
+/** Provides utils for regional preferences. */
+public class RegionalPreferencesDataUtils {
+ private static final String TAG = RegionalPreferencesDataUtils.class.getSimpleName();
+
+ private static final String U_EXTENSION_FAHRENHEIT = "fahrenhe";
+ private static final String KEYWORD_OF_CALENDAR = "calendar";
+
+ static String getDefaultUnicodeExtensionData(Context contxt, String type) {
+ // 1. Check cache data in Settings provider.
+ String record = Settings.System.getString(
+ contxt.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+ String result = "";
+
+ if (!TextUtils.isEmpty(record)) {
+ result = Locale.forLanguageTag(record).getUnicodeLocaleType(type);
+ }
+ // 2. Check cache data in default Locale(ICU lib).
+ if (TextUtils.isEmpty(result)) {
+ result = Locale.getDefault(Locale.Category.FORMAT).getUnicodeLocaleType(type);
+ }
+ if (result == null) {
+ return RegionalPreferencesFragment.TYPE_DEFAULT;
+ }
+
+ // In BCP47 expression, the tag of fahrenheit is "fahrenhe" i.e. und-u-mu-fahrenhe,
+ // so if it may need to convert from the langngiage tag, "fahrenhe", to "fahrenheit".
+ if (result.equals(U_EXTENSION_FAHRENHEIT)) {
+ return LocalePreferences.TemperatureUnit.FAHRENHEIT;
+ }
+
+ return result;
+ }
+
+ static void savePreference(Context context, String type, String value) {
+ if (type.equals(RegionalPreferencesFragment.TYPE_TEMPERATURE)
+ && value != null && value.equals(LocalePreferences.TemperatureUnit.FAHRENHEIT)) {
+ // In BCP47 expression, the temperature unit is expressed to "fahrenhe"
+ // i.e. zh-TW-u-mu-fahrenhe. Hence, if we want to save fahrenheit unit to u extension,
+ // It need to change from "fahrenheit" to "fahrenhe".
+ value = U_EXTENSION_FAHRENHEIT;
+ }
+ saveToSettingsProvider(context, type, value);
+ saveToSystem(type, value);
+ }
+
+ private static void saveToSettingsProvider(Context context, String type, String value) {
+ String record = Settings.System.getString(
+ context.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+
+ record = record == null ? "" : record;
+
+ Settings.System.putString(
+ context.getContentResolver(),
+ Settings.System.LOCALE_PREFERENCES,
+ addUnicodeKeywordToLocale(record, type, value).toLanguageTag());
+ }
+
+ private static void saveToSystem(String type, String value) {
+ LocaleList localeList = LocaleList.getDefault();
+ Locale[] resultLocales = new Locale[localeList.size()];
+ for (int i = 0; i < localeList.size(); i++) {
+ resultLocales[i] = addUnicodeKeywordToLocale(localeList.get(i), type, value);
+ }
+ LocalePicker.updateLocales(new LocaleList(resultLocales));
+ }
+
+ private static Locale addUnicodeKeywordToLocale(Locale locale, String type, String value) {
+ return new Locale.Builder()
+ .setLocale(locale)
+ .setUnicodeLocaleKeyword(type, value)
+ .build();
+ }
+
+ private static Locale addUnicodeKeywordToLocale(String languageTag, String type, String value) {
+ return addUnicodeKeywordToLocale(Locale.forLanguageTag(languageTag), type, value);
+ }
+
+ static String calendarConverter(Context context, String calendarType) {
+ if (calendarType.equals(RegionalPreferencesFragment.TYPE_DEFAULT)) {
+ return context.getString(R.string.default_string_of_regional_preference);
+ }
+
+ Locale locale = new Locale.Builder()
+ .setUnicodeLocaleKeyword(RegionalPreferencesFragment.TYPE_CALENDAR, calendarType)
+ .build();
+ return ULocale.getDisplayKeywordValue(locale.toLanguageTag(), KEYWORD_OF_CALENDAR,
+ ULocale.forLocale(Locale.getDefault(Locale.Category.FORMAT)));
+ }
+
+ static String temperatureUnitsConverter(Context context, String unit) {
+ switch (unit) {
+ case LocalePreferences.TemperatureUnit.CELSIUS:
+ return context.getString(R.string.celsius_temperature_unit);
+ case LocalePreferences.TemperatureUnit.FAHRENHEIT:
+ return context.getString(R.string.fahrenheit_temperature_unit);
+ case LocalePreferences.TemperatureUnit.KELVIN:
+ return context.getString(R.string.kevin_temperature_unit);
+ default:
+ return context.getString(R.string.default_string_of_regional_preference);
+ }
+ }
+
+ static String dayConverter(Context context, String day) {
+ switch (day) {
+ case LocalePreferences.FirstDayOfWeek.MONDAY:
+ return context.getString(R.string.monday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.TUESDAY:
+ return context.getString(R.string.tuesday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.WEDNESDAY:
+ return context.getString(R.string.wednesday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.THURSDAY:
+ return context.getString(R.string.thursday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.FRIDAY:
+ return context.getString(R.string.friday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.SATURDAY:
+ return context.getString(R.string.saturday_first_day_of_week);
+ case LocalePreferences.FirstDayOfWeek.SUNDAY:
+ return context.getString(R.string.sunday_first_day_of_week);
+ default:
+ return context.getString(R.string.default_string_of_regional_preference);
+ }
+ }
+}
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
new file mode 100644
index 0000000..aa06a43
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+/** A fragment to include each kind of regional preferences. */
+public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
+ private static final String TAG = RegionalPreferencesFragment.class.getSimpleName();
+
+ static final String TYPE_DEFAULT = "default";
+ static final String TYPE_TEMPERATURE = "mu";
+ static final String TYPE_CALENDAR = "ca";
+ static final String TYPE_FIRST_DAY_OF_WEEK = "fw";
+ static final String TYPE_NUMBERING_SYSTEM = "nu";
+ static final String TYPE_OF_REGIONAL_PREFERENCE = "type_of_regional_preference";
+
+ private PreferenceScreen mPreferenceScreen;
+ private String mTitle = "";
+ @VisibleForTesting
+ String mType = "";
+
+ private String[] initializeUIdata(String type) {
+ switch(type) {
+ case TYPE_TEMPERATURE:
+ mTitle = getPrefContext().getString(R.string.temperature_preferences_title);
+ return getPrefContext().getResources().getStringArray(R.array.temperature_units);
+ case TYPE_CALENDAR:
+ mTitle = getPrefContext().getString(R.string.calendar_preferences_title);
+ return getPrefContext().getResources().getStringArray(R.array.calendar_type);
+ case TYPE_FIRST_DAY_OF_WEEK:
+ mTitle = getPrefContext().getString(R.string.first_day_of_week_preferences_title);
+ return getPrefContext().getResources().getStringArray(R.array.first_day_of_week);
+ case TYPE_NUMBERING_SYSTEM:
+ mTitle = getPrefContext().getString(R.string.numbers_preferences_title);
+ return new String[0];
+ default:
+ mTitle = getPrefContext().getString(R.string.regional_preferences_title);
+ return new String[0];
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ for (int i = 0; i < mPreferenceScreen.getPreferenceCount(); i++) {
+ TickButtonPreference pref = (TickButtonPreference) mPreferenceScreen.getPreference(i);
+ Log.i(TAG, "[onPreferenceClick] key is " + pref.getKey());
+ if (pref.getKey().equals(preference.getKey())) {
+ pref.setTickEnable(true);
+ RegionalPreferencesDataUtils.savePreference(
+ getPrefContext(),
+ mType,
+ preference.getKey().equals(TYPE_DEFAULT) ? null : preference.getKey());
+ continue;
+ }
+ pref.setTickEnable(false);
+ }
+ return true;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ Bundle bundle = getArguments();
+ String type = bundle.getString(TYPE_OF_REGIONAL_PREFERENCE, "");
+ if (type.isEmpty()) {
+ Log.w(TAG, "There is no type name.");
+ finish();
+ }
+ mType = type;
+ addPreferencesFromResource(R.xml.regional_preference_content_page);
+ mPreferenceScreen = getPreferenceScreen();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ String[] uiData = initializeUIdata(mType);
+
+ for (String item : uiData) {
+ TickButtonPreference pref = new TickButtonPreference(getPrefContext());
+ if (mType.equals(TYPE_FIRST_DAY_OF_WEEK)) {
+ pref.setTitle(RegionalPreferencesDataUtils.dayConverter(
+ getPrefContext(), item));
+ } else if (mType.equals(TYPE_TEMPERATURE)) {
+ pref.setTitle(RegionalPreferencesDataUtils.temperatureUnitsConverter(
+ getPrefContext(), item));
+ } else if (mType.equals(TYPE_CALENDAR)) {
+ pref.setTitle(RegionalPreferencesDataUtils.calendarConverter(
+ getPrefContext(), item));
+ } else {
+ Log.d(TAG, "Finish this page due to no suitable type.");
+ finish();
+ }
+
+ String value = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+ getPrefContext(), mType);
+ pref.setKey(item);
+ pref.setTickEnable(!value.isEmpty() && item.equals(value));
+ mPreferenceScreen.addPreference(pref);
+ }
+ return view;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ getActivity().setTitle(mTitle);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ switch(mType) {
+ case TYPE_CALENDAR:
+ return SettingsEnums.CALENDAR_PREFERENCE;
+ case TYPE_FIRST_DAY_OF_WEEK:
+ return SettingsEnums.FIRST_DAY_OF_WEEK_PREFERENCE;
+ default:
+ return SettingsEnums.TEMPERATURE_PREFERENCE;
+ }
+ }
+
+}
diff --git a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
index b13b6c4..950d137 100644
--- a/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
+++ b/src/com/android/settings/regionalpreferences/TemperatureUnitController.java
@@ -16,16 +16,24 @@
package com.android.settings.regionalpreferences;
+import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
import java.util.Locale;
/** A controller for the entry of Temperature units' page */
public class TemperatureUnitController extends BasePreferenceController {
+ private static final String TAG = TemperatureUnitController.class.getSimpleName();
public TemperatureUnitController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@@ -58,7 +66,26 @@
if (result.isEmpty()) {
result = LocalePreferences.getTemperatureUnit(false);
}
+
return result.isEmpty()
- ? mContext.getString(R.string.default_string_of_regional_preference) : result;
+ ? mContext.getString(R.string.default_string_of_regional_preference)
+ : RegionalPreferencesDataUtils.temperatureUnitsConverter(mContext, result);
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+ Log.e(TAG, "not the key " + preference.getKey() + " / " + mPreferenceKey);
+ return false;
+ }
+ final Bundle extra = new Bundle();
+ extra.putString(RegionalPreferencesFragment.TYPE_OF_REGIONAL_PREFERENCE,
+ RegionalPreferencesFragment.TYPE_TEMPERATURE);
+ new SubSettingLauncher(preference.getContext())
+ .setDestination(RegionalPreferencesFragment.class.getName())
+ .setSourceMetricsCategory(SettingsEnums.REGIONAL_PREFERENCE)
+ .setArguments(extra)
+ .launch();
+ return true;
}
}
diff --git a/src/com/android/settings/regionalpreferences/TickButtonPreference.java b/src/com/android/settings/regionalpreferences/TickButtonPreference.java
new file mode 100644
index 0000000..c01521f
--- /dev/null
+++ b/src/com/android/settings/regionalpreferences/TickButtonPreference.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 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.regionalpreferences;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.TwoTargetPreference;
+
+/** A preference with tick button */
+public class TickButtonPreference extends TwoTargetPreference {
+ private static final String TAG = TickButtonPreference.class.getSimpleName();
+ private boolean mIsTickEnabled;
+ private View mWidgetFrame;
+ private View mDivider;
+
+ public TickButtonPreference(Context context) {
+ super(context, null);
+ }
+
+ /** Set this preference to be selected. */
+ public void setTickEnable(boolean isEnable) {
+ mIsTickEnabled = isEnable;
+ if (mWidgetFrame != null) {
+ mWidgetFrame.setVisibility(isEnable ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ /** Check if this preference is selected. */
+ public boolean isTickEnabled() {
+ return mIsTickEnabled;
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ mDivider = holder.findViewById(R.id.two_target_divider);
+ mWidgetFrame = holder.findViewById(android.R.id.widget_frame);
+ if (mDivider != null) {
+ mDivider.setVisibility(View.GONE);
+ }
+ if (mWidgetFrame != null) {
+ mWidgetFrame.setVisibility(mIsTickEnabled ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+
+ @Override
+ protected int getSecondTargetResId() {
+ super.getSecondTargetResId();
+ return R.layout.preference_widget_tick;
+ }
+}
diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
index 9eab400..6b22b9e 100644
--- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt
+++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt
@@ -29,6 +29,7 @@
import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
import com.android.settings.spa.app.specialaccess.SpecialAppAccessPageProvider
+import com.android.settings.spa.app.specialaccess.WifiControlAppListProvider
import com.android.settings.spa.development.UsageStatsPageProvider
import com.android.settings.spa.home.HomePageProvider
import com.android.settings.spa.notification.AppListNotificationsPageProvider
@@ -43,17 +44,20 @@
open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) {
override val pageProviderRepository = lazy {
- val togglePermissionAppListTemplate = TogglePermissionAppListTemplate(
- allProviders = listOf(
- AllFilesAccessAppListProvider,
- DisplayOverOtherAppsAppListProvider,
- MediaManagementAppsAppListProvider,
- ModifySystemSettingsAppListProvider,
- PictureInPictureListProvider,
- InstallUnknownAppsListProvider,
- AlarmsAndRemindersAppListProvider,
- ),
- )
+ val togglePermissionAppListTemplate =
+ TogglePermissionAppListTemplate(
+ allProviders =
+ listOf(
+ AllFilesAccessAppListProvider,
+ DisplayOverOtherAppsAppListProvider,
+ MediaManagementAppsAppListProvider,
+ ModifySystemSettingsAppListProvider,
+ PictureInPictureListProvider,
+ InstallUnknownAppsListProvider,
+ AlarmsAndRemindersAppListProvider,
+ WifiControlAppListProvider,
+ ),
+ )
SettingsPageProviderRepository(
allPageProviders = listOf(
HomePageProvider,
diff --git a/src/com/android/settings/spa/app/AllAppList.kt b/src/com/android/settings/spa/app/AllAppList.kt
index 05f77ed..08b06a6 100644
--- a/src/com/android/settings/spa/app/AllAppList.kt
+++ b/src/com/android/settings/spa/app/AllAppList.kt
@@ -16,10 +16,12 @@
package com.android.settings.spa.app
+import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
+import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource
import com.android.settings.R
@@ -28,9 +30,12 @@
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.rememberContext
+import com.android.settingslib.spa.framework.util.filterItem
import com.android.settingslib.spa.framework.util.mapItem
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.template.app.AppList
@@ -67,7 +72,7 @@
val resetAppDialogPresenter = rememberResetAppDialogPresenter()
AppListPage(
title = stringResource(R.string.all_apps),
- listModel = remember { AllAppListModel() },
+ listModel = rememberContext(::AllAppListModel),
showInstantApps = true,
moreOptions = { ResetAppPreferences(resetAppDialogPresenter::open) },
appList = appList,
@@ -79,17 +84,71 @@
) : AppRecord
class AllAppListModel(
- private val getSummary: @Composable ApplicationInfo.() -> State<String> = { getStorageSize() },
+ private val context: Context,
+ private val getStorageSummary: @Composable ApplicationInfo.() -> State<String> = {
+ getStorageSize()
+ },
) : AppListModel<AppRecordWithSize> {
+ override fun getSpinnerOptions(recordList: List<AppRecordWithSize>): List<SpinnerOption> {
+ val hasDisabled = recordList.any(isDisabled)
+ val hasInstant = recordList.any(isInstant)
+ if (!hasDisabled && !hasInstant) return emptyList()
+ val options = mutableListOf(SpinnerItem.All, SpinnerItem.Enabled)
+ if (hasDisabled) options += SpinnerItem.Disabled
+ if (hasInstant) options += SpinnerItem.Instant
+ return options.map {
+ SpinnerOption(
+ id = it.ordinal,
+ text = context.getString(it.stringResId),
+ )
+ }
+ }
+
override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
appListFlow.mapItem(::AppRecordWithSize)
+ override fun filter(
+ userIdFlow: Flow<Int>,
+ option: Int,
+ recordListFlow: Flow<List<AppRecordWithSize>>,
+ ): Flow<List<AppRecordWithSize>> = recordListFlow.filterItem(
+ when (SpinnerItem.values().getOrNull(option)) {
+ SpinnerItem.Enabled -> ({ it.app.enabled && !it.app.isInstantApp })
+ SpinnerItem.Disabled -> isDisabled
+ SpinnerItem.Instant -> isInstant
+ else -> ({ true })
+ }
+ )
+
+ private val isDisabled: (AppRecordWithSize) -> Boolean =
+ { !it.app.enabled && !it.app.isInstantApp }
+
+ private val isInstant: (AppRecordWithSize) -> Boolean = { it.app.isInstantApp }
+
@Composable
- override fun getSummary(option: Int, record: AppRecordWithSize) = record.app.getSummary()
+ override fun getSummary(option: Int, record: AppRecordWithSize): State<String> {
+ val storageSummary = record.app.getStorageSummary()
+ return remember {
+ derivedStateOf {
+ storageSummary.value +
+ when (isDisabled(record)) {
+ true -> System.lineSeparator() + context.getString(R.string.disabled)
+ else -> ""
+ }
+ }
+ }
+ }
@Composable
override fun AppListItemModel<AppRecordWithSize>.AppItem() {
AppListItem(onClick = AppInfoSettingsProvider.navigator(app = record.app))
}
}
+
+private enum class SpinnerItem(val stringResId: Int) {
+ All(R.string.filter_all_apps),
+ Enabled(R.string.filter_enabled_apps),
+ Disabled(R.string.filter_apps_disabled),
+ Instant(R.string.filter_instant_apps);
+}
diff --git a/src/com/android/settings/spa/app/AppUtil.kt b/src/com/android/settings/spa/app/AppUtil.kt
new file mode 100644
index 0000000..64da613
--- /dev/null
+++ b/src/com/android/settings/spa/app/AppUtil.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.spa.app
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.UserHandle
+
+/**
+ * Based on PackageManagerService design, and it looks like the suggested replacement in the
+ * deprecate notes suggest that we use PackageInstaller.uninstall which does not guarantee a pop up
+ * would open and depends on the calling application. Seems like further investigation is needed
+ * before we can move over to the new API.
+ */
+@Suppress("DEPRECATION")
+fun Context.startUninstallActivity(
+ packageName: String,
+ userHandle: UserHandle,
+ forAllUsers: Boolean = false,
+) {
+ val packageUri = Uri.parse("package:$packageName")
+
+ val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
+ putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
+ }
+ startActivityAsUser(intent, userHandle)
+}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index cb74388..51426a1 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -22,11 +22,11 @@
import android.content.IntentFilter
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
-import android.net.Uri
import android.os.UserHandle
import android.util.Log
import androidx.compose.runtime.Composable
import com.android.settings.overlay.FeatureFactory
+import com.android.settings.spa.app.startUninstallActivity
import com.android.settingslib.spa.framework.compose.LocalNavController
import com.android.settingslib.spaprivileged.framework.common.activityManager
import com.android.settingslib.spaprivileged.framework.common.asUser
@@ -116,11 +116,7 @@
/** Starts the uninstallation activity. */
fun startUninstallActivity(forAllUsers: Boolean = false) {
logAction(SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP)
- val packageUri = Uri.parse("package:${packageName}")
- val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
- putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
- }
- context.startActivityAsUser(intent, userHandle)
+ context.startUninstallActivity(packageName, userHandle, forAllUsers)
}
/** Clears this instant app. */
diff --git a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
index 9cf9516..a6b10dd 100644
--- a/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProvider.kt
@@ -17,13 +17,11 @@
package com.android.settings.spa.app.backgroundinstall
import android.content.Context
-import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.IBackgroundInstallControlService
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ParceledListSlice
-import android.net.Uri
import android.os.Bundle
import android.os.ServiceManager
import android.provider.DeviceConfig
@@ -40,6 +38,7 @@
import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
+import com.android.settings.spa.app.startUninstallActivity
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -54,6 +53,7 @@
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.template.app.AppList
import com.android.settingslib.spaprivileged.template.app.AppListButtonItem
import com.android.settingslib.spaprivileged.template.app.AppListInput
@@ -150,23 +150,6 @@
}
)
}
-/*
-Based on PackageManagerService design, and it looks like the suggested replacement in the deprecate
-notes suggest that we use PackageInstaller.uninstall which does not guarantee a pop up would open
-and depends on the calling application. Seems like further investigation is needed before we can
-move over to the new API.
- */
-@Suppress
-@VisibleForTesting
-fun startUninstallActivity(context: Context,
- packageName: String,
- forAllUsers: Boolean = false) {
- val packageUri = Uri.parse("package:${packageName}")
- val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri).apply {
- putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, forAllUsers)
- }
- context.startActivityAsUser(intent, context.user)
-}
data class BackgroundInstalledAppListWithGroupingAppRecord(
override val app: ApplicationInfo,
@@ -190,9 +173,10 @@
@Composable
override fun AppListItemModel<BackgroundInstalledAppListWithGroupingAppRecord>.AppItem() {
val context = LocalContext.current
+ val app = record.app
AppListButtonItem(
- onClick = AppInfoSettingsProvider.navigator(app = record.app),
- onButtonClick = { startUninstallActivity(context, record.app.packageName) },
+ onClick = AppInfoSettingsProvider.navigator(app = app),
+ onButtonClick = { context.startUninstallActivity(app.packageName, app.userHandle) },
buttonIcon = Icons.Outlined.Delete,
buttonIconDescription = stringResource(
R.string.background_install_uninstall_button_description))
@@ -209,11 +193,6 @@
}
}
- @Composable
- override fun getSummary(option: Int, record: BackgroundInstalledAppListWithGroupingAppRecord)
- = null
-
- @Suppress
override fun filter(
userIdFlow: Flow<Int>,
option: Int,
@@ -224,6 +203,7 @@
return flowOf()
}
return userIdFlow.combine(recordListFlow) { userId, recordList ->
+ @Suppress("UNCHECKED_CAST")
val appList = (backgroundInstallService.getBackgroundInstalledPackages(
PackageManager.MATCH_ALL.toLong(), userId) as ParceledListSlice<PackageInfo>).list
val appNameList = appList.map { it.packageName }
diff --git a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
index 556ea57..2d2dddf 100644
--- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
@@ -19,6 +19,7 @@
import android.Manifest
import android.app.AppGlobals
import android.app.AppOpsManager.MODE_DEFAULT
+import android.app.AppOpsManager.MODE_ERRORED
import android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES
import android.content.Context
import android.content.pm.ApplicationInfo
@@ -50,27 +51,32 @@
override val pageTitleResId = R.string.install_other_apps
override val switchTitleResId = R.string.external_source_switch_title
override val footerResId = R.string.install_all_warning
- override val switchRestrictionKeys = listOf(
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
- UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
- )
+ override val switchRestrictionKeys =
+ listOf(
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+ UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
+ )
- override fun transformItem(app: ApplicationInfo) = InstallUnknownAppsRecord(
- app = app,
- appOpsController = AppOpsController(
- context = context,
+ override fun transformItem(app: ApplicationInfo) =
+ InstallUnknownAppsRecord(
app = app,
- op = OP_REQUEST_INSTALL_PACKAGES,
- ),
- )
+ appOpsController =
+ AppOpsController(
+ context = context,
+ app = app,
+ op = OP_REQUEST_INSTALL_PACKAGES,
+ modeForNotAllowed = MODE_ERRORED
+ ),
+ )
override fun filter(
- userIdFlow: Flow<Int>, recordListFlow: Flow<List<InstallUnknownAppsRecord>>,
- ) = userIdFlow.map(::getPotentialPackageNames)
- .combine(recordListFlow) { potentialPackageNames, recordList ->
- recordList.filter { record ->
- isChangeable(record, potentialPackageNames)
- }
+ userIdFlow: Flow<Int>,
+ recordListFlow: Flow<List<InstallUnknownAppsRecord>>,
+ ) =
+ userIdFlow.map(::getPotentialPackageNames).combine(recordListFlow) {
+ potentialPackageNames,
+ recordList ->
+ recordList.filter { record -> isChangeable(record, potentialPackageNames) }
}
@Composable
@@ -88,12 +94,13 @@
private fun isChangeable(
record: InstallUnknownAppsRecord,
potentialPackageNames: Set<String>,
- ) = record.appOpsController.getMode() != MODE_DEFAULT ||
+ ) =
+ record.appOpsController.getMode() != MODE_DEFAULT ||
record.app.packageName in potentialPackageNames
private fun getPotentialPackageNames(userId: Int): Set<String> =
- AppGlobals.getPackageManager().getAppOpPermissionPackages(
- Manifest.permission.REQUEST_INSTALL_PACKAGES, userId
- ).toSet()
+ AppGlobals.getPackageManager()
+ .getAppOpPermissionPackages(Manifest.permission.REQUEST_INSTALL_PACKAGES, userId)
+ .toSet()
}
}
diff --git a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
index 0c56e56..994ee92 100644
--- a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
+++ b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
@@ -16,6 +16,7 @@
package com.android.settings.spa.app.specialaccess
+import android.app.AppOpsManager.MODE_ERRORED
import android.app.AppOpsManager.OP_PICTURE_IN_PICTURE
import android.content.Context
import android.content.pm.ActivityInfo
@@ -46,8 +47,8 @@
val appOpsController: AppOpsController,
) : AppRecord
-class PictureInPictureListModel(private val context: Context)
- : TogglePermissionAppListModel<PictureInPictureRecord> {
+class PictureInPictureListModel(private val context: Context) :
+ TogglePermissionAppListModel<PictureInPictureRecord> {
override val pageTitleResId = R.string.picture_in_picture_title
override val switchTitleResId = R.string.picture_in_picture_app_detail_switch
override val footerResId = R.string.picture_in_picture_app_detail_summary
@@ -55,15 +56,16 @@
private val packageManager = context.packageManager
override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
- userIdFlow.map(::getPictureInPicturePackages)
- .combine(appListFlow) { pictureInPicturePackages, appList ->
- appList.map { app ->
- createPictureInPictureRecord(
- app = app,
- isSupport = app.packageName in pictureInPicturePackages,
- )
- }
+ userIdFlow.map(::getPictureInPicturePackages).combine(appListFlow) {
+ pictureInPicturePackages,
+ appList ->
+ appList.map { app ->
+ createPictureInPictureRecord(
+ app = app,
+ isSupport = app.packageName in pictureInPicturePackages,
+ )
}
+ }
override fun transformItem(app: ApplicationInfo): PictureInPictureRecord {
val packageInfo =
@@ -78,17 +80,17 @@
PictureInPictureRecord(
app = app,
isSupport = isSupport,
- appOpsController = AppOpsController(
- context = context,
- app = app,
- op = OP_PICTURE_IN_PICTURE,
- ),
+ appOpsController =
+ AppOpsController(
+ context = context,
+ app = app,
+ op = OP_PICTURE_IN_PICTURE,
+ modeForNotAllowed = MODE_ERRORED,
+ ),
)
override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<PictureInPictureRecord>>) =
- recordListFlow.map { recordList ->
- recordList.filter { it.isSupport }
- }
+ recordListFlow.map { recordList -> recordList.filter { it.isSupport } }
@Composable
override fun isAllowed(record: PictureInPictureRecord) =
@@ -101,7 +103,8 @@
}
private fun getPictureInPicturePackages(userId: Int): Set<String> =
- packageManager.getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
+ packageManager
+ .getInstalledPackagesAsUser(GET_ACTIVITIES_FLAGS, userId)
.filter { it.supportsPictureInPicture() }
.map { it.packageName }
.toSet()
diff --git a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
index f955adf..5b9205a 100644
--- a/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/SpecialAppAccess.kt
@@ -43,10 +43,12 @@
@Composable
fun EntryItem() {
- Preference(object : PreferenceModel {
- override val title = stringResource(R.string.special_access)
- override val onClick = navigator(name)
- })
+ Preference(
+ object : PreferenceModel {
+ override val title = stringResource(R.string.special_access)
+ override val onClick = navigator(name)
+ }
+ )
}
fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
@@ -54,13 +56,15 @@
override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
return listOf(
- AllFilesAccessAppListProvider,
- DisplayOverOtherAppsAppListProvider,
- MediaManagementAppsAppListProvider,
- ModifySystemSettingsAppListProvider,
- PictureInPictureListProvider,
- InstallUnknownAppsListProvider,
- AlarmsAndRemindersAppListProvider,
- ).map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
+ AllFilesAccessAppListProvider,
+ DisplayOverOtherAppsAppListProvider,
+ MediaManagementAppsAppListProvider,
+ ModifySystemSettingsAppListProvider,
+ PictureInPictureListProvider,
+ InstallUnknownAppsListProvider,
+ AlarmsAndRemindersAppListProvider,
+ WifiControlAppListProvider,
+ )
+ .map { it.buildAppListInjectEntry().setLink(fromPage = owner).build() }
}
}
diff --git a/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt b/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt
new file mode 100644
index 0000000..69f7b1e
--- /dev/null
+++ b/src/com/android/settings/spa/app/specialaccess/WifiControlApps.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.spa.app.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.AppOpsManager.MODE_IGNORED
+import android.content.Context
+import com.android.settings.R
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object WifiControlAppListProvider : TogglePermissionAppListProvider {
+ override val permissionType = "WifiControl"
+ override fun createModel(context: Context) = WifiControlAppListModel(context)
+}
+
+class WifiControlAppListModel(
+ private val context: Context,
+ private val packageManagers: IPackageManagers = PackageManagers
+) : AppOpPermissionListModel(context, packageManagers) {
+ override val pageTitleResId = R.string.change_wifi_state_title
+ override val switchTitleResId = R.string.change_wifi_state_app_detail_switch
+ override val footerResId = R.string.change_wifi_state_app_detail_summary
+
+ override val appOp = AppOpsManager.OP_CHANGE_WIFI_STATE
+ override val permission = Manifest.permission.CHANGE_WIFI_STATE
+
+ /** NETWORK_SETTINGS permission trumps CHANGE_WIFI_CONFIG. */
+ override val broaderPermission = Manifest.permission.NETWORK_SETTINGS
+ override val permissionHasAppopFlag = false
+ override val modeForNotAllowed = MODE_IGNORED
+}
diff --git a/src/com/android/settings/spa/development/UsageStatsListModel.kt b/src/com/android/settings/spa/development/UsageStatsListModel.kt
index caa30cc..61c24ac 100644
--- a/src/com/android/settings/spa/development/UsageStatsListModel.kt
+++ b/src/com/android/settings/spa/development/UsageStatsListModel.kt
@@ -26,6 +26,7 @@
import com.android.settings.R
import com.android.settings.spa.development.UsageStatsListModel.SpinnerItem.Companion.toSpinnerItem
import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -53,9 +54,13 @@
appList.map { app -> UsageStatsAppRecord(app, usageStatsMap[app.packageName]) }
}
- override fun getSpinnerOptions() = SpinnerItem.values().map {
- context.getString(it.stringResId)
- }
+ override fun getSpinnerOptions(recordList: List<UsageStatsAppRecord>): List<SpinnerOption> =
+ SpinnerItem.values().map {
+ SpinnerOption(
+ id = it.ordinal,
+ text = context.getString(it.stringResId),
+ )
+ }
override fun filter(
userIdFlow: Flow<Int>,
@@ -75,7 +80,8 @@
override fun getSummary(option: Int, record: UsageStatsAppRecord): State<String>? {
val usageStats = record.usageStats ?: return null
val lastTimeUsed = DateUtils.formatSameDayTime(
- usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM)
+ usageStats.lastTimeUsed, now, DateFormat.MEDIUM, DateFormat.MEDIUM
+ )
val lastTimeUsedLine = "${context.getString(R.string.last_time_used_label)}: $lastTimeUsed"
val usageTime = DateUtils.formatElapsedTime(usageStats.totalTimeInForeground / 1000)
val usageTimeLine = "${context.getString(R.string.usage_time_label)}: $usageTime"
diff --git a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
index 29c8a2b..028b2f4 100644
--- a/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
+++ b/src/com/android/settings/spa/notification/AppNotificationsListModel.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spa.framework.util.asyncFilter
import com.android.settingslib.spa.framework.util.asyncForEach
+import com.android.settingslib.spa.widget.ui.SpinnerOption
import com.android.settingslib.spaprivileged.model.app.AppEntry
import com.android.settingslib.spaprivileged.model.app.AppListModel
import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -78,8 +79,9 @@
}
}
- override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>) {
+ override suspend fun onFirstLoaded(recordList: List<AppNotificationsRecord>): Boolean {
recordList.asyncForEach { it.controller.getEnabled() }
+ return true
}
override fun getComparator(option: Int) = when (option.toSpinnerItem()) {
@@ -97,9 +99,13 @@
}
}
- override fun getSpinnerOptions() = SpinnerItem.values().map {
- context.getString(it.stringResId)
- }
+ override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> =
+ SpinnerItem.values().map {
+ SpinnerOption(
+ id = it.ordinal,
+ text = context.getString(it.stringResId),
+ )
+ }
private fun formatLastSent(lastSent: Long) =
StringUtil.formatRelativeTime(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
index a31fffa..054b44f 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -95,6 +95,7 @@
.when(mContext)
.getSystemService(UserManager.class);
doReturn(true).when(mUserManager).isUserUnlocked(anyInt());
+ doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt());
final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
doReturn(resources).when(mContext).getResources();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 900913b..4883563 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -371,15 +371,6 @@
}
@Test
- public void testIsSystemEntry_uidBatteryWithHiddenState_returnTrue() {
- final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ 123, /*isHidden=*/ true);
- assertThat(entry.isSystemEntry()).isTrue();
- }
-
- @Test
public void testIsSystemEntry_uidBatteryWithSystemProcess_returnFalse() {
final BatteryDiffEntry entry =
createBatteryDiffEntry(
@@ -389,24 +380,6 @@
}
@Test
- public void testIsSystemEntry_uidBatteryWithTetheringProcess_returnTrue() {
- final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ BatteryUtils.UID_TETHERING, /*isHidden=*/ false);
- assertThat(entry.isSystemEntry()).isTrue();
- }
-
- @Test
- public void testIsSystemEntry_uidBatteryWithRemovedAppsProcess_returnTrue() {
- final BatteryDiffEntry entry =
- createBatteryDiffEntry(
- ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*uid=*/ BatteryUtils.UID_REMOVED_APPS, /*isHidden=*/ false);
- assertThat(entry.isSystemEntry()).isTrue();
- }
-
- @Test
public void testUpdateRestrictionFlagState_updateFlagAsExpected() throws Exception {
final String expectedAppLabel = "fake app label";
final String fakePackageName = "com.fake.google.com";
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
index 7e5aaea..07a8dfe 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryEntryTest.java
@@ -108,7 +108,8 @@
mMockContext,
powerComponentId,
/* devicePowerMah= */ 200,
- /* usageDurationMs= */ 1000);
+ /* usageDurationMs= */ 1000,
+ /* isHidden= */ false);
}
private BatteryEntry createCustomAggregateBatteryEntry(int powerComponentId) {
@@ -169,7 +170,8 @@
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY,
/* devicePowerMah= */ 200,
- /* usageDurationMs= */ 1000);
+ /* usageDurationMs= */ 1000,
+ /* isHidden= */ false);
assertThat(entry.mIconId).isEqualTo(R.drawable.ic_settings_aod);
assertThat(entry.mName).isEqualTo("Ambient display");
@@ -202,7 +204,8 @@
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
/* devicePowerMah= */ 10,
- /* usageDurationMs= */ 100);
+ /* usageDurationMs= */ 100,
+ /* isHidden= */ false);
assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
}
@@ -223,7 +226,8 @@
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application,
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
/* devicePowerMah= */ 100,
- /* usageDurationMs= */ 1000);
+ /* usageDurationMs= */ 1000,
+ /* isHidden= */ false);
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(0);
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index fb91ea2..a1caa2c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
@@ -32,6 +33,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.UserInfo;
import android.os.BatteryConsumer;
import android.os.BatteryManager;
@@ -43,6 +45,7 @@
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
@@ -75,13 +78,15 @@
@Mock private BatteryUsageStats mBatteryUsageStats;
@Mock private UserManager mUserManager;
@Mock private IUsageStatsManager mUsageStatsManager;
+ @Mock private ApplicationsState mApplicationsState;
+ @Mock private ApplicationsState.AppEntry mAppEntry;
+ @Mock private ApplicationInfo mApplicationInfo;
@Mock private BatteryEntry mMockBatteryEntry1;
@Mock private BatteryEntry mMockBatteryEntry2;
@Mock private BatteryEntry mMockBatteryEntry3;
@Mock private BatteryEntry mMockBatteryEntry4;
@Mock private UsageEvents mUsageEvents1;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -95,7 +100,9 @@
doReturn(mIntent).when(mContext).registerReceiver(any(), any());
doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
+ doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(new int[]{0}).when(mUserManager).getProfileIdsWithDisabled(anyInt());
}
@Test
@@ -768,7 +775,8 @@
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L);
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L,
+ /*isHidden=*/ false);
// Adds the index = 0 data.
Map<String, BatteryHistEntry> entryMap = new HashMap<>();
BatteryHistEntry entry = createBatteryHistEntry(
@@ -777,7 +785,7 @@
/*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
@@ -793,7 +801,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 15L,
- /*backgroundUsageTimeInMs=*/ 25L);
+ /*backgroundUsageTimeInMs=*/ 25L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
@@ -805,7 +813,7 @@
/*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 25L,
- /*backgroundUsageTimeInMs=*/ 35L);
+ /*backgroundUsageTimeInMs=*/ 35L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package3", "label3", /*consumePower=*/ 10.0,
@@ -813,7 +821,7 @@
/*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
/*uid=*/ 3L, currentUserId,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 40L,
- /*backgroundUsageTimeInMs=*/ 50L);
+ /*backgroundUsageTimeInMs=*/ 50L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package4", "label3", /*consumePower=*/ 15.0,
@@ -821,7 +829,7 @@
/*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3,
/*uid=*/ 4L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
- /*backgroundUsageTimeInMs=*/ 5L);
+ /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[3], entryMap);
@@ -833,7 +841,7 @@
/*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 40L);
+ /*backgroundUsageTimeInMs=*/ 40L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package3", "label3", /*consumePower=*/ 20.0,
@@ -841,7 +849,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 3L, currentUserId,
ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*foregroundUsageTimeInMs=*/ 50L,
- /*backgroundUsageTimeInMs=*/ 60L);
+ /*backgroundUsageTimeInMs=*/ 60L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package4", "label4", /*consumePower=*/ 40.0,
@@ -849,7 +857,7 @@
/*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8,
/*uid=*/ 4L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 5L,
- /*backgroundUsageTimeInMs=*/ 5L);
+ /*backgroundUsageTimeInMs=*/ 5L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entryMap.put(fakeEntry.getKey(), fakeEntry);
batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
@@ -966,7 +974,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package1", "label1", /*consumePower=*/ 10.0,
@@ -974,7 +982,7 @@
/*backgroundUsageConsumePower=*/ 1, /*cachedUsageConsumePower=*/ 1,
/*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 5.0,
@@ -982,7 +990,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
@@ -993,7 +1001,7 @@
/*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package1", "label1", /*consumePower=*/ 30.0,
@@ -1001,7 +1009,7 @@
/*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2,
/*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 15.0,
@@ -1009,7 +1017,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
@@ -1020,7 +1028,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package1", "label1", /*consumePower=*/ 50.0,
@@ -1028,7 +1036,7 @@
/*backgroundUsageConsumePower=*/ 10, /*cachedUsageConsumePower=*/ 10,
/*uid=*/ 2L, currentUserId + 1,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 20L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 25.0,
@@ -1036,7 +1044,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 3L, currentUserId + 2,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 30L,
- /*backgroundUsageTimeInMs=*/ 30L);
+ /*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1084,7 +1092,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
@@ -1095,7 +1103,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
@@ -1106,7 +1114,7 @@
/*backgroundUsageConsumePower=*/ 100, /*cachedUsageConsumePower=*/ 100,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 3600000L,
- /*backgroundUsageTimeInMs=*/ 7200000L);
+ /*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1174,7 +1182,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 0,
@@ -1182,7 +1190,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
@@ -1193,7 +1201,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 0,
@@ -1201,7 +1209,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
@@ -1212,7 +1220,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 10.0,
@@ -1220,7 +1228,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1267,7 +1275,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 0,
@@ -1275,7 +1283,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[0], entryMap);
// Adds the index = 1 data.
@@ -1286,7 +1294,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 0,
@@ -1294,7 +1302,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 0L,
- /*backgroundUsageTimeInMs=*/ 0L);
+ /*backgroundUsageTimeInMs=*/ 0L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[1], entryMap);
// Adds the index = 2 data.
@@ -1305,7 +1313,7 @@
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 1L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
entry = createBatteryHistEntry(
"package2", "label2", /*consumePower=*/ 10.0,
@@ -1313,7 +1321,7 @@
/*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5,
/*uid=*/ 2L, currentUserId,
ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*foregroundUsageTimeInMs=*/ 10L,
- /*backgroundUsageTimeInMs=*/ 20L);
+ /*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
entryMap.put(entry.getKey(), entry);
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
@@ -1603,6 +1611,93 @@
assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(0);
}
+ @Test
+ public void needsCombineInSystemApp_isHidden_returnTrue() {
+ final int currentUserId = mContext.getUserId();
+ final BatteryHistEntry hiddenHistEntry = createBatteryHistEntry(
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, true);
+ final BatteryDiffEntry hiddenDiffEntry = new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*screenOnTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
+ hiddenHistEntry);
+
+ boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+ hiddenDiffEntry, List.of(), mApplicationsState);
+
+ assertThat(needsCombineInSystemApp).isTrue();
+ }
+
+ @Test
+ public void needsCombineInSystemApp_isSystemApp_returnTrue() {
+ final int currentUserId = mContext.getUserId();
+ final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false);
+ final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*screenOnTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
+ batteryHistEntry);
+ doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
+ mAppEntry.info = mApplicationInfo;
+ mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+ batteryDiffEntry, List.of(), mApplicationsState);
+
+ assertThat(needsCombineInSystemApp).isTrue();
+ }
+
+ @Test
+ public void needsCombineInSystemApp_notSystemApp_returnFalse() {
+ final int currentUserId = mContext.getUserId();
+ final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
+ /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false);
+ final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
+ mContext,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0,
+ /*screenOnTimeInMs=*/ 0,
+ /*consumePower=*/ 0,
+ /*foregroundUsageConsumePower=*/ 0,
+ /*foregroundServiceUsageConsumePower=*/ 0,
+ /*backgroundUsageConsumePower=*/ 0,
+ /*cachedUsageConsumePower=*/ 0,
+ batteryHistEntry);
+ doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
+ mAppEntry.info = mApplicationInfo;
+ mApplicationInfo.flags = 0;
+
+ boolean needsCombineInSystemApp = DataProcessor.needsCombineInSystemApp(
+ batteryDiffEntry, List.of(), mApplicationsState);
+
+ assertThat(needsCombineInSystemApp).isFalse();
+ }
+
private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
final long[] timestamps, final int[] levels) {
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
@@ -1639,7 +1734,8 @@
final double foregroundServiceUsageConsumePower,
final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
final long uid, final long userId, final int consumerType,
- final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) {
+ final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
+ final boolean isHidden) {
// Only insert required fields.
final BatteryInformation batteryInformation =
BatteryInformation
@@ -1652,6 +1748,7 @@
.setCachedUsageConsumePower(cachedUsageConsumePower)
.setForegroundUsageTimeInMs(foregroundUsageTimeInMs)
.setBackgroundUsageTimeInMs(backgroundUsageTimeInMs)
+ .setIsHidden(isHidden)
.build();
final ContentValues values = new ContentValues();
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java
new file mode 100644
index 0000000..4c2192c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/SpinnerPreferenceTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 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.batteryusage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.widget.Spinner;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public final class SpinnerPreferenceTest {
+
+ private Context mContext;
+ private SpinnerPreference mSpinnerPreference;
+
+ @Mock
+ private Spinner mMockSpinner;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mSpinnerPreference = new SpinnerPreference(mContext, /*attrs=*/ null);
+ }
+
+ @Test
+ public void constructor_returnExpectedResult() {
+ assertThat(mSpinnerPreference.getLayoutResource()).isEqualTo(R.layout.preference_spinner);
+ }
+
+ @Test
+ public void initializeSpinner_returnExpectedResult() {
+ final String[] items = new String[]{"item1", "item2"};
+ mSpinnerPreference.initializeSpinner(items, null);
+ assertThat(mSpinnerPreference.mItems).isEqualTo(items);
+ }
+
+ @Test
+ public void onSaveInstanceState_returnExpectedResult() {
+ doReturn(1).when(mMockSpinner).getSelectedItemPosition();
+ mSpinnerPreference.mSpinner = mMockSpinner;
+ SpinnerPreference.SavedState savedState =
+ (SpinnerPreference.SavedState) mSpinnerPreference.onSaveInstanceState();
+ assertThat(savedState.getSpinnerPosition()).isEqualTo(1);
+ }
+
+ @Test
+ public void onRestoreInstanceState_returnExpectedResult() {
+ SpinnerPreference.SavedState savedState =
+ new SpinnerPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
+ mSpinnerPreference.onRestoreInstanceState(savedState);
+ assertThat(mSpinnerPreference.mSavedSpinnerPosition).isEqualTo(2);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java
deleted file mode 100644
index c106b48..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/TabPreferenceTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2022 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.batteryusage;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-
-import androidx.fragment.app.Fragment;
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-
-import com.google.android.material.tabs.TabLayout;
-
-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 final class TabPreferenceTest {
-
- private Context mContext;
- private TabPreference mTabPreference;
-
- @Mock
- private Fragment mMockFragment;
- @Mock
- private TabLayout mMockTabLayout;
-
- private final String[] mTabTitles = new String[]{"tab1", "tab2"};
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- mTabPreference = new TabPreference(mContext, /*attrs=*/ null);
- }
-
- @Test
- public void constructor_returnExpectedResult() {
- assertThat(mTabPreference.getLayoutResource()).isEqualTo(R.layout.preference_tab);
- }
-
- @Test
- public void initializeTabs_returnExpectedResult() {
- mTabPreference.initializeTabs(mMockFragment, mTabTitles);
- assertThat(mTabPreference.mTabTitles).isEqualTo(mTabTitles);
- }
-
- @Test
- public void onSaveInstanceState_returnExpectedResult() {
- doReturn(1).when(mMockTabLayout).getSelectedTabPosition();
- mTabPreference.mTabLayout = mMockTabLayout;
- TabPreference.SavedState savedState =
- (TabPreference.SavedState) mTabPreference.onSaveInstanceState();
- assertThat(savedState.getTabPosition()).isEqualTo(1);
- }
-
- @Test
- public void onRestoreInstanceState_returnExpectedResult() {
- TabPreference.SavedState savedState =
- new TabPreference.SavedState(Preference.BaseSavedState.EMPTY_STATE, 2);
- mTabPreference.onRestoreInstanceState(savedState);
- assertThat(mTabPreference.mSavedTabPosition).isEqualTo(2);
- }
-}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
index b767912..b5dfddc 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AllAppListTest.kt
@@ -121,7 +121,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun allAppListModel_transform() = runTest {
- val listModel = AllAppListModel { stateOf(SUMMARY) }
+ val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
val recordListFlow = listModel.transform(flowOf(USER_ID), flowOf(listOf(APP)))
@@ -132,7 +132,7 @@
@Test
fun allAppListModel_getSummary() {
- val listModel = AllAppListModel { stateOf(SUMMARY) }
+ val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
lateinit var summaryState: State<String>
composeTestRule.setContent {
@@ -142,6 +142,23 @@
assertThat(summaryState.value).isEqualTo(SUMMARY)
}
+ @Test
+ fun allAppListModel_getSummaryWhenDisabled() {
+ val listModel = AllAppListModel(context) { stateOf(SUMMARY) }
+ val disabledApp = ApplicationInfo().apply {
+ packageName = PACKAGE_NAME
+ enabled = false
+ }
+
+ lateinit var summaryState: State<String>
+ composeTestRule.setContent {
+ summaryState =
+ listModel.getSummary(option = 0, record = AppRecordWithSize(app = disabledApp))
+ }
+
+ assertThat(summaryState.value).isEqualTo("$SUMMARY${System.lineSeparator()}Disabled")
+ }
+
private fun getAppListInput(): AppListInput<AppRecordWithSize> {
lateinit var input: AppListInput<AppRecordWithSize>
composeTestRule.setContent {
@@ -157,7 +174,7 @@
private fun setItemContent() {
composeTestRule.setContent {
fakeNavControllerWrapper.Wrapper {
- with(AllAppListModel()) {
+ with(AllAppListModel(context)) {
AppListItemModel(
record = AppRecordWithSize(app = APP),
label = LABEL,
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt
new file mode 100644
index 0000000..15f87ed
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/AppUtilTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.spa.app
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RunWith(AndroidJUnit4::class)
+class AppUtilTest {
+ @get:Rule
+ val mockito: MockitoRule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var context: Context
+
+ @Test
+ fun startUninstallActivity() {
+ context.startUninstallActivity(packageName = PACKAGE_NAME, userHandle = USER_HANDLE)
+
+ val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(context).startActivityAsUser(intentCaptor.capture(), eq(USER_HANDLE))
+ val intent = intentCaptor.value
+ assertThat(intent.action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
+ assertThat(intent.data).isEqualTo(Uri.parse("package:$PACKAGE_NAME"))
+ assertThat(intent.extras?.getBoolean(Intent.EXTRA_UNINSTALL_ALL_USERS)).isFalse()
+ }
+
+ private companion object {
+ const val PACKAGE_NAME = "package.name"
+ val USER_HANDLE: UserHandle = UserHandle.of(0)
+ }
+}
\ No newline at end of file
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
new file mode 100644
index 0000000..c5c48f5
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2022 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.spa.app.specialaccess
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.app.AppOpsManager.MODE_ALLOWED
+import android.app.AppOpsManager.MODE_DEFAULT
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.State
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.MutableLiveData
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@ExperimentalCoroutinesApi
+@RunWith(AndroidJUnit4::class)
+class WifiControlAppListModelTest {
+
+ @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+ @get:Rule val composeTestRule = createComposeRule()
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ @Mock private lateinit var packageManagers: IPackageManagers
+
+ private lateinit var listModel: WifiControlAppListModel
+
+ @Before
+ fun setUp() {
+ listModel = WifiControlAppListModel(context, packageManagers)
+ }
+
+ @Test
+ fun transformItem_recordHasCorrectApp() {
+ val record = listModel.transformItem(APP)
+
+ assertThat(record.app).isSameInstanceAs(APP)
+ }
+
+ @Test
+ fun transformItem_hasRequestPermission() = runTest {
+ with(packageManagers) {
+ whenever(APP.hasRequestPermission(PM_CHANGE_WIFI_STATE)).thenReturn(true)
+ }
+
+ val record = listModel.transformItem(APP)
+
+ assertThat(record.hasRequestPermission).isTrue()
+ }
+
+ @Test
+ fun transformItem_notRequestPermission() = runTest {
+ with(packageManagers) {
+ whenever(APP.hasRequestPermission(PM_CHANGE_WIFI_STATE)).thenReturn(false)
+ }
+
+ val record = listModel.transformItem(APP)
+
+ assertThat(record.hasRequestPermission).isFalse()
+ }
+
+ @Test
+ fun transformItem_hasRequestNetworkSettingsPermission() = runTest {
+ with(packageManagers) {
+ whenever(APP.hasRequestPermission(PM_NETWORK_SETTINGS)).thenReturn(true)
+ }
+
+ val record = listModel.transformItem(APP)
+
+ assertThat(record.hasRequestBroaderPermission).isTrue()
+ }
+
+ @Test
+ fun transformItem_notRequestNetworkSettingsPermission() = runTest {
+ with(packageManagers) {
+ whenever(APP.hasRequestPermission(PM_NETWORK_SETTINGS)).thenReturn(false)
+ }
+
+ val record = listModel.transformItem(APP)
+
+ assertThat(record.hasRequestBroaderPermission).isFalse()
+ }
+
+ @Test
+ fun filter() = runTest {
+ val appNotRequestPermissionRecord =
+ AppOpPermissionRecord(
+ app = APP_NOT_REQUEST_PERMISSION,
+ hasRequestPermission = false,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ )
+ val appRequestedNetworkSettingsRecord =
+ AppOpPermissionRecord(
+ app = APP_REQUESTED_NETWORK_SETTINGS,
+ hasRequestPermission = true,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+ )
+
+ val recordListFlow =
+ listModel.filter(
+ flowOf(USER_ID),
+ flowOf(listOf(appNotRequestPermissionRecord, appRequestedNetworkSettingsRecord))
+ )
+
+ val recordList = checkNotNull(recordListFlow.firstWithTimeoutOrNull())
+ assertThat(recordList).containsExactly(appRequestedNetworkSettingsRecord)
+ }
+
+ @Test
+ fun isAllowed_networkSettingsShouldTrump() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = false,
+ hasRequestBroaderPermission = true,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ )
+
+ val isAllowed = getIsAllowed(record)
+
+ assertThat(isAllowed).isTrue()
+ }
+
+ @Test
+ fun isAllowed_grantedChangeWifiState() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = true,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ALLOWED),
+ )
+
+ val isAllowed = getIsAllowed(record)
+
+ assertThat(isAllowed).isTrue()
+ }
+
+ @Test
+ fun isAllowed_notAllowed() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = true,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_IGNORED),
+ )
+
+ val isAllowed = getIsAllowed(record)
+
+ assertThat(isAllowed).isFalse()
+ }
+
+ @Test
+ fun isChangeable_noRequestedPermission() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = false,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ )
+
+ val isChangeable = listModel.isChangeable(record)
+
+ assertThat(isChangeable).isFalse()
+ }
+
+ @Test
+ fun isChangeable_notChangableWhenRequestedNetworkSettingPermissions() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = false,
+ hasRequestBroaderPermission = true,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ )
+
+ val isChangeable = listModel.isChangeable(record)
+
+ assertThat(isChangeable).isFalse()
+ }
+
+ @Test
+ fun isChangeable_changableWhenRequestedChangeWifiStatePermission() {
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = true,
+ hasRequestBroaderPermission = false,
+ appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+ )
+
+ val isChangeable = listModel.isChangeable(record)
+
+ assertThat(isChangeable).isTrue()
+ }
+
+ @Test
+ fun setAllowed_shouldCallController() {
+ val appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+ val record =
+ AppOpPermissionRecord(
+ app = APP,
+ hasRequestPermission = true,
+ hasRequestBroaderPermission = false,
+ appOpsController = appOpsController,
+ )
+
+ listModel.setAllowed(record = record, newAllowed = true)
+
+ assertThat(appOpsController.setAllowedCalledWith).isTrue()
+ }
+
+ private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
+ lateinit var isAllowedState: State<Boolean?>
+ composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) }
+ return isAllowedState.value
+ }
+
+ private companion object {
+ const val USER_ID = 0
+ const val PACKAGE_NAME = "package.name"
+ const val PM_CHANGE_WIFI_STATE = Manifest.permission.CHANGE_WIFI_STATE
+ const val PM_NETWORK_SETTINGS = Manifest.permission.NETWORK_SETTINGS
+
+ val APP = ApplicationInfo().apply { packageName = PACKAGE_NAME }
+
+ val APP_NOT_REQUEST_PERMISSION =
+ ApplicationInfo().apply { packageName = "app1.package.name" }
+ val APP_REQUESTED_NETWORK_SETTINGS =
+ ApplicationInfo().apply { packageName = "app2.package.name" }
+ val APP_REQUESTED_CHANGE_WIFI_STATE =
+ ApplicationInfo().apply { packageName = "app3.package.name" }
+ }
+}
+
+private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
+ var setAllowedCalledWith: Boolean? = null
+
+ override val mode = MutableLiveData(fakeMode)
+
+ override fun setAllowed(allowed: Boolean) {
+ setAllowedCalledWith = allowed
+ }
+
+ override fun getMode() = fakeMode
+}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
index 8e1757f..b3e29af 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/backgroundinstall/BackgroundInstalledAppsPageProviderTest.kt
@@ -17,14 +17,11 @@
package com.android.settings.spa.app.backgroundinstall
import android.content.Context
-import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.IBackgroundInstallControlService
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.ParceledListSlice
-import android.net.Uri
-import android.os.UserHandle
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
@@ -74,9 +71,6 @@
private var packageInfoFlagsCaptor =
ArgumentCaptor.forClass(PackageManager.PackageInfoFlags::class.java)
- private var intentCaptor =
- ArgumentCaptor.forClass(Intent::class.java)
-
private val fakeNavControllerWrapper = FakeNavControllerWrapper()
@Before
@@ -177,26 +171,6 @@
.isEqualTo("AppInfoSettings/package.name/0")
}
- @Suppress
- @OptIn(ExperimentalCoroutinesApi::class)
- @Test
- fun startUninstallActivity_success() = runTest {
- val expectedPackageUri = Uri.parse("package:package.name")
- val mockUserHandle = UserHandle(0)
- Mockito.`when`(mockContext.user).thenReturn(mockUserHandle)
- Mockito.`when`(mockContext.startActivityAsUser(
- intentCaptor.capture(),
- eq(mockUserHandle)
- )).then { }
-
- startUninstallActivity(mockContext, TEST_PACKAGE_NAME)
-
- Truth.assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE)
- Truth.assertThat(intentCaptor.value.data).isEqualTo(expectedPackageUri)
- Truth.assertThat(intentCaptor.value.extras?.getBoolean(Intent.EXTRA_UNINSTALL_ALL_USERS))
- .isEqualTo(false)
- }
-
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun backgroundInstalledAppsWithGroupingListModel_getGroupTitleOne() = runTest {
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
index 7e1ec94..4ac2532 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/CalendarTypeControllerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import android.content.Context;
+import android.icu.util.ULocale;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
@@ -48,49 +49,57 @@
@After
public void tearDown() throws Exception {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, mCacheProviderContent);
Locale.setDefault(mCacheLocale);
}
@Test
- public void getSummary_hasProviderValue_resultIsChinese() {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ public void getSummary_hasProviderValue_resultIsChineseCalendar() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, "und-u-ca-chinese");
- CharSequence type = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.CalendarType.CHINESE, type.toString());
+ assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.CHINESE), summary);
}
@Test
- public void getSummary_hasProviderValue_resultIsDangi() {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ public void getSummary_hasProviderValue_resultIsDangiCalendar() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, "und-u-ca-dangi");
- CharSequence type = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.CalendarType.DANGI, type.toString());
+ assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.DANGI), summary);
}
@Test
- public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsSat() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsChineseCalendar() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US-u-ca-chinese"));
- CharSequence type = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.CalendarType.CHINESE, type.toString());
+ assertEquals(getDisplayKeywordValue(LocalePreferences.CalendarType.CHINESE), summary);
}
@Test
public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US"));
- CharSequence type = mController.getSummary();
+ String summary = mController.getSummary().toString();
assertEquals(ResourcesUtils.getResourcesString(
- mApplicationContext, "default_string_of_regional_preference"), type.toString());
+ mApplicationContext, "default_string_of_regional_preference"), summary);
+ }
+
+ private static String getDisplayKeywordValue(String value) {
+ String languageTag = new Locale.Builder()
+ .setUnicodeLocaleKeyword(
+ RegionalPreferencesFragment.TYPE_CALENDAR, value).build().toLanguageTag();
+ return ULocale.getDisplayKeywordValue(languageTag, "calendar",
+ ULocale.forLocale(Locale.getDefault(Locale.Category.FORMAT)));
}
}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
index b658242..062aef8 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/FirstDayOfWeekControllerTest.java
@@ -48,47 +48,50 @@
@After
public void tearDown() throws Exception {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, mCacheProviderContent);
Locale.setDefault(mCacheLocale);
}
@Test
public void getSummary_hasProviderValue_resultIsWed() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-wed");
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-wed");
- CharSequence day = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.FirstDayOfWeek.WEDNESDAY, day.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "wednesday_first_day_of_week"), summary);
}
@Test
public void getSummary_hasProviderValue_resultIsSat() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-sat");
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "und-u-fw-sat");
- CharSequence day = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.FirstDayOfWeek.SATURDAY, day.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "saturday_first_day_of_week"), summary);
}
@Test
public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsSat() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US-u-fw-sat"));
- CharSequence day = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.FirstDayOfWeek.SATURDAY, day.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "saturday_first_day_of_week"), summary);
}
@Test
- public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsdefault() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US"));
- CharSequence day = mController.getSummary();
+ String summary = mController.getSummary().toString();
assertEquals(ResourcesUtils.getResourcesString(
- mApplicationContext, "default_string_of_regional_preference"), day.toString());
+ mApplicationContext, "default_string_of_regional_preference"), summary);
}
}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
similarity index 95%
rename from tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java
rename to tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
index 709413c..d973236 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceUtils.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferenceTestUtils.java
@@ -20,7 +20,7 @@
import android.provider.Settings;
/** Utils for each regional preference unit test. */
-public final class RegionalPreferenceUtils {
+public final class RegionalPreferenceTestUtils {
/** Set language tag to Settings Provider */
public static void setSettingsProviderContent(Context context, String languageTag) {
Settings.System.putString(context.getContentResolver(),
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
new file mode 100644
index 0000000..0de3b7e
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesDataUtilsTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.LocaleList;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.app.LocalePicker;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Locale;
+
+public class RegionalPreferencesDataUtilsTest {
+ private Context mApplicationContext;
+ private String mCacheProviderContent = "";
+ private Locale mCacheLocale;
+ private LocaleList mCacheLocaleList;
+
+ @Before
+ public void setUp() throws Exception {
+ mApplicationContext = ApplicationProvider.getApplicationContext();
+ mCacheProviderContent = Settings.System.getString(
+ mApplicationContext.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+ mCacheLocale = Locale.getDefault(Locale.Category.FORMAT);
+ mCacheLocaleList = LocaleList.getDefault();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
+ mApplicationContext, mCacheProviderContent);
+ Locale.setDefault(mCacheLocale);
+ LocalePicker.updateLocales(mCacheLocaleList);
+ }
+
+ @Test
+ public void getDefaultUnicodeExtensionData_hasProviderValue_resultIsCelsius() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
+ mApplicationContext, "und-u-mu-celsius");
+
+ String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+ mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+ assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit);
+ }
+
+ @Test
+ public void getDefaultUnicodeExtensionData_hasDefaultLocaleSubtag_resultIsCelsius() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
+ mApplicationContext, "und");
+ Locale.setDefault(Locale.forLanguageTag("en-US-u-mu-celsius"));
+
+ String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+ mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+ assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit);
+ }
+
+ @Test
+ public void getDefaultUnicodeExtensionData_noSubtag_resultIsDefault() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
+ mApplicationContext, "und");
+ Locale.setDefault(Locale.forLanguageTag("en-US"));
+
+ String unit = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
+ mApplicationContext, RegionalPreferencesFragment.TYPE_TEMPERATURE);
+
+ assertEquals(RegionalPreferencesFragment.TYPE_DEFAULT, unit);
+ }
+
+ @Test
+ public void savePreference_saveCalendarIsDangi_success() {
+ RegionalPreferencesDataUtils.savePreference(
+ mApplicationContext,
+ RegionalPreferencesFragment.TYPE_CALENDAR,
+ LocalePreferences.CalendarType.DANGI
+ );
+ String providerContent = Settings.System.getString(
+ mApplicationContext.getContentResolver(), Settings.System.LOCALE_PREFERENCES);
+ Locale locale = Locale.forLanguageTag(providerContent);
+
+
+ String result1 = locale.getUnicodeLocaleType(RegionalPreferencesFragment.TYPE_CALENDAR);
+
+ assertEquals(LocalePreferences.CalendarType.DANGI, result1);
+
+ String result2 = Locale.getDefault(Locale.Category.FORMAT)
+ .getUnicodeLocaleType(RegionalPreferencesFragment.TYPE_CALENDAR);
+
+ assertEquals(LocalePreferences.CalendarType.DANGI, result2);
+
+ }
+
+ @Test
+ public void temperatureUnitsConverter_inputFahrenheit_resultIsFahrenheitString() {
+ String result = RegionalPreferencesDataUtils.temperatureUnitsConverter(mApplicationContext,
+ LocalePreferences.TemperatureUnit.FAHRENHEIT);
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "fahrenheit_temperature_unit"), result);
+ }
+
+ @Test
+ public void temperatureUnitsConverter_inputDefault_resultIsDefaultString() {
+ String result = RegionalPreferencesDataUtils.temperatureUnitsConverter(mApplicationContext,
+ RegionalPreferencesFragment.TYPE_DEFAULT);
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "default_string_of_regional_preference"), result);
+ }
+
+ @Test
+ public void dayConverter_inputWed_resultIsWedString() {
+ String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+ LocalePreferences.FirstDayOfWeek.WEDNESDAY);
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "wednesday_first_day_of_week"), result);
+ }
+
+ @Test
+ public void dayConverter_inputDefault_resultIsDefaultString() {
+ String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+ RegionalPreferencesFragment.TYPE_DEFAULT);
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "default_string_of_regional_preference"), result);
+ }
+
+ @Test
+ public void calendarConverter_inputDefault_resultIsDefaultString() {
+ String result = RegionalPreferencesDataUtils.dayConverter(mApplicationContext,
+ RegionalPreferencesFragment.TYPE_DEFAULT);
+
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "default_string_of_regional_preference"), result);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java
new file mode 100644
index 0000000..f059bf3
--- /dev/null
+++ b/tests/unit/src/com/android/settings/regionalpreferences/RegionalPreferencesFragmentTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 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.regionalpreferences;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.settings.SettingsEnums;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RegionalPreferencesFragmentTest {
+ private RegionalPreferencesFragment mFragment;
+
+ @Before
+ @UiThreadTest
+ public void setUp() throws Exception {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mFragment = new RegionalPreferencesFragment();
+ }
+
+ @Test
+ @UiThreadTest
+ public void getMetricsCategory_typeIsCa_resultIsCalendarPreference() {
+ mFragment.mType = RegionalPreferencesFragment.TYPE_CALENDAR;
+
+ int result = mFragment.getMetricsCategory();
+
+ assertEquals(SettingsEnums.CALENDAR_PREFERENCE, result);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getMetricsCategory_typeIsFw_resultIsFirstDayOfWeekPreference() {
+ mFragment.mType = RegionalPreferencesFragment.TYPE_FIRST_DAY_OF_WEEK;
+
+ int result = mFragment.getMetricsCategory();
+
+ assertEquals(SettingsEnums.FIRST_DAY_OF_WEEK_PREFERENCE, result);
+ }
+
+ @Test
+ @UiThreadTest
+ public void getMetricsCategory_typeIsMu_resultIsTemperaturePreference() {
+ mFragment.mType = RegionalPreferencesFragment.TYPE_TEMPERATURE;
+
+ int result = mFragment.getMetricsCategory();
+
+ assertEquals(SettingsEnums.TEMPERATURE_PREFERENCE, result);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
index 4f473ad..aa652ca 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/TemperatureUnitControllerTest.java
@@ -48,49 +48,52 @@
@After
public void tearDown() throws Exception {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, mCacheProviderContent);
Locale.setDefault(mCacheLocale);
}
@Test
public void getSummary_hasProviderValue_resultIsCelsius() {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, "und-u-mu-celsius");
- CharSequence unit = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.TemperatureUnit.CELSIUS, unit.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "celsius_temperature_unit"), summary);
}
@Test
public void getSummary_hasProviderValue_resultIsFahrenheit() {
- RegionalPreferenceUtils.setSettingsProviderContent(
+ RegionalPreferenceTestUtils.setSettingsProviderContent(
mApplicationContext, "und-u-mu-fahrenhe");
- CharSequence unit = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, unit.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "fahrenheit_temperature_unit"), summary);
}
@Test
public void getSummary_noProviderValueButHasDefaultLocaleWithSubtag_resultIsFahrenheit() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US-u-mu-fahrenhe"));
- CharSequence unit = mController.getSummary();
+ String summary = mController.getSummary().toString();
- assertEquals(LocalePreferences.TemperatureUnit.FAHRENHEIT, unit.toString());
+ assertEquals(ResourcesUtils.getResourcesString(
+ mApplicationContext, "fahrenheit_temperature_unit"), summary);
}
@Test
- public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsEmpty() {
- RegionalPreferenceUtils.setSettingsProviderContent(mApplicationContext, "");
+ public void getSummary_noProviderValueAndDefaultLocaleWithoutSubtag_resultIsDefault() {
+ RegionalPreferenceTestUtils.setSettingsProviderContent(mApplicationContext, "");
Locale.setDefault(Locale.forLanguageTag("en-US"));
- CharSequence unit = mController.getSummary();
+ String summary = mController.getSummary().toString();
assertEquals(ResourcesUtils.getResourcesString(
- mApplicationContext, "default_string_of_regional_preference"), unit.toString());
+ mApplicationContext, "default_string_of_regional_preference"), summary);
}
}